View.java revision 311a5b54979afee7e07bf31600182584fde15b4f
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.view; 18 19import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH; 20import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 21import static android.os.Build.VERSION_CODES.KITKAT; 22import static android.os.Build.VERSION_CODES.M; 23import static android.os.Build.VERSION_CODES.N; 24 25import static java.lang.Math.max; 26 27import android.animation.AnimatorInflater; 28import android.animation.StateListAnimator; 29import android.annotation.CallSuper; 30import android.annotation.ColorInt; 31import android.annotation.DrawableRes; 32import android.annotation.FloatRange; 33import android.annotation.IdRes; 34import android.annotation.IntDef; 35import android.annotation.IntRange; 36import android.annotation.LayoutRes; 37import android.annotation.NonNull; 38import android.annotation.Nullable; 39import android.annotation.Size; 40import android.annotation.TestApi; 41import android.annotation.UiThread; 42import android.content.ClipData; 43import android.content.Context; 44import android.content.ContextWrapper; 45import android.content.Intent; 46import android.content.res.ColorStateList; 47import android.content.res.Configuration; 48import android.content.res.Resources; 49import android.content.res.TypedArray; 50import android.graphics.Bitmap; 51import android.graphics.Canvas; 52import android.graphics.Color; 53import android.graphics.Insets; 54import android.graphics.Interpolator; 55import android.graphics.LinearGradient; 56import android.graphics.Matrix; 57import android.graphics.Outline; 58import android.graphics.Paint; 59import android.graphics.PixelFormat; 60import android.graphics.Point; 61import android.graphics.PorterDuff; 62import android.graphics.PorterDuffXfermode; 63import android.graphics.Rect; 64import android.graphics.RectF; 65import android.graphics.Region; 66import android.graphics.Shader; 67import android.graphics.drawable.ColorDrawable; 68import android.graphics.drawable.Drawable; 69import android.hardware.display.DisplayManagerGlobal; 70import android.os.Build.VERSION_CODES; 71import android.os.Bundle; 72import android.os.Handler; 73import android.os.IBinder; 74import android.os.Parcel; 75import android.os.Parcelable; 76import android.os.RemoteException; 77import android.os.SystemClock; 78import android.os.SystemProperties; 79import android.os.Trace; 80import android.text.TextUtils; 81import android.util.AttributeSet; 82import android.util.FloatProperty; 83import android.util.LayoutDirection; 84import android.util.Log; 85import android.util.LongSparseLongArray; 86import android.util.Pools.SynchronizedPool; 87import android.util.Property; 88import android.util.SparseArray; 89import android.util.StateSet; 90import android.util.SuperNotCalledException; 91import android.util.TypedValue; 92import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 93import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 94import android.view.AccessibilityIterators.TextSegmentIterator; 95import android.view.AccessibilityIterators.WordTextSegmentIterator; 96import android.view.ContextMenu.ContextMenuInfo; 97import android.view.accessibility.AccessibilityEvent; 98import android.view.accessibility.AccessibilityEventSource; 99import android.view.accessibility.AccessibilityManager; 100import android.view.accessibility.AccessibilityNodeInfo; 101import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 102import android.view.accessibility.AccessibilityNodeProvider; 103import android.view.animation.Animation; 104import android.view.animation.AnimationUtils; 105import android.view.animation.Transformation; 106import android.view.inputmethod.EditorInfo; 107import android.view.inputmethod.InputConnection; 108import android.view.inputmethod.InputMethodManager; 109import android.widget.Checkable; 110import android.widget.FrameLayout; 111import android.widget.ScrollBarDrawable; 112 113import com.android.internal.R; 114import com.android.internal.util.Predicate; 115import com.android.internal.view.TooltipPopup; 116import com.android.internal.view.menu.MenuBuilder; 117import com.android.internal.widget.ScrollBarUtils; 118 119import com.google.android.collect.Lists; 120import com.google.android.collect.Maps; 121 122import java.lang.annotation.Retention; 123import java.lang.annotation.RetentionPolicy; 124import java.lang.ref.WeakReference; 125import java.lang.reflect.Field; 126import java.lang.reflect.InvocationTargetException; 127import java.lang.reflect.Method; 128import java.lang.reflect.Modifier; 129import java.util.ArrayList; 130import java.util.Arrays; 131import java.util.Collection; 132import java.util.Collections; 133import java.util.HashMap; 134import java.util.List; 135import java.util.Locale; 136import java.util.Map; 137import java.util.concurrent.CopyOnWriteArrayList; 138import java.util.concurrent.atomic.AtomicInteger; 139 140/** 141 * <p> 142 * This class represents the basic building block for user interface components. A View 143 * occupies a rectangular area on the screen and is responsible for drawing and 144 * event handling. View is the base class for <em>widgets</em>, which are 145 * used to create interactive UI components (buttons, text fields, etc.). The 146 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 147 * are invisible containers that hold other Views (or other ViewGroups) and define 148 * their layout properties. 149 * </p> 150 * 151 * <div class="special reference"> 152 * <h3>Developer Guides</h3> 153 * <p>For information about using this class to develop your application's user interface, 154 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 155 * </div> 156 * 157 * <a name="Using"></a> 158 * <h3>Using Views</h3> 159 * <p> 160 * All of the views in a window are arranged in a single tree. You can add views 161 * either from code or by specifying a tree of views in one or more XML layout 162 * files. There are many specialized subclasses of views that act as controls or 163 * are capable of displaying text, images, or other content. 164 * </p> 165 * <p> 166 * Once you have created a tree of views, there are typically a few types of 167 * common operations you may wish to perform: 168 * <ul> 169 * <li><strong>Set properties:</strong> for example setting the text of a 170 * {@link android.widget.TextView}. The available properties and the methods 171 * that set them will vary among the different subclasses of views. Note that 172 * properties that are known at build time can be set in the XML layout 173 * files.</li> 174 * <li><strong>Set focus:</strong> The framework will handle moving focus in 175 * response to user input. To force focus to a specific view, call 176 * {@link #requestFocus}.</li> 177 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 178 * that will be notified when something interesting happens to the view. For 179 * example, all views will let you set a listener to be notified when the view 180 * gains or loses focus. You can register such a listener using 181 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 182 * Other view subclasses offer more specialized listeners. For example, a Button 183 * exposes a listener to notify clients when the button is clicked.</li> 184 * <li><strong>Set visibility:</strong> You can hide or show views using 185 * {@link #setVisibility(int)}.</li> 186 * </ul> 187 * </p> 188 * <p><em> 189 * Note: The Android framework is responsible for measuring, laying out and 190 * drawing views. You should not call methods that perform these actions on 191 * views yourself unless you are actually implementing a 192 * {@link android.view.ViewGroup}. 193 * </em></p> 194 * 195 * <a name="Lifecycle"></a> 196 * <h3>Implementing a Custom View</h3> 197 * 198 * <p> 199 * To implement a custom view, you will usually begin by providing overrides for 200 * some of the standard methods that the framework calls on all views. You do 201 * not need to override all of these methods. In fact, you can start by just 202 * overriding {@link #onDraw(android.graphics.Canvas)}. 203 * <table border="2" width="85%" align="center" cellpadding="5"> 204 * <thead> 205 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 206 * </thead> 207 * 208 * <tbody> 209 * <tr> 210 * <td rowspan="2">Creation</td> 211 * <td>Constructors</td> 212 * <td>There is a form of the constructor that are called when the view 213 * is created from code and a form that is called when the view is 214 * inflated from a layout file. The second form should parse and apply 215 * any attributes defined in the layout file. 216 * </td> 217 * </tr> 218 * <tr> 219 * <td><code>{@link #onFinishInflate()}</code></td> 220 * <td>Called after a view and all of its children has been inflated 221 * from XML.</td> 222 * </tr> 223 * 224 * <tr> 225 * <td rowspan="3">Layout</td> 226 * <td><code>{@link #onMeasure(int, int)}</code></td> 227 * <td>Called to determine the size requirements for this view and all 228 * of its children. 229 * </td> 230 * </tr> 231 * <tr> 232 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 233 * <td>Called when this view should assign a size and position to all 234 * of its children. 235 * </td> 236 * </tr> 237 * <tr> 238 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 239 * <td>Called when the size of this view has changed. 240 * </td> 241 * </tr> 242 * 243 * <tr> 244 * <td>Drawing</td> 245 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 246 * <td>Called when the view should render its content. 247 * </td> 248 * </tr> 249 * 250 * <tr> 251 * <td rowspan="4">Event processing</td> 252 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 253 * <td>Called when a new hardware key event occurs. 254 * </td> 255 * </tr> 256 * <tr> 257 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 258 * <td>Called when a hardware key up event occurs. 259 * </td> 260 * </tr> 261 * <tr> 262 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 263 * <td>Called when a trackball motion event occurs. 264 * </td> 265 * </tr> 266 * <tr> 267 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 268 * <td>Called when a touch screen motion event occurs. 269 * </td> 270 * </tr> 271 * 272 * <tr> 273 * <td rowspan="2">Focus</td> 274 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 275 * <td>Called when the view gains or loses focus. 276 * </td> 277 * </tr> 278 * 279 * <tr> 280 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 281 * <td>Called when the window containing the view gains or loses focus. 282 * </td> 283 * </tr> 284 * 285 * <tr> 286 * <td rowspan="3">Attaching</td> 287 * <td><code>{@link #onAttachedToWindow()}</code></td> 288 * <td>Called when the view is attached to a window. 289 * </td> 290 * </tr> 291 * 292 * <tr> 293 * <td><code>{@link #onDetachedFromWindow}</code></td> 294 * <td>Called when the view is detached from its window. 295 * </td> 296 * </tr> 297 * 298 * <tr> 299 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 300 * <td>Called when the visibility of the window containing the view 301 * has changed. 302 * </td> 303 * </tr> 304 * </tbody> 305 * 306 * </table> 307 * </p> 308 * 309 * <a name="IDs"></a> 310 * <h3>IDs</h3> 311 * Views may have an integer id associated with them. These ids are typically 312 * assigned in the layout XML files, and are used to find specific views within 313 * the view tree. A common pattern is to: 314 * <ul> 315 * <li>Define a Button in the layout file and assign it a unique ID. 316 * <pre> 317 * <Button 318 * android:id="@+id/my_button" 319 * android:layout_width="wrap_content" 320 * android:layout_height="wrap_content" 321 * android:text="@string/my_button_text"/> 322 * </pre></li> 323 * <li>From the onCreate method of an Activity, find the Button 324 * <pre class="prettyprint"> 325 * Button myButton = (Button) findViewById(R.id.my_button); 326 * </pre></li> 327 * </ul> 328 * <p> 329 * View IDs need not be unique throughout the tree, but it is good practice to 330 * ensure that they are at least unique within the part of the tree you are 331 * searching. 332 * </p> 333 * 334 * <a name="Position"></a> 335 * <h3>Position</h3> 336 * <p> 337 * The geometry of a view is that of a rectangle. A view has a location, 338 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 339 * two dimensions, expressed as a width and a height. The unit for location 340 * and dimensions is the pixel. 341 * </p> 342 * 343 * <p> 344 * It is possible to retrieve the location of a view by invoking the methods 345 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 346 * coordinate of the rectangle representing the view. The latter returns the 347 * top, or Y, coordinate of the rectangle representing the view. These methods 348 * both return the location of the view relative to its parent. For instance, 349 * when getLeft() returns 20, that means the view is located 20 pixels to the 350 * right of the left edge of its direct parent. 351 * </p> 352 * 353 * <p> 354 * In addition, several convenience methods are offered to avoid unnecessary 355 * computations, namely {@link #getRight()} and {@link #getBottom()}. 356 * These methods return the coordinates of the right and bottom edges of the 357 * rectangle representing the view. For instance, calling {@link #getRight()} 358 * is similar to the following computation: <code>getLeft() + getWidth()</code> 359 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 360 * </p> 361 * 362 * <a name="SizePaddingMargins"></a> 363 * <h3>Size, padding and margins</h3> 364 * <p> 365 * The size of a view is expressed with a width and a height. A view actually 366 * possess two pairs of width and height values. 367 * </p> 368 * 369 * <p> 370 * The first pair is known as <em>measured width</em> and 371 * <em>measured height</em>. These dimensions define how big a view wants to be 372 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 373 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 374 * and {@link #getMeasuredHeight()}. 375 * </p> 376 * 377 * <p> 378 * The second pair is simply known as <em>width</em> and <em>height</em>, or 379 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 380 * dimensions define the actual size of the view on screen, at drawing time and 381 * after layout. These values may, but do not have to, be different from the 382 * measured width and height. The width and height can be obtained by calling 383 * {@link #getWidth()} and {@link #getHeight()}. 384 * </p> 385 * 386 * <p> 387 * To measure its dimensions, a view takes into account its padding. The padding 388 * is expressed in pixels for the left, top, right and bottom parts of the view. 389 * Padding can be used to offset the content of the view by a specific amount of 390 * pixels. For instance, a left padding of 2 will push the view's content by 391 * 2 pixels to the right of the left edge. Padding can be set using the 392 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 393 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 394 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 395 * {@link #getPaddingEnd()}. 396 * </p> 397 * 398 * <p> 399 * Even though a view can define a padding, it does not provide any support for 400 * margins. However, view groups provide such a support. Refer to 401 * {@link android.view.ViewGroup} and 402 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 403 * </p> 404 * 405 * <a name="Layout"></a> 406 * <h3>Layout</h3> 407 * <p> 408 * Layout is a two pass process: a measure pass and a layout pass. The measuring 409 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 410 * of the view tree. Each view pushes dimension specifications down the tree 411 * during the recursion. At the end of the measure pass, every view has stored 412 * its measurements. The second pass happens in 413 * {@link #layout(int,int,int,int)} and is also top-down. During 414 * this pass each parent is responsible for positioning all of its children 415 * using the sizes computed in the measure pass. 416 * </p> 417 * 418 * <p> 419 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 420 * {@link #getMeasuredHeight()} values must be set, along with those for all of 421 * that view's descendants. A view's measured width and measured height values 422 * must respect the constraints imposed by the view's parents. This guarantees 423 * that at the end of the measure pass, all parents accept all of their 424 * children's measurements. A parent view may call measure() more than once on 425 * its children. For example, the parent may measure each child once with 426 * unspecified dimensions to find out how big they want to be, then call 427 * measure() on them again with actual numbers if the sum of all the children's 428 * unconstrained sizes is too big or too small. 429 * </p> 430 * 431 * <p> 432 * The measure pass uses two classes to communicate dimensions. The 433 * {@link MeasureSpec} class is used by views to tell their parents how they 434 * want to be measured and positioned. The base LayoutParams class just 435 * describes how big the view wants to be for both width and height. For each 436 * dimension, it can specify one of: 437 * <ul> 438 * <li> an exact number 439 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 440 * (minus padding) 441 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 442 * enclose its content (plus padding). 443 * </ul> 444 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 445 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 446 * an X and Y value. 447 * </p> 448 * 449 * <p> 450 * MeasureSpecs are used to push requirements down the tree from parent to 451 * child. A MeasureSpec can be in one of three modes: 452 * <ul> 453 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 454 * of a child view. For example, a LinearLayout may call measure() on its child 455 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 456 * tall the child view wants to be given a width of 240 pixels. 457 * <li>EXACTLY: This is used by the parent to impose an exact size on the 458 * child. The child must use this size, and guarantee that all of its 459 * descendants will fit within this size. 460 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 461 * child. The child must guarantee that it and all of its descendants will fit 462 * within this size. 463 * </ul> 464 * </p> 465 * 466 * <p> 467 * To initiate a layout, call {@link #requestLayout}. This method is typically 468 * called by a view on itself when it believes that is can no longer fit within 469 * its current bounds. 470 * </p> 471 * 472 * <a name="Drawing"></a> 473 * <h3>Drawing</h3> 474 * <p> 475 * Drawing is handled by walking the tree and recording the drawing commands of 476 * any View that needs to update. After this, the drawing commands of the 477 * entire tree are issued to screen, clipped to the newly damaged area. 478 * </p> 479 * 480 * <p> 481 * The tree is largely recorded and drawn in order, with parents drawn before 482 * (i.e., behind) their children, with siblings drawn in the order they appear 483 * in the tree. If you set a background drawable for a View, then the View will 484 * draw it before calling back to its <code>onDraw()</code> method. The child 485 * drawing order can be overridden with 486 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 487 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 488 * </p> 489 * 490 * <p> 491 * To force a view to draw, call {@link #invalidate()}. 492 * </p> 493 * 494 * <a name="EventHandlingThreading"></a> 495 * <h3>Event Handling and Threading</h3> 496 * <p> 497 * The basic cycle of a view is as follows: 498 * <ol> 499 * <li>An event comes in and is dispatched to the appropriate view. The view 500 * handles the event and notifies any listeners.</li> 501 * <li>If in the course of processing the event, the view's bounds may need 502 * to be changed, the view will call {@link #requestLayout()}.</li> 503 * <li>Similarly, if in the course of processing the event the view's appearance 504 * may need to be changed, the view will call {@link #invalidate()}.</li> 505 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 506 * the framework will take care of measuring, laying out, and drawing the tree 507 * as appropriate.</li> 508 * </ol> 509 * </p> 510 * 511 * <p><em>Note: The entire view tree is single threaded. You must always be on 512 * the UI thread when calling any method on any view.</em> 513 * If you are doing work on other threads and want to update the state of a view 514 * from that thread, you should use a {@link Handler}. 515 * </p> 516 * 517 * <a name="FocusHandling"></a> 518 * <h3>Focus Handling</h3> 519 * <p> 520 * The framework will handle routine focus movement in response to user input. 521 * This includes changing the focus as views are removed or hidden, or as new 522 * views become available. Views indicate their willingness to take focus 523 * through the {@link #isFocusable} method. To change whether a view can take 524 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 525 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 526 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 527 * </p> 528 * <p> 529 * Focus movement is based on an algorithm which finds the nearest neighbor in a 530 * given direction. In rare cases, the default algorithm may not match the 531 * intended behavior of the developer. In these situations, you can provide 532 * explicit overrides by using these XML attributes in the layout file: 533 * <pre> 534 * nextFocusDown 535 * nextFocusLeft 536 * nextFocusRight 537 * nextFocusUp 538 * </pre> 539 * </p> 540 * 541 * 542 * <p> 543 * To get a particular view to take focus, call {@link #requestFocus()}. 544 * </p> 545 * 546 * <a name="TouchMode"></a> 547 * <h3>Touch Mode</h3> 548 * <p> 549 * When a user is navigating a user interface via directional keys such as a D-pad, it is 550 * necessary to give focus to actionable items such as buttons so the user can see 551 * what will take input. If the device has touch capabilities, however, and the user 552 * begins interacting with the interface by touching it, it is no longer necessary to 553 * always highlight, or give focus to, a particular view. This motivates a mode 554 * for interaction named 'touch mode'. 555 * </p> 556 * <p> 557 * For a touch capable device, once the user touches the screen, the device 558 * will enter touch mode. From this point onward, only views for which 559 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 560 * Other views that are touchable, like buttons, will not take focus when touched; they will 561 * only fire the on click listeners. 562 * </p> 563 * <p> 564 * Any time a user hits a directional key, such as a D-pad direction, the view device will 565 * exit touch mode, and find a view to take focus, so that the user may resume interacting 566 * with the user interface without touching the screen again. 567 * </p> 568 * <p> 569 * The touch mode state is maintained across {@link android.app.Activity}s. Call 570 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 571 * </p> 572 * 573 * <a name="Scrolling"></a> 574 * <h3>Scrolling</h3> 575 * <p> 576 * The framework provides basic support for views that wish to internally 577 * scroll their content. This includes keeping track of the X and Y scroll 578 * offset as well as mechanisms for drawing scrollbars. See 579 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 580 * {@link #awakenScrollBars()} for more details. 581 * </p> 582 * 583 * <a name="Tags"></a> 584 * <h3>Tags</h3> 585 * <p> 586 * Unlike IDs, tags are not used to identify views. Tags are essentially an 587 * extra piece of information that can be associated with a view. They are most 588 * often used as a convenience to store data related to views in the views 589 * themselves rather than by putting them in a separate structure. 590 * </p> 591 * <p> 592 * Tags may be specified with character sequence values in layout XML as either 593 * a single tag using the {@link android.R.styleable#View_tag android:tag} 594 * attribute or multiple tags using the {@code <tag>} child element: 595 * <pre> 596 * <View ... 597 * android:tag="@string/mytag_value" /> 598 * <View ...> 599 * <tag android:id="@+id/mytag" 600 * android:value="@string/mytag_value" /> 601 * </View> 602 * </pre> 603 * </p> 604 * <p> 605 * Tags may also be specified with arbitrary objects from code using 606 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 607 * </p> 608 * 609 * <a name="Themes"></a> 610 * <h3>Themes</h3> 611 * <p> 612 * By default, Views are created using the theme of the Context object supplied 613 * to their constructor; however, a different theme may be specified by using 614 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 615 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 616 * code. 617 * </p> 618 * <p> 619 * When the {@link android.R.styleable#View_theme android:theme} attribute is 620 * used in XML, the specified theme is applied on top of the inflation 621 * context's theme (see {@link LayoutInflater}) and used for the view itself as 622 * well as any child elements. 623 * </p> 624 * <p> 625 * In the following example, both views will be created using the Material dark 626 * color scheme; however, because an overlay theme is used which only defines a 627 * subset of attributes, the value of 628 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 629 * the inflation context's theme (e.g. the Activity theme) will be preserved. 630 * <pre> 631 * <LinearLayout 632 * ... 633 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 634 * <View ...> 635 * </LinearLayout> 636 * </pre> 637 * </p> 638 * 639 * <a name="Properties"></a> 640 * <h3>Properties</h3> 641 * <p> 642 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 643 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 644 * available both in the {@link Property} form as well as in similarly-named setter/getter 645 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 646 * be used to set persistent state associated with these rendering-related properties on the view. 647 * The properties and methods can also be used in conjunction with 648 * {@link android.animation.Animator Animator}-based animations, described more in the 649 * <a href="#Animation">Animation</a> section. 650 * </p> 651 * 652 * <a name="Animation"></a> 653 * <h3>Animation</h3> 654 * <p> 655 * Starting with Android 3.0, the preferred way of animating views is to use the 656 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 657 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 658 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 659 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 660 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 661 * makes animating these View properties particularly easy and efficient. 662 * </p> 663 * <p> 664 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 665 * You can attach an {@link Animation} object to a view using 666 * {@link #setAnimation(Animation)} or 667 * {@link #startAnimation(Animation)}. The animation can alter the scale, 668 * rotation, translation and alpha of a view over time. If the animation is 669 * attached to a view that has children, the animation will affect the entire 670 * subtree rooted by that node. When an animation is started, the framework will 671 * take care of redrawing the appropriate views until the animation completes. 672 * </p> 673 * 674 * <a name="Security"></a> 675 * <h3>Security</h3> 676 * <p> 677 * Sometimes it is essential that an application be able to verify that an action 678 * is being performed with the full knowledge and consent of the user, such as 679 * granting a permission request, making a purchase or clicking on an advertisement. 680 * Unfortunately, a malicious application could try to spoof the user into 681 * performing these actions, unaware, by concealing the intended purpose of the view. 682 * As a remedy, the framework offers a touch filtering mechanism that can be used to 683 * improve the security of views that provide access to sensitive functionality. 684 * </p><p> 685 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 686 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 687 * will discard touches that are received whenever the view's window is obscured by 688 * another visible window. As a result, the view will not receive touches whenever a 689 * toast, dialog or other window appears above the view's window. 690 * </p><p> 691 * For more fine-grained control over security, consider overriding the 692 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 693 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 694 * </p> 695 * 696 * @attr ref android.R.styleable#View_alpha 697 * @attr ref android.R.styleable#View_background 698 * @attr ref android.R.styleable#View_clickable 699 * @attr ref android.R.styleable#View_contentDescription 700 * @attr ref android.R.styleable#View_drawingCacheQuality 701 * @attr ref android.R.styleable#View_duplicateParentState 702 * @attr ref android.R.styleable#View_id 703 * @attr ref android.R.styleable#View_requiresFadingEdge 704 * @attr ref android.R.styleable#View_fadeScrollbars 705 * @attr ref android.R.styleable#View_fadingEdgeLength 706 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 707 * @attr ref android.R.styleable#View_fitsSystemWindows 708 * @attr ref android.R.styleable#View_isScrollContainer 709 * @attr ref android.R.styleable#View_focusable 710 * @attr ref android.R.styleable#View_focusableInTouchMode 711 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 712 * @attr ref android.R.styleable#View_keepScreenOn 713 * @attr ref android.R.styleable#View_layerType 714 * @attr ref android.R.styleable#View_layoutDirection 715 * @attr ref android.R.styleable#View_longClickable 716 * @attr ref android.R.styleable#View_minHeight 717 * @attr ref android.R.styleable#View_minWidth 718 * @attr ref android.R.styleable#View_nextFocusDown 719 * @attr ref android.R.styleable#View_nextFocusLeft 720 * @attr ref android.R.styleable#View_nextFocusRight 721 * @attr ref android.R.styleable#View_nextFocusUp 722 * @attr ref android.R.styleable#View_onClick 723 * @attr ref android.R.styleable#View_padding 724 * @attr ref android.R.styleable#View_paddingBottom 725 * @attr ref android.R.styleable#View_paddingLeft 726 * @attr ref android.R.styleable#View_paddingRight 727 * @attr ref android.R.styleable#View_paddingTop 728 * @attr ref android.R.styleable#View_paddingStart 729 * @attr ref android.R.styleable#View_paddingEnd 730 * @attr ref android.R.styleable#View_saveEnabled 731 * @attr ref android.R.styleable#View_rotation 732 * @attr ref android.R.styleable#View_rotationX 733 * @attr ref android.R.styleable#View_rotationY 734 * @attr ref android.R.styleable#View_scaleX 735 * @attr ref android.R.styleable#View_scaleY 736 * @attr ref android.R.styleable#View_scrollX 737 * @attr ref android.R.styleable#View_scrollY 738 * @attr ref android.R.styleable#View_scrollbarSize 739 * @attr ref android.R.styleable#View_scrollbarStyle 740 * @attr ref android.R.styleable#View_scrollbars 741 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 742 * @attr ref android.R.styleable#View_scrollbarFadeDuration 743 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 744 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 745 * @attr ref android.R.styleable#View_scrollbarThumbVertical 746 * @attr ref android.R.styleable#View_scrollbarTrackVertical 747 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 748 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 749 * @attr ref android.R.styleable#View_stateListAnimator 750 * @attr ref android.R.styleable#View_transitionName 751 * @attr ref android.R.styleable#View_soundEffectsEnabled 752 * @attr ref android.R.styleable#View_tag 753 * @attr ref android.R.styleable#View_textAlignment 754 * @attr ref android.R.styleable#View_textDirection 755 * @attr ref android.R.styleable#View_transformPivotX 756 * @attr ref android.R.styleable#View_transformPivotY 757 * @attr ref android.R.styleable#View_translationX 758 * @attr ref android.R.styleable#View_translationY 759 * @attr ref android.R.styleable#View_translationZ 760 * @attr ref android.R.styleable#View_visibility 761 * @attr ref android.R.styleable#View_theme 762 * 763 * @see android.view.ViewGroup 764 */ 765@UiThread 766public class View implements Drawable.Callback, KeyEvent.Callback, 767 AccessibilityEventSource { 768 private static final boolean DBG = false; 769 770 /** @hide */ 771 public static boolean DEBUG_DRAW = false; 772 773 /** 774 * The logging tag used by this class with android.util.Log. 775 */ 776 protected static final String VIEW_LOG_TAG = "View"; 777 778 /** 779 * When set to true, apps will draw debugging information about their layouts. 780 * 781 * @hide 782 */ 783 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 784 785 /** 786 * When set to true, this view will save its attribute data. 787 * 788 * @hide 789 */ 790 public static boolean mDebugViewAttributes = false; 791 792 /** 793 * Used to mark a View that has no ID. 794 */ 795 public static final int NO_ID = -1; 796 797 /** 798 * Signals that compatibility booleans have been initialized according to 799 * target SDK versions. 800 */ 801 private static boolean sCompatibilityDone = false; 802 803 /** 804 * Use the old (broken) way of building MeasureSpecs. 805 */ 806 private static boolean sUseBrokenMakeMeasureSpec = false; 807 808 /** 809 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 810 */ 811 static boolean sUseZeroUnspecifiedMeasureSpec = false; 812 813 /** 814 * Ignore any optimizations using the measure cache. 815 */ 816 private static boolean sIgnoreMeasureCache = false; 817 818 /** 819 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 820 */ 821 private static boolean sAlwaysRemeasureExactly = false; 822 823 /** 824 * Relax constraints around whether setLayoutParams() must be called after 825 * modifying the layout params. 826 */ 827 private static boolean sLayoutParamsAlwaysChanged = false; 828 829 /** 830 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 831 * without throwing 832 */ 833 static boolean sTextureViewIgnoresDrawableSetters = false; 834 835 /** 836 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 837 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 838 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 839 * check is implemented for backwards compatibility. 840 * 841 * {@hide} 842 */ 843 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 844 845 /** 846 * Prior to N, when drag enters into child of a view that has already received an 847 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 848 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 849 * false from its event handler for these events. 850 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 851 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 852 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 853 */ 854 static boolean sCascadedDragDrop; 855 856 /** 857 * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when 858 * calling setFlags. 859 */ 860 private static final int NOT_FOCUSABLE = 0x00000000; 861 862 /** 863 * This view wants keystrokes. Use with TAKES_FOCUS_MASK when calling 864 * setFlags. 865 */ 866 private static final int FOCUSABLE = 0x00000001; 867 868 /** 869 * Mask for use with setFlags indicating bits used for focus. 870 */ 871 private static final int FOCUSABLE_MASK = 0x00000001; 872 873 /** 874 * This view will adjust its padding to fit sytem windows (e.g. status bar) 875 */ 876 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 877 878 /** @hide */ 879 @IntDef({VISIBLE, INVISIBLE, GONE}) 880 @Retention(RetentionPolicy.SOURCE) 881 public @interface Visibility {} 882 883 /** 884 * This view is visible. 885 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 886 * android:visibility}. 887 */ 888 public static final int VISIBLE = 0x00000000; 889 890 /** 891 * This view is invisible, but it still takes up space for layout purposes. 892 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 893 * android:visibility}. 894 */ 895 public static final int INVISIBLE = 0x00000004; 896 897 /** 898 * This view is invisible, and it doesn't take any space for layout 899 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 900 * android:visibility}. 901 */ 902 public static final int GONE = 0x00000008; 903 904 /** 905 * Mask for use with setFlags indicating bits used for visibility. 906 * {@hide} 907 */ 908 static final int VISIBILITY_MASK = 0x0000000C; 909 910 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 911 912 /** 913 * This view is enabled. Interpretation varies by subclass. 914 * Use with ENABLED_MASK when calling setFlags. 915 * {@hide} 916 */ 917 static final int ENABLED = 0x00000000; 918 919 /** 920 * This view is disabled. Interpretation varies by subclass. 921 * Use with ENABLED_MASK when calling setFlags. 922 * {@hide} 923 */ 924 static final int DISABLED = 0x00000020; 925 926 /** 927 * Mask for use with setFlags indicating bits used for indicating whether 928 * this view is enabled 929 * {@hide} 930 */ 931 static final int ENABLED_MASK = 0x00000020; 932 933 /** 934 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 935 * called and further optimizations will be performed. It is okay to have 936 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 937 * {@hide} 938 */ 939 static final int WILL_NOT_DRAW = 0x00000080; 940 941 /** 942 * Mask for use with setFlags indicating bits used for indicating whether 943 * this view is will draw 944 * {@hide} 945 */ 946 static final int DRAW_MASK = 0x00000080; 947 948 /** 949 * <p>This view doesn't show scrollbars.</p> 950 * {@hide} 951 */ 952 static final int SCROLLBARS_NONE = 0x00000000; 953 954 /** 955 * <p>This view shows horizontal scrollbars.</p> 956 * {@hide} 957 */ 958 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 959 960 /** 961 * <p>This view shows vertical scrollbars.</p> 962 * {@hide} 963 */ 964 static final int SCROLLBARS_VERTICAL = 0x00000200; 965 966 /** 967 * <p>Mask for use with setFlags indicating bits used for indicating which 968 * scrollbars are enabled.</p> 969 * {@hide} 970 */ 971 static final int SCROLLBARS_MASK = 0x00000300; 972 973 /** 974 * Indicates that the view should filter touches when its window is obscured. 975 * Refer to the class comments for more information about this security feature. 976 * {@hide} 977 */ 978 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 979 980 /** 981 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 982 * that they are optional and should be skipped if the window has 983 * requested system UI flags that ignore those insets for layout. 984 */ 985 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 986 987 /** 988 * <p>This view doesn't show fading edges.</p> 989 * {@hide} 990 */ 991 static final int FADING_EDGE_NONE = 0x00000000; 992 993 /** 994 * <p>This view shows horizontal fading edges.</p> 995 * {@hide} 996 */ 997 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 998 999 /** 1000 * <p>This view shows vertical fading edges.</p> 1001 * {@hide} 1002 */ 1003 static final int FADING_EDGE_VERTICAL = 0x00002000; 1004 1005 /** 1006 * <p>Mask for use with setFlags indicating bits used for indicating which 1007 * fading edges are enabled.</p> 1008 * {@hide} 1009 */ 1010 static final int FADING_EDGE_MASK = 0x00003000; 1011 1012 /** 1013 * <p>Indicates this view can be clicked. When clickable, a View reacts 1014 * to clicks by notifying the OnClickListener.<p> 1015 * {@hide} 1016 */ 1017 static final int CLICKABLE = 0x00004000; 1018 1019 /** 1020 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1021 * {@hide} 1022 */ 1023 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1024 1025 /** 1026 * <p>Indicates that no icicle should be saved for this view.<p> 1027 * {@hide} 1028 */ 1029 static final int SAVE_DISABLED = 0x000010000; 1030 1031 /** 1032 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1033 * property.</p> 1034 * {@hide} 1035 */ 1036 static final int SAVE_DISABLED_MASK = 0x000010000; 1037 1038 /** 1039 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1040 * {@hide} 1041 */ 1042 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1043 1044 /** 1045 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1046 * {@hide} 1047 */ 1048 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1049 1050 /** @hide */ 1051 @Retention(RetentionPolicy.SOURCE) 1052 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1053 public @interface DrawingCacheQuality {} 1054 1055 /** 1056 * <p>Enables low quality mode for the drawing cache.</p> 1057 */ 1058 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1059 1060 /** 1061 * <p>Enables high quality mode for the drawing cache.</p> 1062 */ 1063 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1064 1065 /** 1066 * <p>Enables automatic quality mode for the drawing cache.</p> 1067 */ 1068 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1069 1070 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1071 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1072 }; 1073 1074 /** 1075 * <p>Mask for use with setFlags indicating bits used for the cache 1076 * quality property.</p> 1077 * {@hide} 1078 */ 1079 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1080 1081 /** 1082 * <p> 1083 * Indicates this view can be long clicked. When long clickable, a View 1084 * reacts to long clicks by notifying the OnLongClickListener or showing a 1085 * context menu. 1086 * </p> 1087 * {@hide} 1088 */ 1089 static final int LONG_CLICKABLE = 0x00200000; 1090 1091 /** 1092 * <p>Indicates that this view gets its drawable states from its direct parent 1093 * and ignores its original internal states.</p> 1094 * 1095 * @hide 1096 */ 1097 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1098 1099 /** 1100 * <p> 1101 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1102 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1103 * OnContextClickListener. 1104 * </p> 1105 * {@hide} 1106 */ 1107 static final int CONTEXT_CLICKABLE = 0x00800000; 1108 1109 1110 /** @hide */ 1111 @IntDef({ 1112 SCROLLBARS_INSIDE_OVERLAY, 1113 SCROLLBARS_INSIDE_INSET, 1114 SCROLLBARS_OUTSIDE_OVERLAY, 1115 SCROLLBARS_OUTSIDE_INSET 1116 }) 1117 @Retention(RetentionPolicy.SOURCE) 1118 public @interface ScrollBarStyle {} 1119 1120 /** 1121 * The scrollbar style to display the scrollbars inside the content area, 1122 * without increasing the padding. The scrollbars will be overlaid with 1123 * translucency on the view's content. 1124 */ 1125 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1126 1127 /** 1128 * The scrollbar style to display the scrollbars inside the padded area, 1129 * increasing the padding of the view. The scrollbars will not overlap the 1130 * content area of the view. 1131 */ 1132 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1133 1134 /** 1135 * The scrollbar style to display the scrollbars at the edge of the view, 1136 * without increasing the padding. The scrollbars will be overlaid with 1137 * translucency. 1138 */ 1139 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1140 1141 /** 1142 * The scrollbar style to display the scrollbars at the edge of the view, 1143 * increasing the padding of the view. The scrollbars will only overlap the 1144 * background, if any. 1145 */ 1146 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1147 1148 /** 1149 * Mask to check if the scrollbar style is overlay or inset. 1150 * {@hide} 1151 */ 1152 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1153 1154 /** 1155 * Mask to check if the scrollbar style is inside or outside. 1156 * {@hide} 1157 */ 1158 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1159 1160 /** 1161 * Mask for scrollbar style. 1162 * {@hide} 1163 */ 1164 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1165 1166 /** 1167 * View flag indicating that the screen should remain on while the 1168 * window containing this view is visible to the user. This effectively 1169 * takes care of automatically setting the WindowManager's 1170 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1171 */ 1172 public static final int KEEP_SCREEN_ON = 0x04000000; 1173 1174 /** 1175 * View flag indicating whether this view should have sound effects enabled 1176 * for events such as clicking and touching. 1177 */ 1178 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1179 1180 /** 1181 * View flag indicating whether this view should have haptic feedback 1182 * enabled for events such as long presses. 1183 */ 1184 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1185 1186 /** 1187 * <p>Indicates that the view hierarchy should stop saving state when 1188 * it reaches this view. If state saving is initiated immediately at 1189 * the view, it will be allowed. 1190 * {@hide} 1191 */ 1192 static final int PARENT_SAVE_DISABLED = 0x20000000; 1193 1194 /** 1195 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1196 * {@hide} 1197 */ 1198 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1199 1200 private static Paint sDebugPaint; 1201 1202 /** 1203 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1204 * {@hide} 1205 */ 1206 static final int TOOLTIP = 0x40000000; 1207 1208 /** @hide */ 1209 @IntDef(flag = true, 1210 value = { 1211 FOCUSABLES_ALL, 1212 FOCUSABLES_TOUCH_MODE 1213 }) 1214 @Retention(RetentionPolicy.SOURCE) 1215 public @interface FocusableMode {} 1216 1217 /** 1218 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1219 * should add all focusable Views regardless if they are focusable in touch mode. 1220 */ 1221 public static final int FOCUSABLES_ALL = 0x00000000; 1222 1223 /** 1224 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1225 * should add only Views focusable in touch mode. 1226 */ 1227 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1228 1229 /** @hide */ 1230 @IntDef({ 1231 FOCUS_BACKWARD, 1232 FOCUS_FORWARD, 1233 FOCUS_LEFT, 1234 FOCUS_UP, 1235 FOCUS_RIGHT, 1236 FOCUS_DOWN 1237 }) 1238 @Retention(RetentionPolicy.SOURCE) 1239 public @interface FocusDirection {} 1240 1241 /** @hide */ 1242 @IntDef({ 1243 FOCUS_LEFT, 1244 FOCUS_UP, 1245 FOCUS_RIGHT, 1246 FOCUS_DOWN 1247 }) 1248 @Retention(RetentionPolicy.SOURCE) 1249 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1250 1251 /** @hide */ 1252 @IntDef({ 1253 KEYBOARD_NAVIGATION_GROUP_CLUSTER, 1254 KEYBOARD_NAVIGATION_GROUP_SECTION 1255 }) 1256 @Retention(RetentionPolicy.SOURCE) 1257 public @interface KeyboardNavigationGroupType {} 1258 1259 /** 1260 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1261 * item. 1262 */ 1263 public static final int FOCUS_BACKWARD = 0x00000001; 1264 1265 /** 1266 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1267 * item. 1268 */ 1269 public static final int FOCUS_FORWARD = 0x00000002; 1270 1271 /** 1272 * Use with {@link #focusSearch(int)}. Move focus to the left. 1273 */ 1274 public static final int FOCUS_LEFT = 0x00000011; 1275 1276 /** 1277 * Use with {@link #focusSearch(int)}. Move focus up. 1278 */ 1279 public static final int FOCUS_UP = 0x00000021; 1280 1281 /** 1282 * Use with {@link #focusSearch(int)}. Move focus to the right. 1283 */ 1284 public static final int FOCUS_RIGHT = 0x00000042; 1285 1286 /** 1287 * Use with {@link #focusSearch(int)}. Move focus down. 1288 */ 1289 public static final int FOCUS_DOWN = 0x00000082; 1290 1291 /** 1292 * Use with {@link #keyboardNavigationGroupSearch(int, View, int)}. Search for a keyboard 1293 * navigation cluster. 1294 */ 1295 public static final int KEYBOARD_NAVIGATION_GROUP_CLUSTER = 1; 1296 1297 /** 1298 * Use with {@link #keyboardNavigationGroupSearch(int, View, int)}. Search for a keyboard 1299 * navigation section. 1300 */ 1301 public static final int KEYBOARD_NAVIGATION_GROUP_SECTION = 2; 1302 1303 /** 1304 * Bits of {@link #getMeasuredWidthAndState()} and 1305 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1306 */ 1307 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1308 1309 /** 1310 * Bits of {@link #getMeasuredWidthAndState()} and 1311 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1312 */ 1313 public static final int MEASURED_STATE_MASK = 0xff000000; 1314 1315 /** 1316 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1317 * for functions that combine both width and height into a single int, 1318 * such as {@link #getMeasuredState()} and the childState argument of 1319 * {@link #resolveSizeAndState(int, int, int)}. 1320 */ 1321 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1322 1323 /** 1324 * Bit of {@link #getMeasuredWidthAndState()} and 1325 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1326 * is smaller that the space the view would like to have. 1327 */ 1328 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1329 1330 /** 1331 * Base View state sets 1332 */ 1333 // Singles 1334 /** 1335 * Indicates the view has no states set. States are used with 1336 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1337 * view depending on its state. 1338 * 1339 * @see android.graphics.drawable.Drawable 1340 * @see #getDrawableState() 1341 */ 1342 protected static final int[] EMPTY_STATE_SET; 1343 /** 1344 * Indicates the view is enabled. States are used with 1345 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1346 * view depending on its state. 1347 * 1348 * @see android.graphics.drawable.Drawable 1349 * @see #getDrawableState() 1350 */ 1351 protected static final int[] ENABLED_STATE_SET; 1352 /** 1353 * Indicates the view is focused. States are used with 1354 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1355 * view depending on its state. 1356 * 1357 * @see android.graphics.drawable.Drawable 1358 * @see #getDrawableState() 1359 */ 1360 protected static final int[] FOCUSED_STATE_SET; 1361 /** 1362 * Indicates the view is selected. States are used with 1363 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1364 * view depending on its state. 1365 * 1366 * @see android.graphics.drawable.Drawable 1367 * @see #getDrawableState() 1368 */ 1369 protected static final int[] SELECTED_STATE_SET; 1370 /** 1371 * Indicates the view is pressed. States are used with 1372 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1373 * view depending on its state. 1374 * 1375 * @see android.graphics.drawable.Drawable 1376 * @see #getDrawableState() 1377 */ 1378 protected static final int[] PRESSED_STATE_SET; 1379 /** 1380 * Indicates the view's window has focus. States are used with 1381 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1382 * view depending on its state. 1383 * 1384 * @see android.graphics.drawable.Drawable 1385 * @see #getDrawableState() 1386 */ 1387 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1388 // Doubles 1389 /** 1390 * Indicates the view is enabled and has the focus. 1391 * 1392 * @see #ENABLED_STATE_SET 1393 * @see #FOCUSED_STATE_SET 1394 */ 1395 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1396 /** 1397 * Indicates the view is enabled and selected. 1398 * 1399 * @see #ENABLED_STATE_SET 1400 * @see #SELECTED_STATE_SET 1401 */ 1402 protected static final int[] ENABLED_SELECTED_STATE_SET; 1403 /** 1404 * Indicates the view is enabled and that its window has focus. 1405 * 1406 * @see #ENABLED_STATE_SET 1407 * @see #WINDOW_FOCUSED_STATE_SET 1408 */ 1409 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1410 /** 1411 * Indicates the view is focused and selected. 1412 * 1413 * @see #FOCUSED_STATE_SET 1414 * @see #SELECTED_STATE_SET 1415 */ 1416 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1417 /** 1418 * Indicates the view has the focus and that its window has the focus. 1419 * 1420 * @see #FOCUSED_STATE_SET 1421 * @see #WINDOW_FOCUSED_STATE_SET 1422 */ 1423 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1424 /** 1425 * Indicates the view is selected and that its window has the focus. 1426 * 1427 * @see #SELECTED_STATE_SET 1428 * @see #WINDOW_FOCUSED_STATE_SET 1429 */ 1430 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1431 // Triples 1432 /** 1433 * Indicates the view is enabled, focused and selected. 1434 * 1435 * @see #ENABLED_STATE_SET 1436 * @see #FOCUSED_STATE_SET 1437 * @see #SELECTED_STATE_SET 1438 */ 1439 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1440 /** 1441 * Indicates the view is enabled, focused and its window has the focus. 1442 * 1443 * @see #ENABLED_STATE_SET 1444 * @see #FOCUSED_STATE_SET 1445 * @see #WINDOW_FOCUSED_STATE_SET 1446 */ 1447 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1448 /** 1449 * Indicates the view is enabled, selected and its window has the focus. 1450 * 1451 * @see #ENABLED_STATE_SET 1452 * @see #SELECTED_STATE_SET 1453 * @see #WINDOW_FOCUSED_STATE_SET 1454 */ 1455 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1456 /** 1457 * Indicates the view is focused, selected and its window has the focus. 1458 * 1459 * @see #FOCUSED_STATE_SET 1460 * @see #SELECTED_STATE_SET 1461 * @see #WINDOW_FOCUSED_STATE_SET 1462 */ 1463 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1464 /** 1465 * Indicates the view is enabled, focused, selected and its window 1466 * has the focus. 1467 * 1468 * @see #ENABLED_STATE_SET 1469 * @see #FOCUSED_STATE_SET 1470 * @see #SELECTED_STATE_SET 1471 * @see #WINDOW_FOCUSED_STATE_SET 1472 */ 1473 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1474 /** 1475 * Indicates the view is pressed and its window has the focus. 1476 * 1477 * @see #PRESSED_STATE_SET 1478 * @see #WINDOW_FOCUSED_STATE_SET 1479 */ 1480 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1481 /** 1482 * Indicates the view is pressed and selected. 1483 * 1484 * @see #PRESSED_STATE_SET 1485 * @see #SELECTED_STATE_SET 1486 */ 1487 protected static final int[] PRESSED_SELECTED_STATE_SET; 1488 /** 1489 * Indicates the view is pressed, selected and its window has the focus. 1490 * 1491 * @see #PRESSED_STATE_SET 1492 * @see #SELECTED_STATE_SET 1493 * @see #WINDOW_FOCUSED_STATE_SET 1494 */ 1495 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1496 /** 1497 * Indicates the view is pressed and focused. 1498 * 1499 * @see #PRESSED_STATE_SET 1500 * @see #FOCUSED_STATE_SET 1501 */ 1502 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1503 /** 1504 * Indicates the view is pressed, focused and its window has the focus. 1505 * 1506 * @see #PRESSED_STATE_SET 1507 * @see #FOCUSED_STATE_SET 1508 * @see #WINDOW_FOCUSED_STATE_SET 1509 */ 1510 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1511 /** 1512 * Indicates the view is pressed, focused and selected. 1513 * 1514 * @see #PRESSED_STATE_SET 1515 * @see #SELECTED_STATE_SET 1516 * @see #FOCUSED_STATE_SET 1517 */ 1518 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1519 /** 1520 * Indicates the view is pressed, focused, selected and its window has the focus. 1521 * 1522 * @see #PRESSED_STATE_SET 1523 * @see #FOCUSED_STATE_SET 1524 * @see #SELECTED_STATE_SET 1525 * @see #WINDOW_FOCUSED_STATE_SET 1526 */ 1527 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1528 /** 1529 * Indicates the view is pressed and enabled. 1530 * 1531 * @see #PRESSED_STATE_SET 1532 * @see #ENABLED_STATE_SET 1533 */ 1534 protected static final int[] PRESSED_ENABLED_STATE_SET; 1535 /** 1536 * Indicates the view is pressed, enabled and its window has the focus. 1537 * 1538 * @see #PRESSED_STATE_SET 1539 * @see #ENABLED_STATE_SET 1540 * @see #WINDOW_FOCUSED_STATE_SET 1541 */ 1542 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1543 /** 1544 * Indicates the view is pressed, enabled and selected. 1545 * 1546 * @see #PRESSED_STATE_SET 1547 * @see #ENABLED_STATE_SET 1548 * @see #SELECTED_STATE_SET 1549 */ 1550 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1551 /** 1552 * Indicates the view is pressed, enabled, selected and its window has the 1553 * focus. 1554 * 1555 * @see #PRESSED_STATE_SET 1556 * @see #ENABLED_STATE_SET 1557 * @see #SELECTED_STATE_SET 1558 * @see #WINDOW_FOCUSED_STATE_SET 1559 */ 1560 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1561 /** 1562 * Indicates the view is pressed, enabled and focused. 1563 * 1564 * @see #PRESSED_STATE_SET 1565 * @see #ENABLED_STATE_SET 1566 * @see #FOCUSED_STATE_SET 1567 */ 1568 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1569 /** 1570 * Indicates the view is pressed, enabled, focused and its window has the 1571 * focus. 1572 * 1573 * @see #PRESSED_STATE_SET 1574 * @see #ENABLED_STATE_SET 1575 * @see #FOCUSED_STATE_SET 1576 * @see #WINDOW_FOCUSED_STATE_SET 1577 */ 1578 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1579 /** 1580 * Indicates the view is pressed, enabled, focused and selected. 1581 * 1582 * @see #PRESSED_STATE_SET 1583 * @see #ENABLED_STATE_SET 1584 * @see #SELECTED_STATE_SET 1585 * @see #FOCUSED_STATE_SET 1586 */ 1587 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1588 /** 1589 * Indicates the view is pressed, enabled, focused, selected and its window 1590 * has the focus. 1591 * 1592 * @see #PRESSED_STATE_SET 1593 * @see #ENABLED_STATE_SET 1594 * @see #SELECTED_STATE_SET 1595 * @see #FOCUSED_STATE_SET 1596 * @see #WINDOW_FOCUSED_STATE_SET 1597 */ 1598 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1599 1600 static { 1601 EMPTY_STATE_SET = StateSet.get(0); 1602 1603 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1604 1605 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1606 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1607 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1608 1609 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1610 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1611 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1612 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1613 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1614 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1615 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1616 | StateSet.VIEW_STATE_FOCUSED); 1617 1618 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1619 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1620 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1621 ENABLED_SELECTED_STATE_SET = StateSet.get( 1622 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1623 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1624 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1625 | StateSet.VIEW_STATE_ENABLED); 1626 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1627 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1628 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1629 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1630 | StateSet.VIEW_STATE_ENABLED); 1631 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1632 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1633 | StateSet.VIEW_STATE_ENABLED); 1634 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1635 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1636 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1637 1638 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1639 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1640 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1641 PRESSED_SELECTED_STATE_SET = StateSet.get( 1642 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1643 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1644 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1645 | StateSet.VIEW_STATE_PRESSED); 1646 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1647 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1648 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1649 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1650 | StateSet.VIEW_STATE_PRESSED); 1651 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1652 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1653 | StateSet.VIEW_STATE_PRESSED); 1654 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1655 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1656 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1657 PRESSED_ENABLED_STATE_SET = StateSet.get( 1658 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1659 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1660 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1661 | StateSet.VIEW_STATE_PRESSED); 1662 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1663 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1664 | StateSet.VIEW_STATE_PRESSED); 1665 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1666 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1667 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1668 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 1669 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 1670 | StateSet.VIEW_STATE_PRESSED); 1671 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1672 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1673 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1674 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1675 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1676 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1677 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1678 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1679 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 1680 | StateSet.VIEW_STATE_PRESSED); 1681 } 1682 1683 /** 1684 * Accessibility event types that are dispatched for text population. 1685 */ 1686 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 1687 AccessibilityEvent.TYPE_VIEW_CLICKED 1688 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 1689 | AccessibilityEvent.TYPE_VIEW_SELECTED 1690 | AccessibilityEvent.TYPE_VIEW_FOCUSED 1691 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 1692 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 1693 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 1694 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 1695 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 1696 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 1697 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 1698 1699 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 1700 1701 static final int DEBUG_CORNERS_SIZE_DIP = 8; 1702 1703 /** 1704 * Temporary Rect currently for use in setBackground(). This will probably 1705 * be extended in the future to hold our own class with more than just 1706 * a Rect. :) 1707 */ 1708 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 1709 1710 /** 1711 * Map used to store views' tags. 1712 */ 1713 private SparseArray<Object> mKeyedTags; 1714 1715 /** 1716 * The next available accessibility id. 1717 */ 1718 private static int sNextAccessibilityViewId; 1719 1720 /** 1721 * The animation currently associated with this view. 1722 * @hide 1723 */ 1724 protected Animation mCurrentAnimation = null; 1725 1726 /** 1727 * Width as measured during measure pass. 1728 * {@hide} 1729 */ 1730 @ViewDebug.ExportedProperty(category = "measurement") 1731 int mMeasuredWidth; 1732 1733 /** 1734 * Height as measured during measure pass. 1735 * {@hide} 1736 */ 1737 @ViewDebug.ExportedProperty(category = "measurement") 1738 int mMeasuredHeight; 1739 1740 /** 1741 * Flag to indicate that this view was marked INVALIDATED, or had its display list 1742 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 1743 * its display list. This flag, used only when hw accelerated, allows us to clear the 1744 * flag while retaining this information until it's needed (at getDisplayList() time and 1745 * in drawChild(), when we decide to draw a view's children's display lists into our own). 1746 * 1747 * {@hide} 1748 */ 1749 boolean mRecreateDisplayList = false; 1750 1751 /** 1752 * The view's identifier. 1753 * {@hide} 1754 * 1755 * @see #setId(int) 1756 * @see #getId() 1757 */ 1758 @IdRes 1759 @ViewDebug.ExportedProperty(resolveId = true) 1760 int mID = NO_ID; 1761 1762 /** 1763 * The stable ID of this view for accessibility purposes. 1764 */ 1765 int mAccessibilityViewId = NO_ID; 1766 1767 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 1768 1769 SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent; 1770 1771 /** 1772 * The view's tag. 1773 * {@hide} 1774 * 1775 * @see #setTag(Object) 1776 * @see #getTag() 1777 */ 1778 protected Object mTag = null; 1779 1780 // for mPrivateFlags: 1781 /** {@hide} */ 1782 static final int PFLAG_WANTS_FOCUS = 0x00000001; 1783 /** {@hide} */ 1784 static final int PFLAG_FOCUSED = 0x00000002; 1785 /** {@hide} */ 1786 static final int PFLAG_SELECTED = 0x00000004; 1787 /** {@hide} */ 1788 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 1789 /** {@hide} */ 1790 static final int PFLAG_HAS_BOUNDS = 0x00000010; 1791 /** {@hide} */ 1792 static final int PFLAG_DRAWN = 0x00000020; 1793 /** 1794 * When this flag is set, this view is running an animation on behalf of its 1795 * children and should therefore not cancel invalidate requests, even if they 1796 * lie outside of this view's bounds. 1797 * 1798 * {@hide} 1799 */ 1800 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 1801 /** {@hide} */ 1802 static final int PFLAG_SKIP_DRAW = 0x00000080; 1803 /** {@hide} */ 1804 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 1805 /** {@hide} */ 1806 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 1807 /** {@hide} */ 1808 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 1809 /** {@hide} */ 1810 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 1811 /** {@hide} */ 1812 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 1813 1814 private static final int PFLAG_PRESSED = 0x00004000; 1815 1816 /** {@hide} */ 1817 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 1818 /** 1819 * Flag used to indicate that this view should be drawn once more (and only once 1820 * more) after its animation has completed. 1821 * {@hide} 1822 */ 1823 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 1824 1825 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 1826 1827 /** 1828 * Indicates that the View returned true when onSetAlpha() was called and that 1829 * the alpha must be restored. 1830 * {@hide} 1831 */ 1832 static final int PFLAG_ALPHA_SET = 0x00040000; 1833 1834 /** 1835 * Set by {@link #setScrollContainer(boolean)}. 1836 */ 1837 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 1838 1839 /** 1840 * Set by {@link #setScrollContainer(boolean)}. 1841 */ 1842 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 1843 1844 /** 1845 * View flag indicating whether this view was invalidated (fully or partially.) 1846 * 1847 * @hide 1848 */ 1849 static final int PFLAG_DIRTY = 0x00200000; 1850 1851 /** 1852 * View flag indicating whether this view was invalidated by an opaque 1853 * invalidate request. 1854 * 1855 * @hide 1856 */ 1857 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 1858 1859 /** 1860 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 1861 * 1862 * @hide 1863 */ 1864 static final int PFLAG_DIRTY_MASK = 0x00600000; 1865 1866 /** 1867 * Indicates whether the background is opaque. 1868 * 1869 * @hide 1870 */ 1871 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 1872 1873 /** 1874 * Indicates whether the scrollbars are opaque. 1875 * 1876 * @hide 1877 */ 1878 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 1879 1880 /** 1881 * Indicates whether the view is opaque. 1882 * 1883 * @hide 1884 */ 1885 static final int PFLAG_OPAQUE_MASK = 0x01800000; 1886 1887 /** 1888 * Indicates a prepressed state; 1889 * the short time between ACTION_DOWN and recognizing 1890 * a 'real' press. Prepressed is used to recognize quick taps 1891 * even when they are shorter than ViewConfiguration.getTapTimeout(). 1892 * 1893 * @hide 1894 */ 1895 private static final int PFLAG_PREPRESSED = 0x02000000; 1896 1897 /** 1898 * Indicates whether the view is temporarily detached. 1899 * 1900 * @hide 1901 */ 1902 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 1903 1904 /** 1905 * Indicates that we should awaken scroll bars once attached 1906 * 1907 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 1908 * during window attachment and it is no longer needed. Feel free to repurpose it. 1909 * 1910 * @hide 1911 */ 1912 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 1913 1914 /** 1915 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 1916 * @hide 1917 */ 1918 private static final int PFLAG_HOVERED = 0x10000000; 1919 1920 /** 1921 * no longer needed, should be reused 1922 */ 1923 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 1924 1925 /** {@hide} */ 1926 static final int PFLAG_ACTIVATED = 0x40000000; 1927 1928 /** 1929 * Indicates that this view was specifically invalidated, not just dirtied because some 1930 * child view was invalidated. The flag is used to determine when we need to recreate 1931 * a view's display list (as opposed to just returning a reference to its existing 1932 * display list). 1933 * 1934 * @hide 1935 */ 1936 static final int PFLAG_INVALIDATED = 0x80000000; 1937 1938 /** 1939 * Masks for mPrivateFlags2, as generated by dumpFlags(): 1940 * 1941 * |-------|-------|-------|-------| 1942 * 1 PFLAG2_DRAG_CAN_ACCEPT 1943 * 1 PFLAG2_DRAG_HOVERED 1944 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 1945 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 1946 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 1947 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 1948 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 1949 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 1950 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 1951 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 1952 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 1953 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 1954 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 1955 * 111 PFLAG2_TEXT_DIRECTION_MASK 1956 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 1957 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 1958 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 1959 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 1960 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 1961 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 1962 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 1963 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 1964 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 1965 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 1966 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 1967 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 1968 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 1969 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 1970 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 1971 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 1972 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 1973 * 1 PFLAG2_VIEW_QUICK_REJECTED 1974 * 1 PFLAG2_PADDING_RESOLVED 1975 * 1 PFLAG2_DRAWABLE_RESOLVED 1976 * 1 PFLAG2_HAS_TRANSIENT_STATE 1977 * |-------|-------|-------|-------| 1978 */ 1979 1980 /** 1981 * Indicates that this view has reported that it can accept the current drag's content. 1982 * Cleared when the drag operation concludes. 1983 * @hide 1984 */ 1985 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 1986 1987 /** 1988 * Indicates that this view is currently directly under the drag location in a 1989 * drag-and-drop operation involving content that it can accept. Cleared when 1990 * the drag exits the view, or when the drag operation concludes. 1991 * @hide 1992 */ 1993 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 1994 1995 /** @hide */ 1996 @IntDef({ 1997 LAYOUT_DIRECTION_LTR, 1998 LAYOUT_DIRECTION_RTL, 1999 LAYOUT_DIRECTION_INHERIT, 2000 LAYOUT_DIRECTION_LOCALE 2001 }) 2002 @Retention(RetentionPolicy.SOURCE) 2003 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2004 public @interface LayoutDir {} 2005 2006 /** @hide */ 2007 @IntDef({ 2008 LAYOUT_DIRECTION_LTR, 2009 LAYOUT_DIRECTION_RTL 2010 }) 2011 @Retention(RetentionPolicy.SOURCE) 2012 public @interface ResolvedLayoutDir {} 2013 2014 /** 2015 * A flag to indicate that the layout direction of this view has not been defined yet. 2016 * @hide 2017 */ 2018 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2019 2020 /** 2021 * Horizontal layout direction of this view is from Left to Right. 2022 * Use with {@link #setLayoutDirection}. 2023 */ 2024 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2025 2026 /** 2027 * Horizontal layout direction of this view is from Right to Left. 2028 * Use with {@link #setLayoutDirection}. 2029 */ 2030 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2031 2032 /** 2033 * Horizontal layout direction of this view is inherited from its parent. 2034 * Use with {@link #setLayoutDirection}. 2035 */ 2036 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2037 2038 /** 2039 * Horizontal layout direction of this view is from deduced from the default language 2040 * script for the locale. Use with {@link #setLayoutDirection}. 2041 */ 2042 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2043 2044 /** 2045 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2046 * @hide 2047 */ 2048 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2049 2050 /** 2051 * Mask for use with private flags indicating bits used for horizontal layout direction. 2052 * @hide 2053 */ 2054 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2055 2056 /** 2057 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2058 * right-to-left direction. 2059 * @hide 2060 */ 2061 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2062 2063 /** 2064 * Indicates whether the view horizontal layout direction has been resolved. 2065 * @hide 2066 */ 2067 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2068 2069 /** 2070 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2071 * @hide 2072 */ 2073 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2074 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2075 2076 /* 2077 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2078 * flag value. 2079 * @hide 2080 */ 2081 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2082 LAYOUT_DIRECTION_LTR, 2083 LAYOUT_DIRECTION_RTL, 2084 LAYOUT_DIRECTION_INHERIT, 2085 LAYOUT_DIRECTION_LOCALE 2086 }; 2087 2088 /** 2089 * Default horizontal layout direction. 2090 */ 2091 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2092 2093 /** 2094 * Default horizontal layout direction. 2095 * @hide 2096 */ 2097 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2098 2099 /** 2100 * Text direction is inherited through {@link ViewGroup} 2101 */ 2102 public static final int TEXT_DIRECTION_INHERIT = 0; 2103 2104 /** 2105 * Text direction is using "first strong algorithm". The first strong directional character 2106 * determines the paragraph direction. If there is no strong directional character, the 2107 * paragraph direction is the view's resolved layout direction. 2108 */ 2109 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2110 2111 /** 2112 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2113 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2114 * If there are neither, the paragraph direction is the view's resolved layout direction. 2115 */ 2116 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2117 2118 /** 2119 * Text direction is forced to LTR. 2120 */ 2121 public static final int TEXT_DIRECTION_LTR = 3; 2122 2123 /** 2124 * Text direction is forced to RTL. 2125 */ 2126 public static final int TEXT_DIRECTION_RTL = 4; 2127 2128 /** 2129 * Text direction is coming from the system Locale. 2130 */ 2131 public static final int TEXT_DIRECTION_LOCALE = 5; 2132 2133 /** 2134 * Text direction is using "first strong algorithm". The first strong directional character 2135 * determines the paragraph direction. If there is no strong directional character, the 2136 * paragraph direction is LTR. 2137 */ 2138 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2139 2140 /** 2141 * Text direction is using "first strong algorithm". The first strong directional character 2142 * determines the paragraph direction. If there is no strong directional character, the 2143 * paragraph direction is RTL. 2144 */ 2145 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2146 2147 /** 2148 * Default text direction is inherited 2149 */ 2150 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2151 2152 /** 2153 * Default resolved text direction 2154 * @hide 2155 */ 2156 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2157 2158 /** 2159 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2160 * @hide 2161 */ 2162 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2163 2164 /** 2165 * Mask for use with private flags indicating bits used for text direction. 2166 * @hide 2167 */ 2168 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2169 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2170 2171 /** 2172 * Array of text direction flags for mapping attribute "textDirection" to correct 2173 * flag value. 2174 * @hide 2175 */ 2176 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2177 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2178 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2179 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2180 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2181 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2182 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2183 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2184 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2185 }; 2186 2187 /** 2188 * Indicates whether the view text direction has been resolved. 2189 * @hide 2190 */ 2191 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2192 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2193 2194 /** 2195 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2196 * @hide 2197 */ 2198 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2199 2200 /** 2201 * Mask for use with private flags indicating bits used for resolved text direction. 2202 * @hide 2203 */ 2204 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2205 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2206 2207 /** 2208 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2209 * @hide 2210 */ 2211 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2212 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2213 2214 /** @hide */ 2215 @IntDef({ 2216 TEXT_ALIGNMENT_INHERIT, 2217 TEXT_ALIGNMENT_GRAVITY, 2218 TEXT_ALIGNMENT_CENTER, 2219 TEXT_ALIGNMENT_TEXT_START, 2220 TEXT_ALIGNMENT_TEXT_END, 2221 TEXT_ALIGNMENT_VIEW_START, 2222 TEXT_ALIGNMENT_VIEW_END 2223 }) 2224 @Retention(RetentionPolicy.SOURCE) 2225 public @interface TextAlignment {} 2226 2227 /** 2228 * Default text alignment. The text alignment of this View is inherited from its parent. 2229 * Use with {@link #setTextAlignment(int)} 2230 */ 2231 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2232 2233 /** 2234 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2235 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2236 * 2237 * Use with {@link #setTextAlignment(int)} 2238 */ 2239 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2240 2241 /** 2242 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2243 * 2244 * Use with {@link #setTextAlignment(int)} 2245 */ 2246 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2247 2248 /** 2249 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2250 * 2251 * Use with {@link #setTextAlignment(int)} 2252 */ 2253 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2254 2255 /** 2256 * Center the paragraph, e.g. ALIGN_CENTER. 2257 * 2258 * Use with {@link #setTextAlignment(int)} 2259 */ 2260 public static final int TEXT_ALIGNMENT_CENTER = 4; 2261 2262 /** 2263 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2264 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2265 * 2266 * Use with {@link #setTextAlignment(int)} 2267 */ 2268 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2269 2270 /** 2271 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2272 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2273 * 2274 * Use with {@link #setTextAlignment(int)} 2275 */ 2276 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2277 2278 /** 2279 * Default text alignment is inherited 2280 */ 2281 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2282 2283 /** 2284 * Default resolved text alignment 2285 * @hide 2286 */ 2287 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2288 2289 /** 2290 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2291 * @hide 2292 */ 2293 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2294 2295 /** 2296 * Mask for use with private flags indicating bits used for text alignment. 2297 * @hide 2298 */ 2299 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2300 2301 /** 2302 * Array of text direction flags for mapping attribute "textAlignment" to correct 2303 * flag value. 2304 * @hide 2305 */ 2306 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2307 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2308 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2309 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2310 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2311 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2312 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2313 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2314 }; 2315 2316 /** 2317 * Indicates whether the view text alignment has been resolved. 2318 * @hide 2319 */ 2320 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2321 2322 /** 2323 * Bit shift to get the resolved text alignment. 2324 * @hide 2325 */ 2326 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2327 2328 /** 2329 * Mask for use with private flags indicating bits used for text alignment. 2330 * @hide 2331 */ 2332 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2333 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2334 2335 /** 2336 * Indicates whether if the view text alignment has been resolved to gravity 2337 */ 2338 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2339 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2340 2341 // Accessiblity constants for mPrivateFlags2 2342 2343 /** 2344 * Shift for the bits in {@link #mPrivateFlags2} related to the 2345 * "importantForAccessibility" attribute. 2346 */ 2347 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2348 2349 /** 2350 * Automatically determine whether a view is important for accessibility. 2351 */ 2352 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2353 2354 /** 2355 * The view is important for accessibility. 2356 */ 2357 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2358 2359 /** 2360 * The view is not important for accessibility. 2361 */ 2362 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2363 2364 /** 2365 * The view is not important for accessibility, nor are any of its 2366 * descendant views. 2367 */ 2368 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2369 2370 /** 2371 * The default whether the view is important for accessibility. 2372 */ 2373 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2374 2375 /** 2376 * Mask for obtaining the bits which specify how to determine 2377 * whether a view is important for accessibility. 2378 */ 2379 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2380 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2381 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2382 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2383 2384 /** 2385 * Shift for the bits in {@link #mPrivateFlags2} related to the 2386 * "accessibilityLiveRegion" attribute. 2387 */ 2388 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2389 2390 /** 2391 * Live region mode specifying that accessibility services should not 2392 * automatically announce changes to this view. This is the default live 2393 * region mode for most views. 2394 * <p> 2395 * Use with {@link #setAccessibilityLiveRegion(int)}. 2396 */ 2397 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2398 2399 /** 2400 * Live region mode specifying that accessibility services should announce 2401 * changes to this view. 2402 * <p> 2403 * Use with {@link #setAccessibilityLiveRegion(int)}. 2404 */ 2405 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2406 2407 /** 2408 * Live region mode specifying that accessibility services should interrupt 2409 * ongoing speech to immediately announce changes to this view. 2410 * <p> 2411 * Use with {@link #setAccessibilityLiveRegion(int)}. 2412 */ 2413 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2414 2415 /** 2416 * The default whether the view is important for accessibility. 2417 */ 2418 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2419 2420 /** 2421 * Mask for obtaining the bits which specify a view's accessibility live 2422 * region mode. 2423 */ 2424 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2425 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2426 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2427 2428 /** 2429 * Flag indicating whether a view has accessibility focus. 2430 */ 2431 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2432 2433 /** 2434 * Flag whether the accessibility state of the subtree rooted at this view changed. 2435 */ 2436 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2437 2438 /** 2439 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2440 * is used to check whether later changes to the view's transform should invalidate the 2441 * view to force the quickReject test to run again. 2442 */ 2443 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2444 2445 /** 2446 * Flag indicating that start/end padding has been resolved into left/right padding 2447 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2448 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2449 * during measurement. In some special cases this is required such as when an adapter-based 2450 * view measures prospective children without attaching them to a window. 2451 */ 2452 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2453 2454 /** 2455 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2456 */ 2457 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2458 2459 /** 2460 * Indicates that the view is tracking some sort of transient state 2461 * that the app should not need to be aware of, but that the framework 2462 * should take special care to preserve. 2463 */ 2464 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2465 2466 /** 2467 * Group of bits indicating that RTL properties resolution is done. 2468 */ 2469 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2470 PFLAG2_TEXT_DIRECTION_RESOLVED | 2471 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2472 PFLAG2_PADDING_RESOLVED | 2473 PFLAG2_DRAWABLE_RESOLVED; 2474 2475 // There are a couple of flags left in mPrivateFlags2 2476 2477 /* End of masks for mPrivateFlags2 */ 2478 2479 /** 2480 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2481 * 2482 * |-------|-------|-------|-------| 2483 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2484 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2485 * 1 PFLAG3_IS_LAID_OUT 2486 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2487 * 1 PFLAG3_CALLED_SUPER 2488 * 1 PFLAG3_APPLYING_INSETS 2489 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2490 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2491 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2492 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2493 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2494 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2495 * 1 PFLAG3_SCROLL_INDICATOR_START 2496 * 1 PFLAG3_SCROLL_INDICATOR_END 2497 * 1 PFLAG3_ASSIST_BLOCKED 2498 * 1 PFLAG3_CLUSTER 2499 * 1 PFLAG3_SECTION 2500 * 1 PFLAG3_FINGER_DOWN 2501 * xxxxx * NO LONGER NEEDED, SHOULD BE REUSED * 2502 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2503 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2504 * 1 PFLAG3_TEMPORARY_DETACH 2505 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2506 * |-------|-------|-------|-------| 2507 */ 2508 2509 /** 2510 * Flag indicating that view has a transform animation set on it. This is used to track whether 2511 * an animation is cleared between successive frames, in order to tell the associated 2512 * DisplayList to clear its animation matrix. 2513 */ 2514 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2515 2516 /** 2517 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2518 * animation is cleared between successive frames, in order to tell the associated 2519 * DisplayList to restore its alpha value. 2520 */ 2521 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2522 2523 /** 2524 * Flag indicating that the view has been through at least one layout since it 2525 * was last attached to a window. 2526 */ 2527 static final int PFLAG3_IS_LAID_OUT = 0x4; 2528 2529 /** 2530 * Flag indicating that a call to measure() was skipped and should be done 2531 * instead when layout() is invoked. 2532 */ 2533 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2534 2535 /** 2536 * Flag indicating that an overridden method correctly called down to 2537 * the superclass implementation as required by the API spec. 2538 */ 2539 static final int PFLAG3_CALLED_SUPER = 0x10; 2540 2541 /** 2542 * Flag indicating that we're in the process of applying window insets. 2543 */ 2544 static final int PFLAG3_APPLYING_INSETS = 0x20; 2545 2546 /** 2547 * Flag indicating that we're in the process of fitting system windows using the old method. 2548 */ 2549 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2550 2551 /** 2552 * Flag indicating that nested scrolling is enabled for this view. 2553 * The view will optionally cooperate with views up its parent chain to allow for 2554 * integrated nested scrolling along the same axis. 2555 */ 2556 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2557 2558 /** 2559 * Flag indicating that the bottom scroll indicator should be displayed 2560 * when this view can scroll up. 2561 */ 2562 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2563 2564 /** 2565 * Flag indicating that the bottom scroll indicator should be displayed 2566 * when this view can scroll down. 2567 */ 2568 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2569 2570 /** 2571 * Flag indicating that the left scroll indicator should be displayed 2572 * when this view can scroll left. 2573 */ 2574 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2575 2576 /** 2577 * Flag indicating that the right scroll indicator should be displayed 2578 * when this view can scroll right. 2579 */ 2580 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2581 2582 /** 2583 * Flag indicating that the start scroll indicator should be displayed 2584 * when this view can scroll in the start direction. 2585 */ 2586 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2587 2588 /** 2589 * Flag indicating that the end scroll indicator should be displayed 2590 * when this view can scroll in the end direction. 2591 */ 2592 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2593 2594 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2595 2596 static final int SCROLL_INDICATORS_NONE = 0x0000; 2597 2598 /** 2599 * Mask for use with setFlags indicating bits used for indicating which 2600 * scroll indicators are enabled. 2601 */ 2602 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2603 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2604 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2605 | PFLAG3_SCROLL_INDICATOR_END; 2606 2607 /** 2608 * Left-shift required to translate between public scroll indicator flags 2609 * and internal PFLAGS3 flags. When used as a right-shift, translates 2610 * PFLAGS3 flags to public flags. 2611 */ 2612 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2613 2614 /** @hide */ 2615 @Retention(RetentionPolicy.SOURCE) 2616 @IntDef(flag = true, 2617 value = { 2618 SCROLL_INDICATOR_TOP, 2619 SCROLL_INDICATOR_BOTTOM, 2620 SCROLL_INDICATOR_LEFT, 2621 SCROLL_INDICATOR_RIGHT, 2622 SCROLL_INDICATOR_START, 2623 SCROLL_INDICATOR_END, 2624 }) 2625 public @interface ScrollIndicators {} 2626 2627 /** 2628 * Scroll indicator direction for the top edge of the view. 2629 * 2630 * @see #setScrollIndicators(int) 2631 * @see #setScrollIndicators(int, int) 2632 * @see #getScrollIndicators() 2633 */ 2634 public static final int SCROLL_INDICATOR_TOP = 2635 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2636 2637 /** 2638 * Scroll indicator direction for the bottom edge of the view. 2639 * 2640 * @see #setScrollIndicators(int) 2641 * @see #setScrollIndicators(int, int) 2642 * @see #getScrollIndicators() 2643 */ 2644 public static final int SCROLL_INDICATOR_BOTTOM = 2645 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2646 2647 /** 2648 * Scroll indicator direction for the left edge of the view. 2649 * 2650 * @see #setScrollIndicators(int) 2651 * @see #setScrollIndicators(int, int) 2652 * @see #getScrollIndicators() 2653 */ 2654 public static final int SCROLL_INDICATOR_LEFT = 2655 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2656 2657 /** 2658 * Scroll indicator direction for the right edge of the view. 2659 * 2660 * @see #setScrollIndicators(int) 2661 * @see #setScrollIndicators(int, int) 2662 * @see #getScrollIndicators() 2663 */ 2664 public static final int SCROLL_INDICATOR_RIGHT = 2665 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2666 2667 /** 2668 * Scroll indicator direction for the starting edge of the view. 2669 * <p> 2670 * Resolved according to the view's layout direction, see 2671 * {@link #getLayoutDirection()} for more information. 2672 * 2673 * @see #setScrollIndicators(int) 2674 * @see #setScrollIndicators(int, int) 2675 * @see #getScrollIndicators() 2676 */ 2677 public static final int SCROLL_INDICATOR_START = 2678 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2679 2680 /** 2681 * Scroll indicator direction for the ending edge of the view. 2682 * <p> 2683 * Resolved according to the view's layout direction, see 2684 * {@link #getLayoutDirection()} for more information. 2685 * 2686 * @see #setScrollIndicators(int) 2687 * @see #setScrollIndicators(int, int) 2688 * @see #getScrollIndicators() 2689 */ 2690 public static final int SCROLL_INDICATOR_END = 2691 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2692 2693 /** 2694 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 2695 * into this view.<p> 2696 */ 2697 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 2698 2699 /** 2700 * Flag indicating that the view is a root of a keyboard navigation cluster. 2701 * 2702 * @see #isKeyboardNavigationCluster() 2703 * @see #setKeyboardNavigationCluster(boolean) 2704 */ 2705 private static final int PFLAG3_CLUSTER = 0x8000; 2706 2707 /** 2708 * Flag indicating that the view is a root of a keyboard navigation section. 2709 * 2710 * @see #isKeyboardNavigationSection() 2711 * @see #setKeyboardNavigationSection(boolean) 2712 */ 2713 private static final int PFLAG3_SECTION = 0x10000; 2714 2715 /** 2716 * Indicates that the user is currently touching the screen. 2717 * Currently used for the tooltip positioning only. 2718 */ 2719 private static final int PFLAG3_FINGER_DOWN = 0x20000; 2720 2721 /** 2722 * Whether this view has rendered elements that overlap (see {@link 2723 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 2724 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 2725 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 2726 * determined by whatever {@link #hasOverlappingRendering()} returns. 2727 */ 2728 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 2729 2730 /** 2731 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 2732 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 2733 */ 2734 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 2735 2736 /** 2737 * Flag indicating that the view is temporarily detached from the parent view. 2738 * 2739 * @see #onStartTemporaryDetach() 2740 * @see #onFinishTemporaryDetach() 2741 */ 2742 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 2743 2744 /** 2745 * Flag indicating that the view does not wish to be revealed within its parent 2746 * hierarchy when it gains focus. Expressed in the negative since the historical 2747 * default behavior is to reveal on focus; this flag suppresses that behavior. 2748 * 2749 * @see #setRevealOnFocusHint(boolean) 2750 * @see #getRevealOnFocusHint() 2751 */ 2752 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 2753 2754 /* End of masks for mPrivateFlags3 */ 2755 2756 /** 2757 * Always allow a user to over-scroll this view, provided it is a 2758 * view that can scroll. 2759 * 2760 * @see #getOverScrollMode() 2761 * @see #setOverScrollMode(int) 2762 */ 2763 public static final int OVER_SCROLL_ALWAYS = 0; 2764 2765 /** 2766 * Allow a user to over-scroll this view only if the content is large 2767 * enough to meaningfully scroll, provided it is a view that can scroll. 2768 * 2769 * @see #getOverScrollMode() 2770 * @see #setOverScrollMode(int) 2771 */ 2772 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 2773 2774 /** 2775 * Never allow a user to over-scroll this view. 2776 * 2777 * @see #getOverScrollMode() 2778 * @see #setOverScrollMode(int) 2779 */ 2780 public static final int OVER_SCROLL_NEVER = 2; 2781 2782 /** 2783 * Special constant for {@link #setSystemUiVisibility(int)}: View has 2784 * requested the system UI (status bar) to be visible (the default). 2785 * 2786 * @see #setSystemUiVisibility(int) 2787 */ 2788 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 2789 2790 /** 2791 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 2792 * system UI to enter an unobtrusive "low profile" mode. 2793 * 2794 * <p>This is for use in games, book readers, video players, or any other 2795 * "immersive" application where the usual system chrome is deemed too distracting. 2796 * 2797 * <p>In low profile mode, the status bar and/or navigation icons may dim. 2798 * 2799 * @see #setSystemUiVisibility(int) 2800 */ 2801 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 2802 2803 /** 2804 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 2805 * system navigation be temporarily hidden. 2806 * 2807 * <p>This is an even less obtrusive state than that called for by 2808 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 2809 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 2810 * those to disappear. This is useful (in conjunction with the 2811 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 2812 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 2813 * window flags) for displaying content using every last pixel on the display. 2814 * 2815 * <p>There is a limitation: because navigation controls are so important, the least user 2816 * interaction will cause them to reappear immediately. When this happens, both 2817 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 2818 * so that both elements reappear at the same time. 2819 * 2820 * @see #setSystemUiVisibility(int) 2821 */ 2822 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 2823 2824 /** 2825 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 2826 * into the normal fullscreen mode so that its content can take over the screen 2827 * while still allowing the user to interact with the application. 2828 * 2829 * <p>This has the same visual effect as 2830 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 2831 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 2832 * meaning that non-critical screen decorations (such as the status bar) will be 2833 * hidden while the user is in the View's window, focusing the experience on 2834 * that content. Unlike the window flag, if you are using ActionBar in 2835 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2836 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 2837 * hide the action bar. 2838 * 2839 * <p>This approach to going fullscreen is best used over the window flag when 2840 * it is a transient state -- that is, the application does this at certain 2841 * points in its user interaction where it wants to allow the user to focus 2842 * on content, but not as a continuous state. For situations where the application 2843 * would like to simply stay full screen the entire time (such as a game that 2844 * wants to take over the screen), the 2845 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 2846 * is usually a better approach. The state set here will be removed by the system 2847 * in various situations (such as the user moving to another application) like 2848 * the other system UI states. 2849 * 2850 * <p>When using this flag, the application should provide some easy facility 2851 * for the user to go out of it. A common example would be in an e-book 2852 * reader, where tapping on the screen brings back whatever screen and UI 2853 * decorations that had been hidden while the user was immersed in reading 2854 * the book. 2855 * 2856 * @see #setSystemUiVisibility(int) 2857 */ 2858 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 2859 2860 /** 2861 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 2862 * flags, we would like a stable view of the content insets given to 2863 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 2864 * will always represent the worst case that the application can expect 2865 * as a continuous state. In the stock Android UI this is the space for 2866 * the system bar, nav bar, and status bar, but not more transient elements 2867 * such as an input method. 2868 * 2869 * The stable layout your UI sees is based on the system UI modes you can 2870 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 2871 * then you will get a stable layout for changes of the 2872 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 2873 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 2874 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 2875 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 2876 * with a stable layout. (Note that you should avoid using 2877 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 2878 * 2879 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 2880 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 2881 * then a hidden status bar will be considered a "stable" state for purposes 2882 * here. This allows your UI to continually hide the status bar, while still 2883 * using the system UI flags to hide the action bar while still retaining 2884 * a stable layout. Note that changing the window fullscreen flag will never 2885 * provide a stable layout for a clean transition. 2886 * 2887 * <p>If you are using ActionBar in 2888 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2889 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 2890 * insets it adds to those given to the application. 2891 */ 2892 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 2893 2894 /** 2895 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2896 * to be laid out as if it has requested 2897 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 2898 * allows it to avoid artifacts when switching in and out of that mode, at 2899 * the expense that some of its user interface may be covered by screen 2900 * decorations when they are shown. You can perform layout of your inner 2901 * UI elements to account for the navigation system UI through the 2902 * {@link #fitSystemWindows(Rect)} method. 2903 */ 2904 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 2905 2906 /** 2907 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2908 * to be laid out as if it has requested 2909 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 2910 * allows it to avoid artifacts when switching in and out of that mode, at 2911 * the expense that some of its user interface may be covered by screen 2912 * decorations when they are shown. You can perform layout of your inner 2913 * UI elements to account for non-fullscreen system UI through the 2914 * {@link #fitSystemWindows(Rect)} method. 2915 */ 2916 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 2917 2918 /** 2919 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2920 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 2921 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 2922 * user interaction. 2923 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 2924 * has an effect when used in combination with that flag.</p> 2925 */ 2926 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 2927 2928 /** 2929 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2930 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 2931 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 2932 * experience while also hiding the system bars. If this flag is not set, 2933 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 2934 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 2935 * if the user swipes from the top of the screen. 2936 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 2937 * system gestures, such as swiping from the top of the screen. These transient system bars 2938 * will overlay app’s content, may have some degree of transparency, and will automatically 2939 * hide after a short timeout. 2940 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 2941 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 2942 * with one or both of those flags.</p> 2943 */ 2944 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 2945 2946 /** 2947 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 2948 * is compatible with light status bar backgrounds. 2949 * 2950 * <p>For this to take effect, the window must request 2951 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2952 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2953 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 2954 * FLAG_TRANSLUCENT_STATUS}. 2955 * 2956 * @see android.R.attr#windowLightStatusBar 2957 */ 2958 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 2959 2960 /** 2961 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 2962 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 2963 */ 2964 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 2965 2966 /** 2967 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 2968 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 2969 */ 2970 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 2971 2972 /** 2973 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 2974 * that is compatible with light navigation bar backgrounds. 2975 * 2976 * <p>For this to take effect, the window must request 2977 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2978 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2979 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 2980 * FLAG_TRANSLUCENT_NAVIGATION}. 2981 */ 2982 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 2983 2984 /** 2985 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 2986 */ 2987 @Deprecated 2988 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 2989 2990 /** 2991 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 2992 */ 2993 @Deprecated 2994 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 2995 2996 /** 2997 * @hide 2998 * 2999 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3000 * out of the public fields to keep the undefined bits out of the developer's way. 3001 * 3002 * Flag to make the status bar not expandable. Unless you also 3003 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3004 */ 3005 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3006 3007 /** 3008 * @hide 3009 * 3010 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3011 * out of the public fields to keep the undefined bits out of the developer's way. 3012 * 3013 * Flag to hide notification icons and scrolling ticker text. 3014 */ 3015 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3016 3017 /** 3018 * @hide 3019 * 3020 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3021 * out of the public fields to keep the undefined bits out of the developer's way. 3022 * 3023 * Flag to disable incoming notification alerts. This will not block 3024 * icons, but it will block sound, vibrating and other visual or aural notifications. 3025 */ 3026 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3027 3028 /** 3029 * @hide 3030 * 3031 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3032 * out of the public fields to keep the undefined bits out of the developer's way. 3033 * 3034 * Flag to hide only the scrolling ticker. Note that 3035 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3036 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3037 */ 3038 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3039 3040 /** 3041 * @hide 3042 * 3043 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3044 * out of the public fields to keep the undefined bits out of the developer's way. 3045 * 3046 * Flag to hide the center system info area. 3047 */ 3048 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3049 3050 /** 3051 * @hide 3052 * 3053 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3054 * out of the public fields to keep the undefined bits out of the developer's way. 3055 * 3056 * Flag to hide only the home button. Don't use this 3057 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3058 */ 3059 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3060 3061 /** 3062 * @hide 3063 * 3064 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3065 * out of the public fields to keep the undefined bits out of the developer's way. 3066 * 3067 * Flag to hide only the back button. Don't use this 3068 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3069 */ 3070 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3071 3072 /** 3073 * @hide 3074 * 3075 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3076 * out of the public fields to keep the undefined bits out of the developer's way. 3077 * 3078 * Flag to hide only the clock. You might use this if your activity has 3079 * its own clock making the status bar's clock redundant. 3080 */ 3081 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3082 3083 /** 3084 * @hide 3085 * 3086 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3087 * out of the public fields to keep the undefined bits out of the developer's way. 3088 * 3089 * Flag to hide only the recent apps button. Don't use this 3090 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3091 */ 3092 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3093 3094 /** 3095 * @hide 3096 * 3097 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3098 * out of the public fields to keep the undefined bits out of the developer's way. 3099 * 3100 * Flag to disable the global search gesture. Don't use this 3101 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3102 */ 3103 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3104 3105 /** 3106 * @hide 3107 * 3108 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3109 * out of the public fields to keep the undefined bits out of the developer's way. 3110 * 3111 * Flag to specify that the status bar is displayed in transient mode. 3112 */ 3113 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3114 3115 /** 3116 * @hide 3117 * 3118 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3119 * out of the public fields to keep the undefined bits out of the developer's way. 3120 * 3121 * Flag to specify that the navigation bar is displayed in transient mode. 3122 */ 3123 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3124 3125 /** 3126 * @hide 3127 * 3128 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3129 * out of the public fields to keep the undefined bits out of the developer's way. 3130 * 3131 * Flag to specify that the hidden status bar would like to be shown. 3132 */ 3133 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3134 3135 /** 3136 * @hide 3137 * 3138 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3139 * out of the public fields to keep the undefined bits out of the developer's way. 3140 * 3141 * Flag to specify that the hidden navigation bar would like to be shown. 3142 */ 3143 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3144 3145 /** 3146 * @hide 3147 * 3148 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3149 * out of the public fields to keep the undefined bits out of the developer's way. 3150 * 3151 * Flag to specify that the status bar is displayed in translucent mode. 3152 */ 3153 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3154 3155 /** 3156 * @hide 3157 * 3158 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3159 * out of the public fields to keep the undefined bits out of the developer's way. 3160 * 3161 * Flag to specify that the navigation bar is displayed in translucent mode. 3162 */ 3163 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3164 3165 /** 3166 * @hide 3167 * 3168 * Makes navigation bar transparent (but not the status bar). 3169 */ 3170 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3171 3172 /** 3173 * @hide 3174 * 3175 * Makes status bar transparent (but not the navigation bar). 3176 */ 3177 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3178 3179 /** 3180 * @hide 3181 * 3182 * Makes both status bar and navigation bar transparent. 3183 */ 3184 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3185 | STATUS_BAR_TRANSPARENT; 3186 3187 /** 3188 * @hide 3189 */ 3190 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3191 3192 /** 3193 * These are the system UI flags that can be cleared by events outside 3194 * of an application. Currently this is just the ability to tap on the 3195 * screen while hiding the navigation bar to have it return. 3196 * @hide 3197 */ 3198 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3199 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3200 | SYSTEM_UI_FLAG_FULLSCREEN; 3201 3202 /** 3203 * Flags that can impact the layout in relation to system UI. 3204 */ 3205 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3206 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3207 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3208 3209 /** @hide */ 3210 @IntDef(flag = true, 3211 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3212 @Retention(RetentionPolicy.SOURCE) 3213 public @interface FindViewFlags {} 3214 3215 /** 3216 * Find views that render the specified text. 3217 * 3218 * @see #findViewsWithText(ArrayList, CharSequence, int) 3219 */ 3220 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3221 3222 /** 3223 * Find find views that contain the specified content description. 3224 * 3225 * @see #findViewsWithText(ArrayList, CharSequence, int) 3226 */ 3227 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3228 3229 /** 3230 * Find views that contain {@link AccessibilityNodeProvider}. Such 3231 * a View is a root of virtual view hierarchy and may contain the searched 3232 * text. If this flag is set Views with providers are automatically 3233 * added and it is a responsibility of the client to call the APIs of 3234 * the provider to determine whether the virtual tree rooted at this View 3235 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3236 * representing the virtual views with this text. 3237 * 3238 * @see #findViewsWithText(ArrayList, CharSequence, int) 3239 * 3240 * @hide 3241 */ 3242 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3243 3244 /** 3245 * The undefined cursor position. 3246 * 3247 * @hide 3248 */ 3249 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3250 3251 /** 3252 * Indicates that the screen has changed state and is now off. 3253 * 3254 * @see #onScreenStateChanged(int) 3255 */ 3256 public static final int SCREEN_STATE_OFF = 0x0; 3257 3258 /** 3259 * Indicates that the screen has changed state and is now on. 3260 * 3261 * @see #onScreenStateChanged(int) 3262 */ 3263 public static final int SCREEN_STATE_ON = 0x1; 3264 3265 /** 3266 * Indicates no axis of view scrolling. 3267 */ 3268 public static final int SCROLL_AXIS_NONE = 0; 3269 3270 /** 3271 * Indicates scrolling along the horizontal axis. 3272 */ 3273 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3274 3275 /** 3276 * Indicates scrolling along the vertical axis. 3277 */ 3278 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3279 3280 /** 3281 * Controls the over-scroll mode for this view. 3282 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3283 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3284 * and {@link #OVER_SCROLL_NEVER}. 3285 */ 3286 private int mOverScrollMode; 3287 3288 /** 3289 * The parent this view is attached to. 3290 * {@hide} 3291 * 3292 * @see #getParent() 3293 */ 3294 protected ViewParent mParent; 3295 3296 /** 3297 * {@hide} 3298 */ 3299 AttachInfo mAttachInfo; 3300 3301 /** 3302 * {@hide} 3303 */ 3304 @ViewDebug.ExportedProperty(flagMapping = { 3305 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3306 name = "FORCE_LAYOUT"), 3307 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3308 name = "LAYOUT_REQUIRED"), 3309 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3310 name = "DRAWING_CACHE_INVALID", outputIf = false), 3311 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3312 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3313 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3314 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3315 }, formatToHexString = true) 3316 int mPrivateFlags; 3317 int mPrivateFlags2; 3318 int mPrivateFlags3; 3319 3320 /** 3321 * This view's request for the visibility of the status bar. 3322 * @hide 3323 */ 3324 @ViewDebug.ExportedProperty(flagMapping = { 3325 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3326 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3327 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3328 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3329 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3330 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3331 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3332 equals = SYSTEM_UI_FLAG_VISIBLE, 3333 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3334 }, formatToHexString = true) 3335 int mSystemUiVisibility; 3336 3337 /** 3338 * Reference count for transient state. 3339 * @see #setHasTransientState(boolean) 3340 */ 3341 int mTransientStateCount = 0; 3342 3343 /** 3344 * Count of how many windows this view has been attached to. 3345 */ 3346 int mWindowAttachCount; 3347 3348 /** 3349 * The layout parameters associated with this view and used by the parent 3350 * {@link android.view.ViewGroup} to determine how this view should be 3351 * laid out. 3352 * {@hide} 3353 */ 3354 protected ViewGroup.LayoutParams mLayoutParams; 3355 3356 /** 3357 * The view flags hold various views states. 3358 * {@hide} 3359 */ 3360 @ViewDebug.ExportedProperty(formatToHexString = true) 3361 int mViewFlags; 3362 3363 static class TransformationInfo { 3364 /** 3365 * The transform matrix for the View. This transform is calculated internally 3366 * based on the translation, rotation, and scale properties. 3367 * 3368 * Do *not* use this variable directly; instead call getMatrix(), which will 3369 * load the value from the View's RenderNode. 3370 */ 3371 private final Matrix mMatrix = new Matrix(); 3372 3373 /** 3374 * The inverse transform matrix for the View. This transform is calculated 3375 * internally based on the translation, rotation, and scale properties. 3376 * 3377 * Do *not* use this variable directly; instead call getInverseMatrix(), 3378 * which will load the value from the View's RenderNode. 3379 */ 3380 private Matrix mInverseMatrix; 3381 3382 /** 3383 * The opacity of the View. This is a value from 0 to 1, where 0 means 3384 * completely transparent and 1 means completely opaque. 3385 */ 3386 @ViewDebug.ExportedProperty 3387 float mAlpha = 1f; 3388 3389 /** 3390 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3391 * property only used by transitions, which is composited with the other alpha 3392 * values to calculate the final visual alpha value. 3393 */ 3394 float mTransitionAlpha = 1f; 3395 } 3396 3397 TransformationInfo mTransformationInfo; 3398 3399 /** 3400 * Current clip bounds. to which all drawing of this view are constrained. 3401 */ 3402 Rect mClipBounds = null; 3403 3404 private boolean mLastIsOpaque; 3405 3406 /** 3407 * The distance in pixels from the left edge of this view's parent 3408 * to the left edge of this view. 3409 * {@hide} 3410 */ 3411 @ViewDebug.ExportedProperty(category = "layout") 3412 protected int mLeft; 3413 /** 3414 * The distance in pixels from the left edge of this view's parent 3415 * to the right edge of this view. 3416 * {@hide} 3417 */ 3418 @ViewDebug.ExportedProperty(category = "layout") 3419 protected int mRight; 3420 /** 3421 * The distance in pixels from the top edge of this view's parent 3422 * to the top edge of this view. 3423 * {@hide} 3424 */ 3425 @ViewDebug.ExportedProperty(category = "layout") 3426 protected int mTop; 3427 /** 3428 * The distance in pixels from the top edge of this view's parent 3429 * to the bottom edge of this view. 3430 * {@hide} 3431 */ 3432 @ViewDebug.ExportedProperty(category = "layout") 3433 protected int mBottom; 3434 3435 /** 3436 * The offset, in pixels, by which the content of this view is scrolled 3437 * horizontally. 3438 * {@hide} 3439 */ 3440 @ViewDebug.ExportedProperty(category = "scrolling") 3441 protected int mScrollX; 3442 /** 3443 * The offset, in pixels, by which the content of this view is scrolled 3444 * vertically. 3445 * {@hide} 3446 */ 3447 @ViewDebug.ExportedProperty(category = "scrolling") 3448 protected int mScrollY; 3449 3450 /** 3451 * The left padding in pixels, that is the distance in pixels between the 3452 * left edge of this view and the left edge of its content. 3453 * {@hide} 3454 */ 3455 @ViewDebug.ExportedProperty(category = "padding") 3456 protected int mPaddingLeft = 0; 3457 /** 3458 * The right padding in pixels, that is the distance in pixels between the 3459 * right edge of this view and the right edge of its content. 3460 * {@hide} 3461 */ 3462 @ViewDebug.ExportedProperty(category = "padding") 3463 protected int mPaddingRight = 0; 3464 /** 3465 * The top padding in pixels, that is the distance in pixels between the 3466 * top edge of this view and the top edge of its content. 3467 * {@hide} 3468 */ 3469 @ViewDebug.ExportedProperty(category = "padding") 3470 protected int mPaddingTop; 3471 /** 3472 * The bottom padding in pixels, that is the distance in pixels between the 3473 * bottom edge of this view and the bottom edge of its content. 3474 * {@hide} 3475 */ 3476 @ViewDebug.ExportedProperty(category = "padding") 3477 protected int mPaddingBottom; 3478 3479 /** 3480 * The layout insets in pixels, that is the distance in pixels between the 3481 * visible edges of this view its bounds. 3482 */ 3483 private Insets mLayoutInsets; 3484 3485 /** 3486 * Briefly describes the view and is primarily used for accessibility support. 3487 */ 3488 private CharSequence mContentDescription; 3489 3490 /** 3491 * Specifies the id of a view for which this view serves as a label for 3492 * accessibility purposes. 3493 */ 3494 private int mLabelForId = View.NO_ID; 3495 3496 /** 3497 * Predicate for matching labeled view id with its label for 3498 * accessibility purposes. 3499 */ 3500 private MatchLabelForPredicate mMatchLabelForPredicate; 3501 3502 /** 3503 * Specifies a view before which this one is visited in accessibility traversal. 3504 */ 3505 private int mAccessibilityTraversalBeforeId = NO_ID; 3506 3507 /** 3508 * Specifies a view after which this one is visited in accessibility traversal. 3509 */ 3510 private int mAccessibilityTraversalAfterId = NO_ID; 3511 3512 /** 3513 * Predicate for matching a view by its id. 3514 */ 3515 private MatchIdPredicate mMatchIdPredicate; 3516 3517 /** 3518 * Cache the paddingRight set by the user to append to the scrollbar's size. 3519 * 3520 * @hide 3521 */ 3522 @ViewDebug.ExportedProperty(category = "padding") 3523 protected int mUserPaddingRight; 3524 3525 /** 3526 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3527 * 3528 * @hide 3529 */ 3530 @ViewDebug.ExportedProperty(category = "padding") 3531 protected int mUserPaddingBottom; 3532 3533 /** 3534 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3535 * 3536 * @hide 3537 */ 3538 @ViewDebug.ExportedProperty(category = "padding") 3539 protected int mUserPaddingLeft; 3540 3541 /** 3542 * Cache the paddingStart set by the user to append to the scrollbar's size. 3543 * 3544 */ 3545 @ViewDebug.ExportedProperty(category = "padding") 3546 int mUserPaddingStart; 3547 3548 /** 3549 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3550 * 3551 */ 3552 @ViewDebug.ExportedProperty(category = "padding") 3553 int mUserPaddingEnd; 3554 3555 /** 3556 * Cache initial left padding. 3557 * 3558 * @hide 3559 */ 3560 int mUserPaddingLeftInitial; 3561 3562 /** 3563 * Cache initial right padding. 3564 * 3565 * @hide 3566 */ 3567 int mUserPaddingRightInitial; 3568 3569 /** 3570 * Default undefined padding 3571 */ 3572 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3573 3574 /** 3575 * Cache if a left padding has been defined 3576 */ 3577 private boolean mLeftPaddingDefined = false; 3578 3579 /** 3580 * Cache if a right padding has been defined 3581 */ 3582 private boolean mRightPaddingDefined = false; 3583 3584 /** 3585 * @hide 3586 */ 3587 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3588 /** 3589 * @hide 3590 */ 3591 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3592 3593 private LongSparseLongArray mMeasureCache; 3594 3595 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3596 private Drawable mBackground; 3597 private TintInfo mBackgroundTint; 3598 3599 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3600 private ForegroundInfo mForegroundInfo; 3601 3602 private Drawable mScrollIndicatorDrawable; 3603 3604 /** 3605 * RenderNode used for backgrounds. 3606 * <p> 3607 * When non-null and valid, this is expected to contain an up-to-date copy 3608 * of the background drawable. It is cleared on temporary detach, and reset 3609 * on cleanup. 3610 */ 3611 private RenderNode mBackgroundRenderNode; 3612 3613 private int mBackgroundResource; 3614 private boolean mBackgroundSizeChanged; 3615 3616 private String mTransitionName; 3617 3618 static class TintInfo { 3619 ColorStateList mTintList; 3620 PorterDuff.Mode mTintMode; 3621 boolean mHasTintMode; 3622 boolean mHasTintList; 3623 } 3624 3625 private static class ForegroundInfo { 3626 private Drawable mDrawable; 3627 private TintInfo mTintInfo; 3628 private int mGravity = Gravity.FILL; 3629 private boolean mInsidePadding = true; 3630 private boolean mBoundsChanged = true; 3631 private final Rect mSelfBounds = new Rect(); 3632 private final Rect mOverlayBounds = new Rect(); 3633 } 3634 3635 static class ListenerInfo { 3636 /** 3637 * Listener used to dispatch focus change events. 3638 * This field should be made private, so it is hidden from the SDK. 3639 * {@hide} 3640 */ 3641 protected OnFocusChangeListener mOnFocusChangeListener; 3642 3643 /** 3644 * Listeners for layout change events. 3645 */ 3646 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 3647 3648 protected OnScrollChangeListener mOnScrollChangeListener; 3649 3650 /** 3651 * Listeners for attach events. 3652 */ 3653 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 3654 3655 /** 3656 * Listener used to dispatch click events. 3657 * This field should be made private, so it is hidden from the SDK. 3658 * {@hide} 3659 */ 3660 public OnClickListener mOnClickListener; 3661 3662 /** 3663 * Listener used to dispatch long click events. 3664 * This field should be made private, so it is hidden from the SDK. 3665 * {@hide} 3666 */ 3667 protected OnLongClickListener mOnLongClickListener; 3668 3669 /** 3670 * Listener used to dispatch context click events. This field should be made private, so it 3671 * is hidden from the SDK. 3672 * {@hide} 3673 */ 3674 protected OnContextClickListener mOnContextClickListener; 3675 3676 /** 3677 * Listener used to build the context menu. 3678 * This field should be made private, so it is hidden from the SDK. 3679 * {@hide} 3680 */ 3681 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 3682 3683 private OnKeyListener mOnKeyListener; 3684 3685 private OnTouchListener mOnTouchListener; 3686 3687 private OnHoverListener mOnHoverListener; 3688 3689 private OnGenericMotionListener mOnGenericMotionListener; 3690 3691 private OnDragListener mOnDragListener; 3692 3693 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 3694 3695 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 3696 } 3697 3698 ListenerInfo mListenerInfo; 3699 3700 private static class TooltipInfo { 3701 /** 3702 * Text to be displayed in a tooltip popup. 3703 */ 3704 @Nullable 3705 CharSequence mTooltip; 3706 3707 /** 3708 * View-relative position of the tooltip anchor point. 3709 */ 3710 int mAnchorX; 3711 int mAnchorY; 3712 3713 /** 3714 * The tooltip popup. 3715 */ 3716 @Nullable 3717 TooltipPopup mTooltipPopup; 3718 3719 /** 3720 * Set to true if the tooltip was shown as a result of a long click. 3721 */ 3722 boolean mTooltipFromLongClick; 3723 3724 /** 3725 * Keep these Runnables so that they can be used to reschedule. 3726 */ 3727 Runnable mShowTooltipRunnable; 3728 Runnable mHideTooltipRunnable; 3729 } 3730 3731 TooltipInfo mTooltipInfo; 3732 3733 // Temporary values used to hold (x,y) coordinates when delegating from the 3734 // two-arg performLongClick() method to the legacy no-arg version. 3735 private float mLongClickX = Float.NaN; 3736 private float mLongClickY = Float.NaN; 3737 3738 /** 3739 * The application environment this view lives in. 3740 * This field should be made private, so it is hidden from the SDK. 3741 * {@hide} 3742 */ 3743 @ViewDebug.ExportedProperty(deepExport = true) 3744 protected Context mContext; 3745 3746 private final Resources mResources; 3747 3748 private ScrollabilityCache mScrollCache; 3749 3750 private int[] mDrawableState = null; 3751 3752 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 3753 3754 /** 3755 * Animator that automatically runs based on state changes. 3756 */ 3757 private StateListAnimator mStateListAnimator; 3758 3759 /** 3760 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 3761 * the user may specify which view to go to next. 3762 */ 3763 private int mNextFocusLeftId = View.NO_ID; 3764 3765 /** 3766 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 3767 * the user may specify which view to go to next. 3768 */ 3769 private int mNextFocusRightId = View.NO_ID; 3770 3771 /** 3772 * When this view has focus and the next focus is {@link #FOCUS_UP}, 3773 * the user may specify which view to go to next. 3774 */ 3775 private int mNextFocusUpId = View.NO_ID; 3776 3777 /** 3778 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 3779 * the user may specify which view to go to next. 3780 */ 3781 private int mNextFocusDownId = View.NO_ID; 3782 3783 /** 3784 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 3785 * the user may specify which view to go to next. 3786 */ 3787 int mNextFocusForwardId = View.NO_ID; 3788 3789 /** 3790 * User-specified next keyboard navigation cluster. 3791 */ 3792 int mNextClusterForwardId = View.NO_ID; 3793 3794 /** 3795 * User-specified next keyboard navigation section. 3796 */ 3797 int mNextSectionForwardId = View.NO_ID; 3798 3799 private CheckForLongPress mPendingCheckForLongPress; 3800 private CheckForTap mPendingCheckForTap = null; 3801 private PerformClick mPerformClick; 3802 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 3803 3804 private UnsetPressedState mUnsetPressedState; 3805 3806 /** 3807 * Whether the long press's action has been invoked. The tap's action is invoked on the 3808 * up event while a long press is invoked as soon as the long press duration is reached, so 3809 * a long press could be performed before the tap is checked, in which case the tap's action 3810 * should not be invoked. 3811 */ 3812 private boolean mHasPerformedLongPress; 3813 3814 /** 3815 * Whether a context click button is currently pressed down. This is true when the stylus is 3816 * touching the screen and the primary button has been pressed, or if a mouse's right button is 3817 * pressed. This is false once the button is released or if the stylus has been lifted. 3818 */ 3819 private boolean mInContextButtonPress; 3820 3821 /** 3822 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 3823 * true after a stylus button press has occured, when the next up event should not be recognized 3824 * as a tap. 3825 */ 3826 private boolean mIgnoreNextUpEvent; 3827 3828 /** 3829 * The minimum height of the view. We'll try our best to have the height 3830 * of this view to at least this amount. 3831 */ 3832 @ViewDebug.ExportedProperty(category = "measurement") 3833 private int mMinHeight; 3834 3835 /** 3836 * The minimum width of the view. We'll try our best to have the width 3837 * of this view to at least this amount. 3838 */ 3839 @ViewDebug.ExportedProperty(category = "measurement") 3840 private int mMinWidth; 3841 3842 /** 3843 * The delegate to handle touch events that are physically in this view 3844 * but should be handled by another view. 3845 */ 3846 private TouchDelegate mTouchDelegate = null; 3847 3848 /** 3849 * Solid color to use as a background when creating the drawing cache. Enables 3850 * the cache to use 16 bit bitmaps instead of 32 bit. 3851 */ 3852 private int mDrawingCacheBackgroundColor = 0; 3853 3854 /** 3855 * Special tree observer used when mAttachInfo is null. 3856 */ 3857 private ViewTreeObserver mFloatingTreeObserver; 3858 3859 /** 3860 * Cache the touch slop from the context that created the view. 3861 */ 3862 private int mTouchSlop; 3863 3864 /** 3865 * Object that handles automatic animation of view properties. 3866 */ 3867 private ViewPropertyAnimator mAnimator = null; 3868 3869 /** 3870 * List of registered FrameMetricsObservers. 3871 */ 3872 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 3873 3874 /** 3875 * Flag indicating that a drag can cross window boundaries. When 3876 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3877 * with this flag set, all visible applications with targetSdkVersion >= 3878 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 3879 * in the drag operation and receive the dragged content. 3880 * 3881 * <p>If this is the only flag set, then the drag recipient will only have access to text data 3882 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 3883 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 3884 */ 3885 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 3886 3887 /** 3888 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3889 * request read access to the content URI(s) contained in the {@link ClipData} object. 3890 * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION 3891 */ 3892 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 3893 3894 /** 3895 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3896 * request write access to the content URI(s) contained in the {@link ClipData} object. 3897 * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION 3898 */ 3899 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 3900 3901 /** 3902 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3903 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 3904 * reboots until explicitly revoked with 3905 * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}. 3906 * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION 3907 */ 3908 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 3909 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 3910 3911 /** 3912 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3913 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 3914 * match against the original granted URI. 3915 * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION 3916 */ 3917 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 3918 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 3919 3920 /** 3921 * Flag indicating that the drag shadow will be opaque. When 3922 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3923 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 3924 */ 3925 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 3926 3927 /** 3928 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 3929 */ 3930 private float mVerticalScrollFactor; 3931 3932 /** 3933 * Position of the vertical scroll bar. 3934 */ 3935 private int mVerticalScrollbarPosition; 3936 3937 /** 3938 * Position the scroll bar at the default position as determined by the system. 3939 */ 3940 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 3941 3942 /** 3943 * Position the scroll bar along the left edge. 3944 */ 3945 public static final int SCROLLBAR_POSITION_LEFT = 1; 3946 3947 /** 3948 * Position the scroll bar along the right edge. 3949 */ 3950 public static final int SCROLLBAR_POSITION_RIGHT = 2; 3951 3952 /** 3953 * Indicates that the view does not have a layer. 3954 * 3955 * @see #getLayerType() 3956 * @see #setLayerType(int, android.graphics.Paint) 3957 * @see #LAYER_TYPE_SOFTWARE 3958 * @see #LAYER_TYPE_HARDWARE 3959 */ 3960 public static final int LAYER_TYPE_NONE = 0; 3961 3962 /** 3963 * <p>Indicates that the view has a software layer. A software layer is backed 3964 * by a bitmap and causes the view to be rendered using Android's software 3965 * rendering pipeline, even if hardware acceleration is enabled.</p> 3966 * 3967 * <p>Software layers have various usages:</p> 3968 * <p>When the application is not using hardware acceleration, a software layer 3969 * is useful to apply a specific color filter and/or blending mode and/or 3970 * translucency to a view and all its children.</p> 3971 * <p>When the application is using hardware acceleration, a software layer 3972 * is useful to render drawing primitives not supported by the hardware 3973 * accelerated pipeline. It can also be used to cache a complex view tree 3974 * into a texture and reduce the complexity of drawing operations. For instance, 3975 * when animating a complex view tree with a translation, a software layer can 3976 * be used to render the view tree only once.</p> 3977 * <p>Software layers should be avoided when the affected view tree updates 3978 * often. Every update will require to re-render the software layer, which can 3979 * potentially be slow (particularly when hardware acceleration is turned on 3980 * since the layer will have to be uploaded into a hardware texture after every 3981 * update.)</p> 3982 * 3983 * @see #getLayerType() 3984 * @see #setLayerType(int, android.graphics.Paint) 3985 * @see #LAYER_TYPE_NONE 3986 * @see #LAYER_TYPE_HARDWARE 3987 */ 3988 public static final int LAYER_TYPE_SOFTWARE = 1; 3989 3990 /** 3991 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 3992 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 3993 * OpenGL hardware) and causes the view to be rendered using Android's hardware 3994 * rendering pipeline, but only if hardware acceleration is turned on for the 3995 * view hierarchy. When hardware acceleration is turned off, hardware layers 3996 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 3997 * 3998 * <p>A hardware layer is useful to apply a specific color filter and/or 3999 * blending mode and/or translucency to a view and all its children.</p> 4000 * <p>A hardware layer can be used to cache a complex view tree into a 4001 * texture and reduce the complexity of drawing operations. For instance, 4002 * when animating a complex view tree with a translation, a hardware layer can 4003 * be used to render the view tree only once.</p> 4004 * <p>A hardware layer can also be used to increase the rendering quality when 4005 * rotation transformations are applied on a view. It can also be used to 4006 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4007 * 4008 * @see #getLayerType() 4009 * @see #setLayerType(int, android.graphics.Paint) 4010 * @see #LAYER_TYPE_NONE 4011 * @see #LAYER_TYPE_SOFTWARE 4012 */ 4013 public static final int LAYER_TYPE_HARDWARE = 2; 4014 4015 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4016 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4017 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4018 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4019 }) 4020 int mLayerType = LAYER_TYPE_NONE; 4021 Paint mLayerPaint; 4022 4023 4024 /** 4025 * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should not contain 4026 * PII (Personally Identifiable Information). 4027 */ 4028 // TODO(b/33197203) (b/33269702): improve documentation: mention all cases, show examples, etc. 4029 public static final int ASSIST_FLAG_SANITIZED_TEXT = 0x1; 4030 4031 /** 4032 * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should contain all 4033 * type of data, even sensitive PII (Personally Identifiable Information) like passwords or 4034 * credit card numbers. 4035 */ 4036 public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 0x2; 4037 4038 /** 4039 * Set to true when drawing cache is enabled and cannot be created. 4040 * 4041 * @hide 4042 */ 4043 public boolean mCachingFailed; 4044 private Bitmap mDrawingCache; 4045 private Bitmap mUnscaledDrawingCache; 4046 4047 /** 4048 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4049 * <p> 4050 * When non-null and valid, this is expected to contain an up-to-date copy 4051 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4052 * cleanup. 4053 */ 4054 final RenderNode mRenderNode; 4055 4056 /** 4057 * Set to true when the view is sending hover accessibility events because it 4058 * is the innermost hovered view. 4059 */ 4060 private boolean mSendingHoverAccessibilityEvents; 4061 4062 /** 4063 * Delegate for injecting accessibility functionality. 4064 */ 4065 AccessibilityDelegate mAccessibilityDelegate; 4066 4067 /** 4068 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4069 * and add/remove objects to/from the overlay directly through the Overlay methods. 4070 */ 4071 ViewOverlay mOverlay; 4072 4073 /** 4074 * The currently active parent view for receiving delegated nested scrolling events. 4075 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4076 * by {@link #stopNestedScroll()} at the same point where we clear 4077 * requestDisallowInterceptTouchEvent. 4078 */ 4079 private ViewParent mNestedScrollingParent; 4080 4081 /** 4082 * Consistency verifier for debugging purposes. 4083 * @hide 4084 */ 4085 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4086 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4087 new InputEventConsistencyVerifier(this, 0) : null; 4088 4089 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4090 4091 private int[] mTempNestedScrollConsumed; 4092 4093 /** 4094 * An overlay is going to draw this View instead of being drawn as part of this 4095 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4096 * when this view is invalidated. 4097 */ 4098 GhostView mGhostView; 4099 4100 /** 4101 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4102 * @hide 4103 */ 4104 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4105 public String[] mAttributes; 4106 4107 /** 4108 * Maps a Resource id to its name. 4109 */ 4110 private static SparseArray<String> mAttributeMap; 4111 4112 /** 4113 * Queue of pending runnables. Used to postpone calls to post() until this 4114 * view is attached and has a handler. 4115 */ 4116 private HandlerActionQueue mRunQueue; 4117 4118 /** 4119 * The pointer icon when the mouse hovers on this view. The default is null. 4120 */ 4121 private PointerIcon mPointerIcon; 4122 4123 /** 4124 * @hide 4125 */ 4126 String mStartActivityRequestWho; 4127 4128 @Nullable 4129 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4130 4131 /** 4132 * Simple constructor to use when creating a view from code. 4133 * 4134 * @param context The Context the view is running in, through which it can 4135 * access the current theme, resources, etc. 4136 */ 4137 public View(Context context) { 4138 mContext = context; 4139 mResources = context != null ? context.getResources() : null; 4140 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED; 4141 // Set some flags defaults 4142 mPrivateFlags2 = 4143 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4144 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4145 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4146 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4147 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4148 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4149 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4150 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4151 mUserPaddingStart = UNDEFINED_PADDING; 4152 mUserPaddingEnd = UNDEFINED_PADDING; 4153 mRenderNode = RenderNode.create(getClass().getName(), this); 4154 4155 if (!sCompatibilityDone && context != null) { 4156 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4157 4158 // Older apps may need this compatibility hack for measurement. 4159 sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1; 4160 4161 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4162 // of whether a layout was requested on that View. 4163 sIgnoreMeasureCache = targetSdkVersion < KITKAT; 4164 4165 Canvas.sCompatibilityRestore = targetSdkVersion < M; 4166 4167 // In M and newer, our widgets can pass a "hint" value in the size 4168 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4169 // know what the expected parent size is going to be, so e.g. list items can size 4170 // themselves at 1/3 the size of their container. It breaks older apps though, 4171 // specifically apps that use some popular open source libraries. 4172 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < M; 4173 4174 // Old versions of the platform would give different results from 4175 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4176 // modes, so we always need to run an additional EXACTLY pass. 4177 sAlwaysRemeasureExactly = targetSdkVersion <= M; 4178 4179 // Prior to N, layout params could change without requiring a 4180 // subsequent call to setLayoutParams() and they would usually 4181 // work. Partial layout breaks this assumption. 4182 sLayoutParamsAlwaysChanged = targetSdkVersion <= M; 4183 4184 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4185 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4186 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M; 4187 4188 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4189 // in apps so we target check it to avoid breaking existing apps. 4190 sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N; 4191 4192 sCascadedDragDrop = targetSdkVersion < N; 4193 4194 sCompatibilityDone = true; 4195 } 4196 } 4197 4198 /** 4199 * Constructor that is called when inflating a view from XML. This is called 4200 * when a view is being constructed from an XML file, supplying attributes 4201 * that were specified in the XML file. This version uses a default style of 4202 * 0, so the only attribute values applied are those in the Context's Theme 4203 * and the given AttributeSet. 4204 * 4205 * <p> 4206 * The method onFinishInflate() will be called after all children have been 4207 * added. 4208 * 4209 * @param context The Context the view is running in, through which it can 4210 * access the current theme, resources, etc. 4211 * @param attrs The attributes of the XML tag that is inflating the view. 4212 * @see #View(Context, AttributeSet, int) 4213 */ 4214 public View(Context context, @Nullable AttributeSet attrs) { 4215 this(context, attrs, 0); 4216 } 4217 4218 /** 4219 * Perform inflation from XML and apply a class-specific base style from a 4220 * theme attribute. This constructor of View allows subclasses to use their 4221 * own base style when they are inflating. For example, a Button class's 4222 * constructor would call this version of the super class constructor and 4223 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4224 * allows the theme's button style to modify all of the base view attributes 4225 * (in particular its background) as well as the Button class's attributes. 4226 * 4227 * @param context The Context the view is running in, through which it can 4228 * access the current theme, resources, etc. 4229 * @param attrs The attributes of the XML tag that is inflating the view. 4230 * @param defStyleAttr An attribute in the current theme that contains a 4231 * reference to a style resource that supplies default values for 4232 * the view. Can be 0 to not look for defaults. 4233 * @see #View(Context, AttributeSet) 4234 */ 4235 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4236 this(context, attrs, defStyleAttr, 0); 4237 } 4238 4239 /** 4240 * Perform inflation from XML and apply a class-specific base style from a 4241 * theme attribute or style resource. This constructor of View allows 4242 * subclasses to use their own base style when they are inflating. 4243 * <p> 4244 * When determining the final value of a particular attribute, there are 4245 * four inputs that come into play: 4246 * <ol> 4247 * <li>Any attribute values in the given AttributeSet. 4248 * <li>The style resource specified in the AttributeSet (named "style"). 4249 * <li>The default style specified by <var>defStyleAttr</var>. 4250 * <li>The default style specified by <var>defStyleRes</var>. 4251 * <li>The base values in this theme. 4252 * </ol> 4253 * <p> 4254 * Each of these inputs is considered in-order, with the first listed taking 4255 * precedence over the following ones. In other words, if in the 4256 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4257 * , then the button's text will <em>always</em> be black, regardless of 4258 * what is specified in any of the styles. 4259 * 4260 * @param context The Context the view is running in, through which it can 4261 * access the current theme, resources, etc. 4262 * @param attrs The attributes of the XML tag that is inflating the view. 4263 * @param defStyleAttr An attribute in the current theme that contains a 4264 * reference to a style resource that supplies default values for 4265 * the view. Can be 0 to not look for defaults. 4266 * @param defStyleRes A resource identifier of a style resource that 4267 * supplies default values for the view, used only if 4268 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4269 * to not look for defaults. 4270 * @see #View(Context, AttributeSet, int) 4271 */ 4272 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4273 this(context); 4274 4275 final TypedArray a = context.obtainStyledAttributes( 4276 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4277 4278 if (mDebugViewAttributes) { 4279 saveAttributeData(attrs, a); 4280 } 4281 4282 Drawable background = null; 4283 4284 int leftPadding = -1; 4285 int topPadding = -1; 4286 int rightPadding = -1; 4287 int bottomPadding = -1; 4288 int startPadding = UNDEFINED_PADDING; 4289 int endPadding = UNDEFINED_PADDING; 4290 4291 int padding = -1; 4292 int paddingHorizontal = -1; 4293 int paddingVertical = -1; 4294 4295 int viewFlagValues = 0; 4296 int viewFlagMasks = 0; 4297 4298 boolean setScrollContainer = false; 4299 4300 int x = 0; 4301 int y = 0; 4302 4303 float tx = 0; 4304 float ty = 0; 4305 float tz = 0; 4306 float elevation = 0; 4307 float rotation = 0; 4308 float rotationX = 0; 4309 float rotationY = 0; 4310 float sx = 1f; 4311 float sy = 1f; 4312 boolean transformSet = false; 4313 4314 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4315 int overScrollMode = mOverScrollMode; 4316 boolean initializeScrollbars = false; 4317 boolean initializeScrollIndicators = false; 4318 4319 boolean startPaddingDefined = false; 4320 boolean endPaddingDefined = false; 4321 boolean leftPaddingDefined = false; 4322 boolean rightPaddingDefined = false; 4323 4324 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4325 4326 final int N = a.getIndexCount(); 4327 for (int i = 0; i < N; i++) { 4328 int attr = a.getIndex(i); 4329 switch (attr) { 4330 case com.android.internal.R.styleable.View_background: 4331 background = a.getDrawable(attr); 4332 break; 4333 case com.android.internal.R.styleable.View_padding: 4334 padding = a.getDimensionPixelSize(attr, -1); 4335 mUserPaddingLeftInitial = padding; 4336 mUserPaddingRightInitial = padding; 4337 leftPaddingDefined = true; 4338 rightPaddingDefined = true; 4339 break; 4340 case com.android.internal.R.styleable.View_paddingHorizontal: 4341 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4342 mUserPaddingLeftInitial = paddingHorizontal; 4343 mUserPaddingRightInitial = paddingHorizontal; 4344 leftPaddingDefined = true; 4345 rightPaddingDefined = true; 4346 break; 4347 case com.android.internal.R.styleable.View_paddingVertical: 4348 paddingVertical = a.getDimensionPixelSize(attr, -1); 4349 break; 4350 case com.android.internal.R.styleable.View_paddingLeft: 4351 leftPadding = a.getDimensionPixelSize(attr, -1); 4352 mUserPaddingLeftInitial = leftPadding; 4353 leftPaddingDefined = true; 4354 break; 4355 case com.android.internal.R.styleable.View_paddingTop: 4356 topPadding = a.getDimensionPixelSize(attr, -1); 4357 break; 4358 case com.android.internal.R.styleable.View_paddingRight: 4359 rightPadding = a.getDimensionPixelSize(attr, -1); 4360 mUserPaddingRightInitial = rightPadding; 4361 rightPaddingDefined = true; 4362 break; 4363 case com.android.internal.R.styleable.View_paddingBottom: 4364 bottomPadding = a.getDimensionPixelSize(attr, -1); 4365 break; 4366 case com.android.internal.R.styleable.View_paddingStart: 4367 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4368 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4369 break; 4370 case com.android.internal.R.styleable.View_paddingEnd: 4371 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4372 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4373 break; 4374 case com.android.internal.R.styleable.View_scrollX: 4375 x = a.getDimensionPixelOffset(attr, 0); 4376 break; 4377 case com.android.internal.R.styleable.View_scrollY: 4378 y = a.getDimensionPixelOffset(attr, 0); 4379 break; 4380 case com.android.internal.R.styleable.View_alpha: 4381 setAlpha(a.getFloat(attr, 1f)); 4382 break; 4383 case com.android.internal.R.styleable.View_transformPivotX: 4384 setPivotX(a.getDimension(attr, 0)); 4385 break; 4386 case com.android.internal.R.styleable.View_transformPivotY: 4387 setPivotY(a.getDimension(attr, 0)); 4388 break; 4389 case com.android.internal.R.styleable.View_translationX: 4390 tx = a.getDimension(attr, 0); 4391 transformSet = true; 4392 break; 4393 case com.android.internal.R.styleable.View_translationY: 4394 ty = a.getDimension(attr, 0); 4395 transformSet = true; 4396 break; 4397 case com.android.internal.R.styleable.View_translationZ: 4398 tz = a.getDimension(attr, 0); 4399 transformSet = true; 4400 break; 4401 case com.android.internal.R.styleable.View_elevation: 4402 elevation = a.getDimension(attr, 0); 4403 transformSet = true; 4404 break; 4405 case com.android.internal.R.styleable.View_rotation: 4406 rotation = a.getFloat(attr, 0); 4407 transformSet = true; 4408 break; 4409 case com.android.internal.R.styleable.View_rotationX: 4410 rotationX = a.getFloat(attr, 0); 4411 transformSet = true; 4412 break; 4413 case com.android.internal.R.styleable.View_rotationY: 4414 rotationY = a.getFloat(attr, 0); 4415 transformSet = true; 4416 break; 4417 case com.android.internal.R.styleable.View_scaleX: 4418 sx = a.getFloat(attr, 1f); 4419 transformSet = true; 4420 break; 4421 case com.android.internal.R.styleable.View_scaleY: 4422 sy = a.getFloat(attr, 1f); 4423 transformSet = true; 4424 break; 4425 case com.android.internal.R.styleable.View_id: 4426 mID = a.getResourceId(attr, NO_ID); 4427 break; 4428 case com.android.internal.R.styleable.View_tag: 4429 mTag = a.getText(attr); 4430 break; 4431 case com.android.internal.R.styleable.View_fitsSystemWindows: 4432 if (a.getBoolean(attr, false)) { 4433 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4434 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4435 } 4436 break; 4437 case com.android.internal.R.styleable.View_focusable: 4438 if (a.getBoolean(attr, false)) { 4439 viewFlagValues |= FOCUSABLE; 4440 viewFlagMasks |= FOCUSABLE_MASK; 4441 } 4442 break; 4443 case com.android.internal.R.styleable.View_focusableInTouchMode: 4444 if (a.getBoolean(attr, false)) { 4445 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4446 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4447 } 4448 break; 4449 case com.android.internal.R.styleable.View_clickable: 4450 if (a.getBoolean(attr, false)) { 4451 viewFlagValues |= CLICKABLE; 4452 viewFlagMasks |= CLICKABLE; 4453 } 4454 break; 4455 case com.android.internal.R.styleable.View_longClickable: 4456 if (a.getBoolean(attr, false)) { 4457 viewFlagValues |= LONG_CLICKABLE; 4458 viewFlagMasks |= LONG_CLICKABLE; 4459 } 4460 break; 4461 case com.android.internal.R.styleable.View_contextClickable: 4462 if (a.getBoolean(attr, false)) { 4463 viewFlagValues |= CONTEXT_CLICKABLE; 4464 viewFlagMasks |= CONTEXT_CLICKABLE; 4465 } 4466 break; 4467 case com.android.internal.R.styleable.View_saveEnabled: 4468 if (!a.getBoolean(attr, true)) { 4469 viewFlagValues |= SAVE_DISABLED; 4470 viewFlagMasks |= SAVE_DISABLED_MASK; 4471 } 4472 break; 4473 case com.android.internal.R.styleable.View_duplicateParentState: 4474 if (a.getBoolean(attr, false)) { 4475 viewFlagValues |= DUPLICATE_PARENT_STATE; 4476 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4477 } 4478 break; 4479 case com.android.internal.R.styleable.View_visibility: 4480 final int visibility = a.getInt(attr, 0); 4481 if (visibility != 0) { 4482 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4483 viewFlagMasks |= VISIBILITY_MASK; 4484 } 4485 break; 4486 case com.android.internal.R.styleable.View_layoutDirection: 4487 // Clear any layout direction flags (included resolved bits) already set 4488 mPrivateFlags2 &= 4489 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4490 // Set the layout direction flags depending on the value of the attribute 4491 final int layoutDirection = a.getInt(attr, -1); 4492 final int value = (layoutDirection != -1) ? 4493 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4494 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4495 break; 4496 case com.android.internal.R.styleable.View_drawingCacheQuality: 4497 final int cacheQuality = a.getInt(attr, 0); 4498 if (cacheQuality != 0) { 4499 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4500 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4501 } 4502 break; 4503 case com.android.internal.R.styleable.View_contentDescription: 4504 setContentDescription(a.getString(attr)); 4505 break; 4506 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4507 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4508 break; 4509 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4510 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4511 break; 4512 case com.android.internal.R.styleable.View_labelFor: 4513 setLabelFor(a.getResourceId(attr, NO_ID)); 4514 break; 4515 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4516 if (!a.getBoolean(attr, true)) { 4517 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4518 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4519 } 4520 break; 4521 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4522 if (!a.getBoolean(attr, true)) { 4523 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4524 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4525 } 4526 break; 4527 case R.styleable.View_scrollbars: 4528 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4529 if (scrollbars != SCROLLBARS_NONE) { 4530 viewFlagValues |= scrollbars; 4531 viewFlagMasks |= SCROLLBARS_MASK; 4532 initializeScrollbars = true; 4533 } 4534 break; 4535 //noinspection deprecation 4536 case R.styleable.View_fadingEdge: 4537 if (targetSdkVersion >= ICE_CREAM_SANDWICH) { 4538 // Ignore the attribute starting with ICS 4539 break; 4540 } 4541 // With builds < ICS, fall through and apply fading edges 4542 case R.styleable.View_requiresFadingEdge: 4543 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4544 if (fadingEdge != FADING_EDGE_NONE) { 4545 viewFlagValues |= fadingEdge; 4546 viewFlagMasks |= FADING_EDGE_MASK; 4547 initializeFadingEdgeInternal(a); 4548 } 4549 break; 4550 case R.styleable.View_scrollbarStyle: 4551 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4552 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4553 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4554 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4555 } 4556 break; 4557 case R.styleable.View_isScrollContainer: 4558 setScrollContainer = true; 4559 if (a.getBoolean(attr, false)) { 4560 setScrollContainer(true); 4561 } 4562 break; 4563 case com.android.internal.R.styleable.View_keepScreenOn: 4564 if (a.getBoolean(attr, false)) { 4565 viewFlagValues |= KEEP_SCREEN_ON; 4566 viewFlagMasks |= KEEP_SCREEN_ON; 4567 } 4568 break; 4569 case R.styleable.View_filterTouchesWhenObscured: 4570 if (a.getBoolean(attr, false)) { 4571 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4572 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4573 } 4574 break; 4575 case R.styleable.View_nextFocusLeft: 4576 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4577 break; 4578 case R.styleable.View_nextFocusRight: 4579 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4580 break; 4581 case R.styleable.View_nextFocusUp: 4582 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4583 break; 4584 case R.styleable.View_nextFocusDown: 4585 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4586 break; 4587 case R.styleable.View_nextFocusForward: 4588 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4589 break; 4590 case R.styleable.View_nextClusterForward: 4591 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 4592 break; 4593 case R.styleable.View_nextSectionForward: 4594 mNextSectionForwardId = a.getResourceId(attr, View.NO_ID); 4595 break; 4596 case R.styleable.View_minWidth: 4597 mMinWidth = a.getDimensionPixelSize(attr, 0); 4598 break; 4599 case R.styleable.View_minHeight: 4600 mMinHeight = a.getDimensionPixelSize(attr, 0); 4601 break; 4602 case R.styleable.View_onClick: 4603 if (context.isRestricted()) { 4604 throw new IllegalStateException("The android:onClick attribute cannot " 4605 + "be used within a restricted context"); 4606 } 4607 4608 final String handlerName = a.getString(attr); 4609 if (handlerName != null) { 4610 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 4611 } 4612 break; 4613 case R.styleable.View_overScrollMode: 4614 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 4615 break; 4616 case R.styleable.View_verticalScrollbarPosition: 4617 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 4618 break; 4619 case R.styleable.View_layerType: 4620 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 4621 break; 4622 case R.styleable.View_textDirection: 4623 // Clear any text direction flag already set 4624 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 4625 // Set the text direction flags depending on the value of the attribute 4626 final int textDirection = a.getInt(attr, -1); 4627 if (textDirection != -1) { 4628 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 4629 } 4630 break; 4631 case R.styleable.View_textAlignment: 4632 // Clear any text alignment flag already set 4633 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 4634 // Set the text alignment flag depending on the value of the attribute 4635 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 4636 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 4637 break; 4638 case R.styleable.View_importantForAccessibility: 4639 setImportantForAccessibility(a.getInt(attr, 4640 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 4641 break; 4642 case R.styleable.View_accessibilityLiveRegion: 4643 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 4644 break; 4645 case R.styleable.View_transitionName: 4646 setTransitionName(a.getString(attr)); 4647 break; 4648 case R.styleable.View_nestedScrollingEnabled: 4649 setNestedScrollingEnabled(a.getBoolean(attr, false)); 4650 break; 4651 case R.styleable.View_stateListAnimator: 4652 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 4653 a.getResourceId(attr, 0))); 4654 break; 4655 case R.styleable.View_backgroundTint: 4656 // This will get applied later during setBackground(). 4657 if (mBackgroundTint == null) { 4658 mBackgroundTint = new TintInfo(); 4659 } 4660 mBackgroundTint.mTintList = a.getColorStateList( 4661 R.styleable.View_backgroundTint); 4662 mBackgroundTint.mHasTintList = true; 4663 break; 4664 case R.styleable.View_backgroundTintMode: 4665 // This will get applied later during setBackground(). 4666 if (mBackgroundTint == null) { 4667 mBackgroundTint = new TintInfo(); 4668 } 4669 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 4670 R.styleable.View_backgroundTintMode, -1), null); 4671 mBackgroundTint.mHasTintMode = true; 4672 break; 4673 case R.styleable.View_outlineProvider: 4674 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 4675 PROVIDER_BACKGROUND)); 4676 break; 4677 case R.styleable.View_foreground: 4678 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4679 setForeground(a.getDrawable(attr)); 4680 } 4681 break; 4682 case R.styleable.View_foregroundGravity: 4683 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4684 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 4685 } 4686 break; 4687 case R.styleable.View_foregroundTintMode: 4688 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4689 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 4690 } 4691 break; 4692 case R.styleable.View_foregroundTint: 4693 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4694 setForegroundTintList(a.getColorStateList(attr)); 4695 } 4696 break; 4697 case R.styleable.View_foregroundInsidePadding: 4698 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4699 if (mForegroundInfo == null) { 4700 mForegroundInfo = new ForegroundInfo(); 4701 } 4702 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 4703 mForegroundInfo.mInsidePadding); 4704 } 4705 break; 4706 case R.styleable.View_scrollIndicators: 4707 final int scrollIndicators = 4708 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 4709 & SCROLL_INDICATORS_PFLAG3_MASK; 4710 if (scrollIndicators != 0) { 4711 mPrivateFlags3 |= scrollIndicators; 4712 initializeScrollIndicators = true; 4713 } 4714 break; 4715 case R.styleable.View_pointerIcon: 4716 final int resourceId = a.getResourceId(attr, 0); 4717 if (resourceId != 0) { 4718 setPointerIcon(PointerIcon.load( 4719 context.getResources(), resourceId)); 4720 } else { 4721 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 4722 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 4723 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 4724 } 4725 } 4726 break; 4727 case R.styleable.View_forceHasOverlappingRendering: 4728 if (a.peekValue(attr) != null) { 4729 forceHasOverlappingRendering(a.getBoolean(attr, true)); 4730 } 4731 break; 4732 case R.styleable.View_tooltip: 4733 setTooltip(a.getText(attr)); 4734 break; 4735 case R.styleable.View_keyboardNavigationCluster: 4736 if (a.peekValue(attr) != null) { 4737 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 4738 } 4739 break; 4740 case R.styleable.View_keyboardNavigationSection: 4741 if (a.peekValue(attr) != null) { 4742 setKeyboardNavigationSection(a.getBoolean(attr, true)); 4743 } 4744 break; 4745 } 4746 } 4747 4748 setOverScrollMode(overScrollMode); 4749 4750 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 4751 // the resolved layout direction). Those cached values will be used later during padding 4752 // resolution. 4753 mUserPaddingStart = startPadding; 4754 mUserPaddingEnd = endPadding; 4755 4756 if (background != null) { 4757 setBackground(background); 4758 } 4759 4760 // setBackground above will record that padding is currently provided by the background. 4761 // If we have padding specified via xml, record that here instead and use it. 4762 mLeftPaddingDefined = leftPaddingDefined; 4763 mRightPaddingDefined = rightPaddingDefined; 4764 4765 if (padding >= 0) { 4766 leftPadding = padding; 4767 topPadding = padding; 4768 rightPadding = padding; 4769 bottomPadding = padding; 4770 mUserPaddingLeftInitial = padding; 4771 mUserPaddingRightInitial = padding; 4772 } else { 4773 if (paddingHorizontal >= 0) { 4774 leftPadding = paddingHorizontal; 4775 rightPadding = paddingHorizontal; 4776 mUserPaddingLeftInitial = paddingHorizontal; 4777 mUserPaddingRightInitial = paddingHorizontal; 4778 } 4779 if (paddingVertical >= 0) { 4780 topPadding = paddingVertical; 4781 bottomPadding = paddingVertical; 4782 } 4783 } 4784 4785 if (isRtlCompatibilityMode()) { 4786 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 4787 // left / right padding are used if defined (meaning here nothing to do). If they are not 4788 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 4789 // start / end and resolve them as left / right (layout direction is not taken into account). 4790 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4791 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4792 // defined. 4793 if (!mLeftPaddingDefined && startPaddingDefined) { 4794 leftPadding = startPadding; 4795 } 4796 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 4797 if (!mRightPaddingDefined && endPaddingDefined) { 4798 rightPadding = endPadding; 4799 } 4800 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 4801 } else { 4802 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 4803 // values defined. Otherwise, left /right values are used. 4804 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4805 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4806 // defined. 4807 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 4808 4809 if (mLeftPaddingDefined && !hasRelativePadding) { 4810 mUserPaddingLeftInitial = leftPadding; 4811 } 4812 if (mRightPaddingDefined && !hasRelativePadding) { 4813 mUserPaddingRightInitial = rightPadding; 4814 } 4815 } 4816 4817 internalSetPadding( 4818 mUserPaddingLeftInitial, 4819 topPadding >= 0 ? topPadding : mPaddingTop, 4820 mUserPaddingRightInitial, 4821 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 4822 4823 if (viewFlagMasks != 0) { 4824 setFlags(viewFlagValues, viewFlagMasks); 4825 } 4826 4827 if (initializeScrollbars) { 4828 initializeScrollbarsInternal(a); 4829 } 4830 4831 if (initializeScrollIndicators) { 4832 initializeScrollIndicatorsInternal(); 4833 } 4834 4835 a.recycle(); 4836 4837 // Needs to be called after mViewFlags is set 4838 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4839 recomputePadding(); 4840 } 4841 4842 if (x != 0 || y != 0) { 4843 scrollTo(x, y); 4844 } 4845 4846 if (transformSet) { 4847 setTranslationX(tx); 4848 setTranslationY(ty); 4849 setTranslationZ(tz); 4850 setElevation(elevation); 4851 setRotation(rotation); 4852 setRotationX(rotationX); 4853 setRotationY(rotationY); 4854 setScaleX(sx); 4855 setScaleY(sy); 4856 } 4857 4858 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 4859 setScrollContainer(true); 4860 } 4861 4862 computeOpaqueFlags(); 4863 } 4864 4865 /** 4866 * An implementation of OnClickListener that attempts to lazily load a 4867 * named click handling method from a parent or ancestor context. 4868 */ 4869 private static class DeclaredOnClickListener implements OnClickListener { 4870 private final View mHostView; 4871 private final String mMethodName; 4872 4873 private Method mResolvedMethod; 4874 private Context mResolvedContext; 4875 4876 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 4877 mHostView = hostView; 4878 mMethodName = methodName; 4879 } 4880 4881 @Override 4882 public void onClick(@NonNull View v) { 4883 if (mResolvedMethod == null) { 4884 resolveMethod(mHostView.getContext(), mMethodName); 4885 } 4886 4887 try { 4888 mResolvedMethod.invoke(mResolvedContext, v); 4889 } catch (IllegalAccessException e) { 4890 throw new IllegalStateException( 4891 "Could not execute non-public method for android:onClick", e); 4892 } catch (InvocationTargetException e) { 4893 throw new IllegalStateException( 4894 "Could not execute method for android:onClick", e); 4895 } 4896 } 4897 4898 @NonNull 4899 private void resolveMethod(@Nullable Context context, @NonNull String name) { 4900 while (context != null) { 4901 try { 4902 if (!context.isRestricted()) { 4903 final Method method = context.getClass().getMethod(mMethodName, View.class); 4904 if (method != null) { 4905 mResolvedMethod = method; 4906 mResolvedContext = context; 4907 return; 4908 } 4909 } 4910 } catch (NoSuchMethodException e) { 4911 // Failed to find method, keep searching up the hierarchy. 4912 } 4913 4914 if (context instanceof ContextWrapper) { 4915 context = ((ContextWrapper) context).getBaseContext(); 4916 } else { 4917 // Can't search up the hierarchy, null out and fail. 4918 context = null; 4919 } 4920 } 4921 4922 final int id = mHostView.getId(); 4923 final String idText = id == NO_ID ? "" : " with id '" 4924 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 4925 throw new IllegalStateException("Could not find method " + mMethodName 4926 + "(View) in a parent or ancestor Context for android:onClick " 4927 + "attribute defined on view " + mHostView.getClass() + idText); 4928 } 4929 } 4930 4931 /** 4932 * Non-public constructor for use in testing 4933 */ 4934 View() { 4935 mResources = null; 4936 mRenderNode = RenderNode.create(getClass().getName(), this); 4937 } 4938 4939 final boolean debugDraw() { 4940 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 4941 } 4942 4943 private static SparseArray<String> getAttributeMap() { 4944 if (mAttributeMap == null) { 4945 mAttributeMap = new SparseArray<>(); 4946 } 4947 return mAttributeMap; 4948 } 4949 4950 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 4951 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 4952 final int indexCount = t.getIndexCount(); 4953 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 4954 4955 int i = 0; 4956 4957 // Store raw XML attributes. 4958 for (int j = 0; j < attrsCount; ++j) { 4959 attributes[i] = attrs.getAttributeName(j); 4960 attributes[i + 1] = attrs.getAttributeValue(j); 4961 i += 2; 4962 } 4963 4964 // Store resolved styleable attributes. 4965 final Resources res = t.getResources(); 4966 final SparseArray<String> attributeMap = getAttributeMap(); 4967 for (int j = 0; j < indexCount; ++j) { 4968 final int index = t.getIndex(j); 4969 if (!t.hasValueOrEmpty(index)) { 4970 // Value is undefined. Skip it. 4971 continue; 4972 } 4973 4974 final int resourceId = t.getResourceId(index, 0); 4975 if (resourceId == 0) { 4976 // Value is not a reference. Skip it. 4977 continue; 4978 } 4979 4980 String resourceName = attributeMap.get(resourceId); 4981 if (resourceName == null) { 4982 try { 4983 resourceName = res.getResourceName(resourceId); 4984 } catch (Resources.NotFoundException e) { 4985 resourceName = "0x" + Integer.toHexString(resourceId); 4986 } 4987 attributeMap.put(resourceId, resourceName); 4988 } 4989 4990 attributes[i] = resourceName; 4991 attributes[i + 1] = t.getString(index); 4992 i += 2; 4993 } 4994 4995 // Trim to fit contents. 4996 final String[] trimmed = new String[i]; 4997 System.arraycopy(attributes, 0, trimmed, 0, i); 4998 mAttributes = trimmed; 4999 } 5000 5001 public String toString() { 5002 StringBuilder out = new StringBuilder(128); 5003 out.append(getClass().getName()); 5004 out.append('{'); 5005 out.append(Integer.toHexString(System.identityHashCode(this))); 5006 out.append(' '); 5007 switch (mViewFlags&VISIBILITY_MASK) { 5008 case VISIBLE: out.append('V'); break; 5009 case INVISIBLE: out.append('I'); break; 5010 case GONE: out.append('G'); break; 5011 default: out.append('.'); break; 5012 } 5013 out.append((mViewFlags&FOCUSABLE_MASK) == FOCUSABLE ? 'F' : '.'); 5014 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5015 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5016 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5017 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5018 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5019 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5020 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5021 out.append(' '); 5022 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5023 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5024 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5025 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5026 out.append('p'); 5027 } else { 5028 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5029 } 5030 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5031 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5032 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5033 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5034 out.append(' '); 5035 out.append(mLeft); 5036 out.append(','); 5037 out.append(mTop); 5038 out.append('-'); 5039 out.append(mRight); 5040 out.append(','); 5041 out.append(mBottom); 5042 final int id = getId(); 5043 if (id != NO_ID) { 5044 out.append(" #"); 5045 out.append(Integer.toHexString(id)); 5046 final Resources r = mResources; 5047 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5048 try { 5049 String pkgname; 5050 switch (id&0xff000000) { 5051 case 0x7f000000: 5052 pkgname="app"; 5053 break; 5054 case 0x01000000: 5055 pkgname="android"; 5056 break; 5057 default: 5058 pkgname = r.getResourcePackageName(id); 5059 break; 5060 } 5061 String typename = r.getResourceTypeName(id); 5062 String entryname = r.getResourceEntryName(id); 5063 out.append(" "); 5064 out.append(pkgname); 5065 out.append(":"); 5066 out.append(typename); 5067 out.append("/"); 5068 out.append(entryname); 5069 } catch (Resources.NotFoundException e) { 5070 } 5071 } 5072 } 5073 out.append("}"); 5074 return out.toString(); 5075 } 5076 5077 /** 5078 * <p> 5079 * Initializes the fading edges from a given set of styled attributes. This 5080 * method should be called by subclasses that need fading edges and when an 5081 * instance of these subclasses is created programmatically rather than 5082 * being inflated from XML. This method is automatically called when the XML 5083 * is inflated. 5084 * </p> 5085 * 5086 * @param a the styled attributes set to initialize the fading edges from 5087 * 5088 * @removed 5089 */ 5090 protected void initializeFadingEdge(TypedArray a) { 5091 // This method probably shouldn't have been included in the SDK to begin with. 5092 // It relies on 'a' having been initialized using an attribute filter array that is 5093 // not publicly available to the SDK. The old method has been renamed 5094 // to initializeFadingEdgeInternal and hidden for framework use only; 5095 // this one initializes using defaults to make it safe to call for apps. 5096 5097 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5098 5099 initializeFadingEdgeInternal(arr); 5100 5101 arr.recycle(); 5102 } 5103 5104 /** 5105 * <p> 5106 * Initializes the fading edges from a given set of styled attributes. This 5107 * method should be called by subclasses that need fading edges and when an 5108 * instance of these subclasses is created programmatically rather than 5109 * being inflated from XML. This method is automatically called when the XML 5110 * is inflated. 5111 * </p> 5112 * 5113 * @param a the styled attributes set to initialize the fading edges from 5114 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5115 */ 5116 protected void initializeFadingEdgeInternal(TypedArray a) { 5117 initScrollCache(); 5118 5119 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5120 R.styleable.View_fadingEdgeLength, 5121 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5122 } 5123 5124 /** 5125 * Returns the size of the vertical faded edges used to indicate that more 5126 * content in this view is visible. 5127 * 5128 * @return The size in pixels of the vertical faded edge or 0 if vertical 5129 * faded edges are not enabled for this view. 5130 * @attr ref android.R.styleable#View_fadingEdgeLength 5131 */ 5132 public int getVerticalFadingEdgeLength() { 5133 if (isVerticalFadingEdgeEnabled()) { 5134 ScrollabilityCache cache = mScrollCache; 5135 if (cache != null) { 5136 return cache.fadingEdgeLength; 5137 } 5138 } 5139 return 0; 5140 } 5141 5142 /** 5143 * Set the size of the faded edge used to indicate that more content in this 5144 * view is available. Will not change whether the fading edge is enabled; use 5145 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5146 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5147 * for the vertical or horizontal fading edges. 5148 * 5149 * @param length The size in pixels of the faded edge used to indicate that more 5150 * content in this view is visible. 5151 */ 5152 public void setFadingEdgeLength(int length) { 5153 initScrollCache(); 5154 mScrollCache.fadingEdgeLength = length; 5155 } 5156 5157 /** 5158 * Returns the size of the horizontal faded edges used to indicate that more 5159 * content in this view is visible. 5160 * 5161 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5162 * faded edges are not enabled for this view. 5163 * @attr ref android.R.styleable#View_fadingEdgeLength 5164 */ 5165 public int getHorizontalFadingEdgeLength() { 5166 if (isHorizontalFadingEdgeEnabled()) { 5167 ScrollabilityCache cache = mScrollCache; 5168 if (cache != null) { 5169 return cache.fadingEdgeLength; 5170 } 5171 } 5172 return 0; 5173 } 5174 5175 /** 5176 * Returns the width of the vertical scrollbar. 5177 * 5178 * @return The width in pixels of the vertical scrollbar or 0 if there 5179 * is no vertical scrollbar. 5180 */ 5181 public int getVerticalScrollbarWidth() { 5182 ScrollabilityCache cache = mScrollCache; 5183 if (cache != null) { 5184 ScrollBarDrawable scrollBar = cache.scrollBar; 5185 if (scrollBar != null) { 5186 int size = scrollBar.getSize(true); 5187 if (size <= 0) { 5188 size = cache.scrollBarSize; 5189 } 5190 return size; 5191 } 5192 return 0; 5193 } 5194 return 0; 5195 } 5196 5197 /** 5198 * Returns the height of the horizontal scrollbar. 5199 * 5200 * @return The height in pixels of the horizontal scrollbar or 0 if 5201 * there is no horizontal scrollbar. 5202 */ 5203 protected int getHorizontalScrollbarHeight() { 5204 ScrollabilityCache cache = mScrollCache; 5205 if (cache != null) { 5206 ScrollBarDrawable scrollBar = cache.scrollBar; 5207 if (scrollBar != null) { 5208 int size = scrollBar.getSize(false); 5209 if (size <= 0) { 5210 size = cache.scrollBarSize; 5211 } 5212 return size; 5213 } 5214 return 0; 5215 } 5216 return 0; 5217 } 5218 5219 /** 5220 * <p> 5221 * Initializes the scrollbars from a given set of styled attributes. This 5222 * method should be called by subclasses that need scrollbars and when an 5223 * instance of these subclasses is created programmatically rather than 5224 * being inflated from XML. This method is automatically called when the XML 5225 * is inflated. 5226 * </p> 5227 * 5228 * @param a the styled attributes set to initialize the scrollbars from 5229 * 5230 * @removed 5231 */ 5232 protected void initializeScrollbars(TypedArray a) { 5233 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5234 // using the View filter array which is not available to the SDK. As such, internal 5235 // framework usage now uses initializeScrollbarsInternal and we grab a default 5236 // TypedArray with the right filter instead here. 5237 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5238 5239 initializeScrollbarsInternal(arr); 5240 5241 // We ignored the method parameter. Recycle the one we actually did use. 5242 arr.recycle(); 5243 } 5244 5245 /** 5246 * <p> 5247 * Initializes the scrollbars from a given set of styled attributes. This 5248 * method should be called by subclasses that need scrollbars and when an 5249 * instance of these subclasses is created programmatically rather than 5250 * being inflated from XML. This method is automatically called when the XML 5251 * is inflated. 5252 * </p> 5253 * 5254 * @param a the styled attributes set to initialize the scrollbars from 5255 * @hide 5256 */ 5257 protected void initializeScrollbarsInternal(TypedArray a) { 5258 initScrollCache(); 5259 5260 final ScrollabilityCache scrollabilityCache = mScrollCache; 5261 5262 if (scrollabilityCache.scrollBar == null) { 5263 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5264 scrollabilityCache.scrollBar.setState(getDrawableState()); 5265 scrollabilityCache.scrollBar.setCallback(this); 5266 } 5267 5268 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5269 5270 if (!fadeScrollbars) { 5271 scrollabilityCache.state = ScrollabilityCache.ON; 5272 } 5273 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5274 5275 5276 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5277 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5278 .getScrollBarFadeDuration()); 5279 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5280 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5281 ViewConfiguration.getScrollDefaultDelay()); 5282 5283 5284 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5285 com.android.internal.R.styleable.View_scrollbarSize, 5286 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5287 5288 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5289 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5290 5291 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5292 if (thumb != null) { 5293 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5294 } 5295 5296 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5297 false); 5298 if (alwaysDraw) { 5299 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5300 } 5301 5302 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5303 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5304 5305 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5306 if (thumb != null) { 5307 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5308 } 5309 5310 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5311 false); 5312 if (alwaysDraw) { 5313 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5314 } 5315 5316 // Apply layout direction to the new Drawables if needed 5317 final int layoutDirection = getLayoutDirection(); 5318 if (track != null) { 5319 track.setLayoutDirection(layoutDirection); 5320 } 5321 if (thumb != null) { 5322 thumb.setLayoutDirection(layoutDirection); 5323 } 5324 5325 // Re-apply user/background padding so that scrollbar(s) get added 5326 resolvePadding(); 5327 } 5328 5329 private void initializeScrollIndicatorsInternal() { 5330 // Some day maybe we'll break this into top/left/start/etc. and let the 5331 // client control it. Until then, you can have any scroll indicator you 5332 // want as long as it's a 1dp foreground-colored rectangle. 5333 if (mScrollIndicatorDrawable == null) { 5334 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5335 } 5336 } 5337 5338 /** 5339 * <p> 5340 * Initalizes the scrollability cache if necessary. 5341 * </p> 5342 */ 5343 private void initScrollCache() { 5344 if (mScrollCache == null) { 5345 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5346 } 5347 } 5348 5349 private ScrollabilityCache getScrollCache() { 5350 initScrollCache(); 5351 return mScrollCache; 5352 } 5353 5354 /** 5355 * Set the position of the vertical scroll bar. Should be one of 5356 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5357 * {@link #SCROLLBAR_POSITION_RIGHT}. 5358 * 5359 * @param position Where the vertical scroll bar should be positioned. 5360 */ 5361 public void setVerticalScrollbarPosition(int position) { 5362 if (mVerticalScrollbarPosition != position) { 5363 mVerticalScrollbarPosition = position; 5364 computeOpaqueFlags(); 5365 resolvePadding(); 5366 } 5367 } 5368 5369 /** 5370 * @return The position where the vertical scroll bar will show, if applicable. 5371 * @see #setVerticalScrollbarPosition(int) 5372 */ 5373 public int getVerticalScrollbarPosition() { 5374 return mVerticalScrollbarPosition; 5375 } 5376 5377 boolean isOnScrollbar(float x, float y) { 5378 if (mScrollCache == null) { 5379 return false; 5380 } 5381 x += getScrollX(); 5382 y += getScrollY(); 5383 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5384 final Rect bounds = mScrollCache.mScrollBarBounds; 5385 getVerticalScrollBarBounds(bounds); 5386 if (bounds.contains((int)x, (int)y)) { 5387 return true; 5388 } 5389 } 5390 if (isHorizontalScrollBarEnabled()) { 5391 final Rect bounds = mScrollCache.mScrollBarBounds; 5392 getHorizontalScrollBarBounds(bounds); 5393 if (bounds.contains((int)x, (int)y)) { 5394 return true; 5395 } 5396 } 5397 return false; 5398 } 5399 5400 boolean isOnScrollbarThumb(float x, float y) { 5401 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5402 } 5403 5404 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5405 if (mScrollCache == null) { 5406 return false; 5407 } 5408 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5409 x += getScrollX(); 5410 y += getScrollY(); 5411 final Rect bounds = mScrollCache.mScrollBarBounds; 5412 getVerticalScrollBarBounds(bounds); 5413 final int range = computeVerticalScrollRange(); 5414 final int offset = computeVerticalScrollOffset(); 5415 final int extent = computeVerticalScrollExtent(); 5416 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5417 extent, range); 5418 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5419 extent, range, offset); 5420 final int thumbTop = bounds.top + thumbOffset; 5421 if (x >= bounds.left && x <= bounds.right && y >= thumbTop 5422 && y <= thumbTop + thumbLength) { 5423 return true; 5424 } 5425 } 5426 return false; 5427 } 5428 5429 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5430 if (mScrollCache == null) { 5431 return false; 5432 } 5433 if (isHorizontalScrollBarEnabled()) { 5434 x += getScrollX(); 5435 y += getScrollY(); 5436 final Rect bounds = mScrollCache.mScrollBarBounds; 5437 getHorizontalScrollBarBounds(bounds); 5438 final int range = computeHorizontalScrollRange(); 5439 final int offset = computeHorizontalScrollOffset(); 5440 final int extent = computeHorizontalScrollExtent(); 5441 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5442 extent, range); 5443 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5444 extent, range, offset); 5445 final int thumbLeft = bounds.left + thumbOffset; 5446 if (x >= thumbLeft && x <= thumbLeft + thumbLength && y >= bounds.top 5447 && y <= bounds.bottom) { 5448 return true; 5449 } 5450 } 5451 return false; 5452 } 5453 5454 boolean isDraggingScrollBar() { 5455 return mScrollCache != null 5456 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5457 } 5458 5459 /** 5460 * Sets the state of all scroll indicators. 5461 * <p> 5462 * See {@link #setScrollIndicators(int, int)} for usage information. 5463 * 5464 * @param indicators a bitmask of indicators that should be enabled, or 5465 * {@code 0} to disable all indicators 5466 * @see #setScrollIndicators(int, int) 5467 * @see #getScrollIndicators() 5468 * @attr ref android.R.styleable#View_scrollIndicators 5469 */ 5470 public void setScrollIndicators(@ScrollIndicators int indicators) { 5471 setScrollIndicators(indicators, 5472 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5473 } 5474 5475 /** 5476 * Sets the state of the scroll indicators specified by the mask. To change 5477 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5478 * <p> 5479 * When a scroll indicator is enabled, it will be displayed if the view 5480 * can scroll in the direction of the indicator. 5481 * <p> 5482 * Multiple indicator types may be enabled or disabled by passing the 5483 * logical OR of the desired types. If multiple types are specified, they 5484 * will all be set to the same enabled state. 5485 * <p> 5486 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5487 * 5488 * @param indicators the indicator direction, or the logical OR of multiple 5489 * indicator directions. One or more of: 5490 * <ul> 5491 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5492 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5493 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5494 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5495 * <li>{@link #SCROLL_INDICATOR_START}</li> 5496 * <li>{@link #SCROLL_INDICATOR_END}</li> 5497 * </ul> 5498 * @see #setScrollIndicators(int) 5499 * @see #getScrollIndicators() 5500 * @attr ref android.R.styleable#View_scrollIndicators 5501 */ 5502 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5503 // Shift and sanitize mask. 5504 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5505 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5506 5507 // Shift and mask indicators. 5508 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5509 indicators &= mask; 5510 5511 // Merge with non-masked flags. 5512 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5513 5514 if (mPrivateFlags3 != updatedFlags) { 5515 mPrivateFlags3 = updatedFlags; 5516 5517 if (indicators != 0) { 5518 initializeScrollIndicatorsInternal(); 5519 } 5520 invalidate(); 5521 } 5522 } 5523 5524 /** 5525 * Returns a bitmask representing the enabled scroll indicators. 5526 * <p> 5527 * For example, if the top and left scroll indicators are enabled and all 5528 * other indicators are disabled, the return value will be 5529 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5530 * <p> 5531 * To check whether the bottom scroll indicator is enabled, use the value 5532 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5533 * 5534 * @return a bitmask representing the enabled scroll indicators 5535 */ 5536 @ScrollIndicators 5537 public int getScrollIndicators() { 5538 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5539 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5540 } 5541 5542 ListenerInfo getListenerInfo() { 5543 if (mListenerInfo != null) { 5544 return mListenerInfo; 5545 } 5546 mListenerInfo = new ListenerInfo(); 5547 return mListenerInfo; 5548 } 5549 5550 /** 5551 * Register a callback to be invoked when the scroll X or Y positions of 5552 * this view change. 5553 * <p> 5554 * <b>Note:</b> Some views handle scrolling independently from View and may 5555 * have their own separate listeners for scroll-type events. For example, 5556 * {@link android.widget.ListView ListView} allows clients to register an 5557 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 5558 * to listen for changes in list scroll position. 5559 * 5560 * @param l The listener to notify when the scroll X or Y position changes. 5561 * @see android.view.View#getScrollX() 5562 * @see android.view.View#getScrollY() 5563 */ 5564 public void setOnScrollChangeListener(OnScrollChangeListener l) { 5565 getListenerInfo().mOnScrollChangeListener = l; 5566 } 5567 5568 /** 5569 * Register a callback to be invoked when focus of this view changed. 5570 * 5571 * @param l The callback that will run. 5572 */ 5573 public void setOnFocusChangeListener(OnFocusChangeListener l) { 5574 getListenerInfo().mOnFocusChangeListener = l; 5575 } 5576 5577 /** 5578 * Add a listener that will be called when the bounds of the view change due to 5579 * layout processing. 5580 * 5581 * @param listener The listener that will be called when layout bounds change. 5582 */ 5583 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 5584 ListenerInfo li = getListenerInfo(); 5585 if (li.mOnLayoutChangeListeners == null) { 5586 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 5587 } 5588 if (!li.mOnLayoutChangeListeners.contains(listener)) { 5589 li.mOnLayoutChangeListeners.add(listener); 5590 } 5591 } 5592 5593 /** 5594 * Remove a listener for layout changes. 5595 * 5596 * @param listener The listener for layout bounds change. 5597 */ 5598 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 5599 ListenerInfo li = mListenerInfo; 5600 if (li == null || li.mOnLayoutChangeListeners == null) { 5601 return; 5602 } 5603 li.mOnLayoutChangeListeners.remove(listener); 5604 } 5605 5606 /** 5607 * Add a listener for attach state changes. 5608 * 5609 * This listener will be called whenever this view is attached or detached 5610 * from a window. Remove the listener using 5611 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 5612 * 5613 * @param listener Listener to attach 5614 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 5615 */ 5616 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5617 ListenerInfo li = getListenerInfo(); 5618 if (li.mOnAttachStateChangeListeners == null) { 5619 li.mOnAttachStateChangeListeners 5620 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 5621 } 5622 li.mOnAttachStateChangeListeners.add(listener); 5623 } 5624 5625 /** 5626 * Remove a listener for attach state changes. The listener will receive no further 5627 * notification of window attach/detach events. 5628 * 5629 * @param listener Listener to remove 5630 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 5631 */ 5632 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5633 ListenerInfo li = mListenerInfo; 5634 if (li == null || li.mOnAttachStateChangeListeners == null) { 5635 return; 5636 } 5637 li.mOnAttachStateChangeListeners.remove(listener); 5638 } 5639 5640 /** 5641 * Returns the focus-change callback registered for this view. 5642 * 5643 * @return The callback, or null if one is not registered. 5644 */ 5645 public OnFocusChangeListener getOnFocusChangeListener() { 5646 ListenerInfo li = mListenerInfo; 5647 return li != null ? li.mOnFocusChangeListener : null; 5648 } 5649 5650 /** 5651 * Register a callback to be invoked when this view is clicked. If this view is not 5652 * clickable, it becomes clickable. 5653 * 5654 * @param l The callback that will run 5655 * 5656 * @see #setClickable(boolean) 5657 */ 5658 public void setOnClickListener(@Nullable OnClickListener l) { 5659 if (!isClickable()) { 5660 setClickable(true); 5661 } 5662 getListenerInfo().mOnClickListener = l; 5663 } 5664 5665 /** 5666 * Return whether this view has an attached OnClickListener. Returns 5667 * true if there is a listener, false if there is none. 5668 */ 5669 public boolean hasOnClickListeners() { 5670 ListenerInfo li = mListenerInfo; 5671 return (li != null && li.mOnClickListener != null); 5672 } 5673 5674 /** 5675 * Register a callback to be invoked when this view is clicked and held. If this view is not 5676 * long clickable, it becomes long clickable. 5677 * 5678 * @param l The callback that will run 5679 * 5680 * @see #setLongClickable(boolean) 5681 */ 5682 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 5683 if (!isLongClickable()) { 5684 setLongClickable(true); 5685 } 5686 getListenerInfo().mOnLongClickListener = l; 5687 } 5688 5689 /** 5690 * Register a callback to be invoked when this view is context clicked. If the view is not 5691 * context clickable, it becomes context clickable. 5692 * 5693 * @param l The callback that will run 5694 * @see #setContextClickable(boolean) 5695 */ 5696 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 5697 if (!isContextClickable()) { 5698 setContextClickable(true); 5699 } 5700 getListenerInfo().mOnContextClickListener = l; 5701 } 5702 5703 /** 5704 * Register a callback to be invoked when the context menu for this view is 5705 * being built. If this view is not long clickable, it becomes long clickable. 5706 * 5707 * @param l The callback that will run 5708 * 5709 */ 5710 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 5711 if (!isLongClickable()) { 5712 setLongClickable(true); 5713 } 5714 getListenerInfo().mOnCreateContextMenuListener = l; 5715 } 5716 5717 /** 5718 * Set an observer to collect stats for each frame rendered for this view. 5719 * 5720 * @hide 5721 */ 5722 public void addFrameMetricsListener(Window window, 5723 Window.OnFrameMetricsAvailableListener listener, 5724 Handler handler) { 5725 if (mAttachInfo != null) { 5726 if (mAttachInfo.mThreadedRenderer != null) { 5727 if (mFrameMetricsObservers == null) { 5728 mFrameMetricsObservers = new ArrayList<>(); 5729 } 5730 5731 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5732 handler.getLooper(), listener); 5733 mFrameMetricsObservers.add(fmo); 5734 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 5735 } else { 5736 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5737 } 5738 } else { 5739 if (mFrameMetricsObservers == null) { 5740 mFrameMetricsObservers = new ArrayList<>(); 5741 } 5742 5743 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5744 handler.getLooper(), listener); 5745 mFrameMetricsObservers.add(fmo); 5746 } 5747 } 5748 5749 /** 5750 * Remove observer configured to collect frame stats for this view. 5751 * 5752 * @hide 5753 */ 5754 public void removeFrameMetricsListener( 5755 Window.OnFrameMetricsAvailableListener listener) { 5756 ThreadedRenderer renderer = getThreadedRenderer(); 5757 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 5758 if (fmo == null) { 5759 throw new IllegalArgumentException( 5760 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 5761 } 5762 5763 if (mFrameMetricsObservers != null) { 5764 mFrameMetricsObservers.remove(fmo); 5765 if (renderer != null) { 5766 renderer.removeFrameMetricsObserver(fmo); 5767 } 5768 } 5769 } 5770 5771 private void registerPendingFrameMetricsObservers() { 5772 if (mFrameMetricsObservers != null) { 5773 ThreadedRenderer renderer = getThreadedRenderer(); 5774 if (renderer != null) { 5775 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 5776 renderer.addFrameMetricsObserver(fmo); 5777 } 5778 } else { 5779 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5780 } 5781 } 5782 } 5783 5784 private FrameMetricsObserver findFrameMetricsObserver( 5785 Window.OnFrameMetricsAvailableListener listener) { 5786 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 5787 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 5788 if (observer.mListener == listener) { 5789 return observer; 5790 } 5791 } 5792 5793 return null; 5794 } 5795 5796 /** 5797 * Call this view's OnClickListener, if it is defined. Performs all normal 5798 * actions associated with clicking: reporting accessibility event, playing 5799 * a sound, etc. 5800 * 5801 * @return True there was an assigned OnClickListener that was called, false 5802 * otherwise is returned. 5803 */ 5804 public boolean performClick() { 5805 final boolean result; 5806 final ListenerInfo li = mListenerInfo; 5807 if (li != null && li.mOnClickListener != null) { 5808 playSoundEffect(SoundEffectConstants.CLICK); 5809 li.mOnClickListener.onClick(this); 5810 result = true; 5811 } else { 5812 result = false; 5813 } 5814 5815 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 5816 return result; 5817 } 5818 5819 /** 5820 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 5821 * this only calls the listener, and does not do any associated clicking 5822 * actions like reporting an accessibility event. 5823 * 5824 * @return True there was an assigned OnClickListener that was called, false 5825 * otherwise is returned. 5826 */ 5827 public boolean callOnClick() { 5828 ListenerInfo li = mListenerInfo; 5829 if (li != null && li.mOnClickListener != null) { 5830 li.mOnClickListener.onClick(this); 5831 return true; 5832 } 5833 return false; 5834 } 5835 5836 /** 5837 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5838 * context menu if the OnLongClickListener did not consume the event. 5839 * 5840 * @return {@code true} if one of the above receivers consumed the event, 5841 * {@code false} otherwise 5842 */ 5843 public boolean performLongClick() { 5844 return performLongClickInternal(mLongClickX, mLongClickY); 5845 } 5846 5847 /** 5848 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5849 * context menu if the OnLongClickListener did not consume the event, 5850 * anchoring it to an (x,y) coordinate. 5851 * 5852 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5853 * to disable anchoring 5854 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5855 * to disable anchoring 5856 * @return {@code true} if one of the above receivers consumed the event, 5857 * {@code false} otherwise 5858 */ 5859 public boolean performLongClick(float x, float y) { 5860 mLongClickX = x; 5861 mLongClickY = y; 5862 final boolean handled = performLongClick(); 5863 mLongClickX = Float.NaN; 5864 mLongClickY = Float.NaN; 5865 return handled; 5866 } 5867 5868 /** 5869 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5870 * context menu if the OnLongClickListener did not consume the event, 5871 * optionally anchoring it to an (x,y) coordinate. 5872 * 5873 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5874 * to disable anchoring 5875 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5876 * to disable anchoring 5877 * @return {@code true} if one of the above receivers consumed the event, 5878 * {@code false} otherwise 5879 */ 5880 private boolean performLongClickInternal(float x, float y) { 5881 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 5882 5883 boolean handled = false; 5884 final ListenerInfo li = mListenerInfo; 5885 if (li != null && li.mOnLongClickListener != null) { 5886 handled = li.mOnLongClickListener.onLongClick(View.this); 5887 } 5888 if (!handled) { 5889 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 5890 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 5891 } 5892 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 5893 if (!handled) { 5894 handled = showLongClickTooltip((int) x, (int) y); 5895 } 5896 } 5897 if (handled) { 5898 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 5899 } 5900 return handled; 5901 } 5902 5903 /** 5904 * Call this view's OnContextClickListener, if it is defined. 5905 * 5906 * @param x the x coordinate of the context click 5907 * @param y the y coordinate of the context click 5908 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5909 * otherwise. 5910 */ 5911 public boolean performContextClick(float x, float y) { 5912 return performContextClick(); 5913 } 5914 5915 /** 5916 * Call this view's OnContextClickListener, if it is defined. 5917 * 5918 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5919 * otherwise. 5920 */ 5921 public boolean performContextClick() { 5922 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 5923 5924 boolean handled = false; 5925 ListenerInfo li = mListenerInfo; 5926 if (li != null && li.mOnContextClickListener != null) { 5927 handled = li.mOnContextClickListener.onContextClick(View.this); 5928 } 5929 if (handled) { 5930 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 5931 } 5932 return handled; 5933 } 5934 5935 /** 5936 * Performs button-related actions during a touch down event. 5937 * 5938 * @param event The event. 5939 * @return True if the down was consumed. 5940 * 5941 * @hide 5942 */ 5943 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 5944 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 5945 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 5946 showContextMenu(event.getX(), event.getY()); 5947 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 5948 return true; 5949 } 5950 return false; 5951 } 5952 5953 /** 5954 * Shows the context menu for this view. 5955 * 5956 * @return {@code true} if the context menu was shown, {@code false} 5957 * otherwise 5958 * @see #showContextMenu(float, float) 5959 */ 5960 public boolean showContextMenu() { 5961 return getParent().showContextMenuForChild(this); 5962 } 5963 5964 /** 5965 * Shows the context menu for this view anchored to the specified 5966 * view-relative coordinate. 5967 * 5968 * @param x the X coordinate in pixels relative to the view to which the 5969 * menu should be anchored, or {@link Float#NaN} to disable anchoring 5970 * @param y the Y coordinate in pixels relative to the view to which the 5971 * menu should be anchored, or {@link Float#NaN} to disable anchoring 5972 * @return {@code true} if the context menu was shown, {@code false} 5973 * otherwise 5974 */ 5975 public boolean showContextMenu(float x, float y) { 5976 return getParent().showContextMenuForChild(this, x, y); 5977 } 5978 5979 /** 5980 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 5981 * 5982 * @param callback Callback that will control the lifecycle of the action mode 5983 * @return The new action mode if it is started, null otherwise 5984 * 5985 * @see ActionMode 5986 * @see #startActionMode(android.view.ActionMode.Callback, int) 5987 */ 5988 public ActionMode startActionMode(ActionMode.Callback callback) { 5989 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 5990 } 5991 5992 /** 5993 * Start an action mode with the given type. 5994 * 5995 * @param callback Callback that will control the lifecycle of the action mode 5996 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 5997 * @return The new action mode if it is started, null otherwise 5998 * 5999 * @see ActionMode 6000 */ 6001 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6002 ViewParent parent = getParent(); 6003 if (parent == null) return null; 6004 try { 6005 return parent.startActionModeForChild(this, callback, type); 6006 } catch (AbstractMethodError ame) { 6007 // Older implementations of custom views might not implement this. 6008 return parent.startActionModeForChild(this, callback); 6009 } 6010 } 6011 6012 /** 6013 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6014 * Context, creating a unique View identifier to retrieve the result. 6015 * 6016 * @param intent The Intent to be started. 6017 * @param requestCode The request code to use. 6018 * @hide 6019 */ 6020 public void startActivityForResult(Intent intent, int requestCode) { 6021 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6022 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6023 } 6024 6025 /** 6026 * If this View corresponds to the calling who, dispatches the activity result. 6027 * @param who The identifier for the targeted View to receive the result. 6028 * @param requestCode The integer request code originally supplied to 6029 * startActivityForResult(), allowing you to identify who this 6030 * result came from. 6031 * @param resultCode The integer result code returned by the child activity 6032 * through its setResult(). 6033 * @param data An Intent, which can return result data to the caller 6034 * (various data can be attached to Intent "extras"). 6035 * @return {@code true} if the activity result was dispatched. 6036 * @hide 6037 */ 6038 public boolean dispatchActivityResult( 6039 String who, int requestCode, int resultCode, Intent data) { 6040 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6041 onActivityResult(requestCode, resultCode, data); 6042 mStartActivityRequestWho = null; 6043 return true; 6044 } 6045 return false; 6046 } 6047 6048 /** 6049 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6050 * 6051 * @param requestCode The integer request code originally supplied to 6052 * startActivityForResult(), allowing you to identify who this 6053 * result came from. 6054 * @param resultCode The integer result code returned by the child activity 6055 * through its setResult(). 6056 * @param data An Intent, which can return result data to the caller 6057 * (various data can be attached to Intent "extras"). 6058 * @hide 6059 */ 6060 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6061 // Do nothing. 6062 } 6063 6064 /** 6065 * Register a callback to be invoked when a hardware key is pressed in this view. 6066 * Key presses in software input methods will generally not trigger the methods of 6067 * this listener. 6068 * @param l the key listener to attach to this view 6069 */ 6070 public void setOnKeyListener(OnKeyListener l) { 6071 getListenerInfo().mOnKeyListener = l; 6072 } 6073 6074 /** 6075 * Register a callback to be invoked when a touch event is sent to this view. 6076 * @param l the touch listener to attach to this view 6077 */ 6078 public void setOnTouchListener(OnTouchListener l) { 6079 getListenerInfo().mOnTouchListener = l; 6080 } 6081 6082 /** 6083 * Register a callback to be invoked when a generic motion event is sent to this view. 6084 * @param l the generic motion listener to attach to this view 6085 */ 6086 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6087 getListenerInfo().mOnGenericMotionListener = l; 6088 } 6089 6090 /** 6091 * Register a callback to be invoked when a hover event is sent to this view. 6092 * @param l the hover listener to attach to this view 6093 */ 6094 public void setOnHoverListener(OnHoverListener l) { 6095 getListenerInfo().mOnHoverListener = l; 6096 } 6097 6098 /** 6099 * Register a drag event listener callback object for this View. The parameter is 6100 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6101 * View, the system calls the 6102 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6103 * @param l An implementation of {@link android.view.View.OnDragListener}. 6104 */ 6105 public void setOnDragListener(OnDragListener l) { 6106 getListenerInfo().mOnDragListener = l; 6107 } 6108 6109 /** 6110 * Give this view focus. This will cause 6111 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6112 * 6113 * Note: this does not check whether this {@link View} should get focus, it just 6114 * gives it focus no matter what. It should only be called internally by framework 6115 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6116 * 6117 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6118 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6119 * focus moved when requestFocus() is called. It may not always 6120 * apply, in which case use the default View.FOCUS_DOWN. 6121 * @param previouslyFocusedRect The rectangle of the view that had focus 6122 * prior in this View's coordinate system. 6123 */ 6124 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6125 if (DBG) { 6126 System.out.println(this + " requestFocus()"); 6127 } 6128 6129 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6130 mPrivateFlags |= PFLAG_FOCUSED; 6131 6132 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6133 6134 if (mParent != null) { 6135 mParent.requestChildFocus(this, this); 6136 if (!isKeyboardNavigationCluster() && mParent instanceof ViewGroup) { 6137 ((ViewGroup) mParent).saveFocus(); 6138 } 6139 } 6140 6141 if (mAttachInfo != null) { 6142 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6143 } 6144 6145 onFocusChanged(true, direction, previouslyFocusedRect); 6146 refreshDrawableState(); 6147 } 6148 } 6149 6150 /** 6151 * Sets this view's preference for reveal behavior when it gains focus. 6152 * 6153 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6154 * this view would prefer to be brought fully into view when it gains focus. 6155 * For example, a text field that a user is meant to type into. Other views such 6156 * as scrolling containers may prefer to opt-out of this behavior.</p> 6157 * 6158 * <p>The default value for views is true, though subclasses may change this 6159 * based on their preferred behavior.</p> 6160 * 6161 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6162 * 6163 * @see #getRevealOnFocusHint() 6164 */ 6165 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6166 if (revealOnFocus) { 6167 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6168 } else { 6169 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6170 } 6171 } 6172 6173 /** 6174 * Returns this view's preference for reveal behavior when it gains focus. 6175 * 6176 * <p>When this method returns true for a child view requesting focus, ancestor 6177 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6178 * should make a best effort to make the newly focused child fully visible to the user. 6179 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6180 * other properties affecting visibility to the user as part of the focus change.</p> 6181 * 6182 * @return true if this view would prefer to become fully visible when it gains focus, 6183 * false if it would prefer not to disrupt scroll positioning 6184 * 6185 * @see #setRevealOnFocusHint(boolean) 6186 */ 6187 public final boolean getRevealOnFocusHint() { 6188 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6189 } 6190 6191 /** 6192 * Populates <code>outRect</code> with the hotspot bounds. By default, 6193 * the hotspot bounds are identical to the screen bounds. 6194 * 6195 * @param outRect rect to populate with hotspot bounds 6196 * @hide Only for internal use by views and widgets. 6197 */ 6198 public void getHotspotBounds(Rect outRect) { 6199 final Drawable background = getBackground(); 6200 if (background != null) { 6201 background.getHotspotBounds(outRect); 6202 } else { 6203 getBoundsOnScreen(outRect); 6204 } 6205 } 6206 6207 /** 6208 * Request that a rectangle of this view be visible on the screen, 6209 * scrolling if necessary just enough. 6210 * 6211 * <p>A View should call this if it maintains some notion of which part 6212 * of its content is interesting. For example, a text editing view 6213 * should call this when its cursor moves. 6214 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6215 * It should not be affected by which part of the View is currently visible or its scroll 6216 * position. 6217 * 6218 * @param rectangle The rectangle in the View's content coordinate space 6219 * @return Whether any parent scrolled. 6220 */ 6221 public boolean requestRectangleOnScreen(Rect rectangle) { 6222 return requestRectangleOnScreen(rectangle, false); 6223 } 6224 6225 /** 6226 * Request that a rectangle of this view be visible on the screen, 6227 * scrolling if necessary just enough. 6228 * 6229 * <p>A View should call this if it maintains some notion of which part 6230 * of its content is interesting. For example, a text editing view 6231 * should call this when its cursor moves. 6232 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6233 * It should not be affected by which part of the View is currently visible or its scroll 6234 * position. 6235 * <p>When <code>immediate</code> is set to true, scrolling will not be 6236 * animated. 6237 * 6238 * @param rectangle The rectangle in the View's content coordinate space 6239 * @param immediate True to forbid animated scrolling, false otherwise 6240 * @return Whether any parent scrolled. 6241 */ 6242 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6243 if (mParent == null) { 6244 return false; 6245 } 6246 6247 View child = this; 6248 6249 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6250 position.set(rectangle); 6251 6252 ViewParent parent = mParent; 6253 boolean scrolled = false; 6254 while (parent != null) { 6255 rectangle.set((int) position.left, (int) position.top, 6256 (int) position.right, (int) position.bottom); 6257 6258 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6259 6260 if (!(parent instanceof View)) { 6261 break; 6262 } 6263 6264 // move it from child's content coordinate space to parent's content coordinate space 6265 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6266 6267 child = (View) parent; 6268 parent = child.getParent(); 6269 } 6270 6271 return scrolled; 6272 } 6273 6274 /** 6275 * Called when this view wants to give up focus. If focus is cleared 6276 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6277 * <p> 6278 * <strong>Note:</strong> When a View clears focus the framework is trying 6279 * to give focus to the first focusable View from the top. Hence, if this 6280 * View is the first from the top that can take focus, then all callbacks 6281 * related to clearing focus will be invoked after which the framework will 6282 * give focus to this view. 6283 * </p> 6284 */ 6285 public void clearFocus() { 6286 if (DBG) { 6287 System.out.println(this + " clearFocus()"); 6288 } 6289 6290 clearFocusInternal(null, true, true); 6291 } 6292 6293 /** 6294 * Clears focus from the view, optionally propagating the change up through 6295 * the parent hierarchy and requesting that the root view place new focus. 6296 * 6297 * @param propagate whether to propagate the change up through the parent 6298 * hierarchy 6299 * @param refocus when propagate is true, specifies whether to request the 6300 * root view place new focus 6301 */ 6302 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6303 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6304 mPrivateFlags &= ~PFLAG_FOCUSED; 6305 6306 if (propagate && mParent != null) { 6307 mParent.clearChildFocus(this); 6308 } 6309 6310 onFocusChanged(false, 0, null); 6311 refreshDrawableState(); 6312 6313 if (propagate && (!refocus || !rootViewRequestFocus())) { 6314 notifyGlobalFocusCleared(this); 6315 } 6316 } 6317 } 6318 6319 void notifyGlobalFocusCleared(View oldFocus) { 6320 if (oldFocus != null && mAttachInfo != null) { 6321 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6322 } 6323 } 6324 6325 boolean rootViewRequestFocus() { 6326 final View root = getRootView(); 6327 return root != null && root.requestFocus(); 6328 } 6329 6330 /** 6331 * Called internally by the view system when a new view is getting focus. 6332 * This is what clears the old focus. 6333 * <p> 6334 * <b>NOTE:</b> The parent view's focused child must be updated manually 6335 * after calling this method. Otherwise, the view hierarchy may be left in 6336 * an inconstent state. 6337 */ 6338 void unFocus(View focused) { 6339 if (DBG) { 6340 System.out.println(this + " unFocus()"); 6341 } 6342 6343 clearFocusInternal(focused, false, false); 6344 } 6345 6346 /** 6347 * Returns true if this view has focus itself, or is the ancestor of the 6348 * view that has focus. 6349 * 6350 * @return True if this view has or contains focus, false otherwise. 6351 */ 6352 @ViewDebug.ExportedProperty(category = "focus") 6353 public boolean hasFocus() { 6354 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6355 } 6356 6357 /** 6358 * Returns true if this view is focusable or if it contains a reachable View 6359 * for which {@link #hasFocusable()} returns true. A "reachable hasFocusable()" 6360 * is a View whose parents do not block descendants focus. 6361 * 6362 * Only {@link #VISIBLE} views are considered focusable. 6363 * 6364 * @return True if the view is focusable or if the view contains a focusable 6365 * View, false otherwise. 6366 * 6367 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6368 * @see ViewGroup#getTouchscreenBlocksFocus() 6369 */ 6370 public boolean hasFocusable() { 6371 if (!isFocusableInTouchMode()) { 6372 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6373 final ViewGroup g = (ViewGroup) p; 6374 if (g.shouldBlockFocusForTouchscreen()) { 6375 return false; 6376 } 6377 } 6378 } 6379 return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable(); 6380 } 6381 6382 /** 6383 * Called by the view system when the focus state of this view changes. 6384 * When the focus change event is caused by directional navigation, direction 6385 * and previouslyFocusedRect provide insight into where the focus is coming from. 6386 * When overriding, be sure to call up through to the super class so that 6387 * the standard focus handling will occur. 6388 * 6389 * @param gainFocus True if the View has focus; false otherwise. 6390 * @param direction The direction focus has moved when requestFocus() 6391 * is called to give this view focus. Values are 6392 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6393 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6394 * It may not always apply, in which case use the default. 6395 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6396 * system, of the previously focused view. If applicable, this will be 6397 * passed in as finer grained information about where the focus is coming 6398 * from (in addition to direction). Will be <code>null</code> otherwise. 6399 */ 6400 @CallSuper 6401 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6402 @Nullable Rect previouslyFocusedRect) { 6403 if (gainFocus) { 6404 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6405 } else { 6406 notifyViewAccessibilityStateChangedIfNeeded( 6407 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6408 } 6409 6410 InputMethodManager imm = InputMethodManager.peekInstance(); 6411 if (!gainFocus) { 6412 if (isPressed()) { 6413 setPressed(false); 6414 } 6415 if (imm != null && mAttachInfo != null 6416 && mAttachInfo.mHasWindowFocus) { 6417 imm.focusOut(this); 6418 } 6419 onFocusLost(); 6420 } else if (imm != null && mAttachInfo != null 6421 && mAttachInfo.mHasWindowFocus) { 6422 imm.focusIn(this); 6423 } 6424 6425 invalidate(true); 6426 ListenerInfo li = mListenerInfo; 6427 if (li != null && li.mOnFocusChangeListener != null) { 6428 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6429 } 6430 6431 if (mAttachInfo != null) { 6432 mAttachInfo.mKeyDispatchState.reset(this); 6433 } 6434 } 6435 6436 /** 6437 * Sends an accessibility event of the given type. If accessibility is 6438 * not enabled this method has no effect. The default implementation calls 6439 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6440 * to populate information about the event source (this View), then calls 6441 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6442 * populate the text content of the event source including its descendants, 6443 * and last calls 6444 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6445 * on its parent to request sending of the event to interested parties. 6446 * <p> 6447 * If an {@link AccessibilityDelegate} has been specified via calling 6448 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6449 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6450 * responsible for handling this call. 6451 * </p> 6452 * 6453 * @param eventType The type of the event to send, as defined by several types from 6454 * {@link android.view.accessibility.AccessibilityEvent}, such as 6455 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6456 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6457 * 6458 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6459 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6460 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6461 * @see AccessibilityDelegate 6462 */ 6463 public void sendAccessibilityEvent(int eventType) { 6464 if (mAccessibilityDelegate != null) { 6465 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6466 } else { 6467 sendAccessibilityEventInternal(eventType); 6468 } 6469 } 6470 6471 /** 6472 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6473 * {@link AccessibilityEvent} to make an announcement which is related to some 6474 * sort of a context change for which none of the events representing UI transitions 6475 * is a good fit. For example, announcing a new page in a book. If accessibility 6476 * is not enabled this method does nothing. 6477 * 6478 * @param text The announcement text. 6479 */ 6480 public void announceForAccessibility(CharSequence text) { 6481 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6482 AccessibilityEvent event = AccessibilityEvent.obtain( 6483 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6484 onInitializeAccessibilityEvent(event); 6485 event.getText().add(text); 6486 event.setContentDescription(null); 6487 mParent.requestSendAccessibilityEvent(this, event); 6488 } 6489 } 6490 6491 /** 6492 * @see #sendAccessibilityEvent(int) 6493 * 6494 * Note: Called from the default {@link AccessibilityDelegate}. 6495 * 6496 * @hide 6497 */ 6498 public void sendAccessibilityEventInternal(int eventType) { 6499 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 6500 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 6501 } 6502 } 6503 6504 /** 6505 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 6506 * takes as an argument an empty {@link AccessibilityEvent} and does not 6507 * perform a check whether accessibility is enabled. 6508 * <p> 6509 * If an {@link AccessibilityDelegate} has been specified via calling 6510 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6511 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 6512 * is responsible for handling this call. 6513 * </p> 6514 * 6515 * @param event The event to send. 6516 * 6517 * @see #sendAccessibilityEvent(int) 6518 */ 6519 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 6520 if (mAccessibilityDelegate != null) { 6521 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 6522 } else { 6523 sendAccessibilityEventUncheckedInternal(event); 6524 } 6525 } 6526 6527 /** 6528 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 6529 * 6530 * Note: Called from the default {@link AccessibilityDelegate}. 6531 * 6532 * @hide 6533 */ 6534 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 6535 if (!isShown()) { 6536 return; 6537 } 6538 onInitializeAccessibilityEvent(event); 6539 // Only a subset of accessibility events populates text content. 6540 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 6541 dispatchPopulateAccessibilityEvent(event); 6542 } 6543 // In the beginning we called #isShown(), so we know that getParent() is not null. 6544 getParent().requestSendAccessibilityEvent(this, event); 6545 } 6546 6547 /** 6548 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 6549 * to its children for adding their text content to the event. Note that the 6550 * event text is populated in a separate dispatch path since we add to the 6551 * event not only the text of the source but also the text of all its descendants. 6552 * A typical implementation will call 6553 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 6554 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6555 * on each child. Override this method if custom population of the event text 6556 * content is required. 6557 * <p> 6558 * If an {@link AccessibilityDelegate} has been specified via calling 6559 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6560 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 6561 * is responsible for handling this call. 6562 * </p> 6563 * <p> 6564 * <em>Note:</em> Accessibility events of certain types are not dispatched for 6565 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 6566 * </p> 6567 * 6568 * @param event The event. 6569 * 6570 * @return True if the event population was completed. 6571 */ 6572 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 6573 if (mAccessibilityDelegate != null) { 6574 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 6575 } else { 6576 return dispatchPopulateAccessibilityEventInternal(event); 6577 } 6578 } 6579 6580 /** 6581 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6582 * 6583 * Note: Called from the default {@link AccessibilityDelegate}. 6584 * 6585 * @hide 6586 */ 6587 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6588 onPopulateAccessibilityEvent(event); 6589 return false; 6590 } 6591 6592 /** 6593 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6594 * giving a chance to this View to populate the accessibility event with its 6595 * text content. While this method is free to modify event 6596 * attributes other than text content, doing so should normally be performed in 6597 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 6598 * <p> 6599 * Example: Adding formatted date string to an accessibility event in addition 6600 * to the text added by the super implementation: 6601 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6602 * super.onPopulateAccessibilityEvent(event); 6603 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 6604 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 6605 * mCurrentDate.getTimeInMillis(), flags); 6606 * event.getText().add(selectedDateUtterance); 6607 * }</pre> 6608 * <p> 6609 * If an {@link AccessibilityDelegate} has been specified via calling 6610 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6611 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 6612 * is responsible for handling this call. 6613 * </p> 6614 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6615 * information to the event, in case the default implementation has basic information to add. 6616 * </p> 6617 * 6618 * @param event The accessibility event which to populate. 6619 * 6620 * @see #sendAccessibilityEvent(int) 6621 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6622 */ 6623 @CallSuper 6624 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6625 if (mAccessibilityDelegate != null) { 6626 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 6627 } else { 6628 onPopulateAccessibilityEventInternal(event); 6629 } 6630 } 6631 6632 /** 6633 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 6634 * 6635 * Note: Called from the default {@link AccessibilityDelegate}. 6636 * 6637 * @hide 6638 */ 6639 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6640 } 6641 6642 /** 6643 * Initializes an {@link AccessibilityEvent} with information about 6644 * this View which is the event source. In other words, the source of 6645 * an accessibility event is the view whose state change triggered firing 6646 * the event. 6647 * <p> 6648 * Example: Setting the password property of an event in addition 6649 * to properties set by the super implementation: 6650 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6651 * super.onInitializeAccessibilityEvent(event); 6652 * event.setPassword(true); 6653 * }</pre> 6654 * <p> 6655 * If an {@link AccessibilityDelegate} has been specified via calling 6656 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6657 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 6658 * is responsible for handling this call. 6659 * </p> 6660 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6661 * information to the event, in case the default implementation has basic information to add. 6662 * </p> 6663 * @param event The event to initialize. 6664 * 6665 * @see #sendAccessibilityEvent(int) 6666 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6667 */ 6668 @CallSuper 6669 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6670 if (mAccessibilityDelegate != null) { 6671 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 6672 } else { 6673 onInitializeAccessibilityEventInternal(event); 6674 } 6675 } 6676 6677 /** 6678 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6679 * 6680 * Note: Called from the default {@link AccessibilityDelegate}. 6681 * 6682 * @hide 6683 */ 6684 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 6685 event.setSource(this); 6686 event.setClassName(getAccessibilityClassName()); 6687 event.setPackageName(getContext().getPackageName()); 6688 event.setEnabled(isEnabled()); 6689 event.setContentDescription(mContentDescription); 6690 6691 switch (event.getEventType()) { 6692 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 6693 ArrayList<View> focusablesTempList = (mAttachInfo != null) 6694 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 6695 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 6696 event.setItemCount(focusablesTempList.size()); 6697 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 6698 if (mAttachInfo != null) { 6699 focusablesTempList.clear(); 6700 } 6701 } break; 6702 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 6703 CharSequence text = getIterableTextForAccessibility(); 6704 if (text != null && text.length() > 0) { 6705 event.setFromIndex(getAccessibilitySelectionStart()); 6706 event.setToIndex(getAccessibilitySelectionEnd()); 6707 event.setItemCount(text.length()); 6708 } 6709 } break; 6710 } 6711 } 6712 6713 /** 6714 * Returns an {@link AccessibilityNodeInfo} representing this view from the 6715 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 6716 * This method is responsible for obtaining an accessibility node info from a 6717 * pool of reusable instances and calling 6718 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 6719 * initialize the former. 6720 * <p> 6721 * Note: The client is responsible for recycling the obtained instance by calling 6722 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 6723 * </p> 6724 * 6725 * @return A populated {@link AccessibilityNodeInfo}. 6726 * 6727 * @see AccessibilityNodeInfo 6728 */ 6729 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 6730 if (mAccessibilityDelegate != null) { 6731 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 6732 } else { 6733 return createAccessibilityNodeInfoInternal(); 6734 } 6735 } 6736 6737 /** 6738 * @see #createAccessibilityNodeInfo() 6739 * 6740 * @hide 6741 */ 6742 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 6743 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 6744 if (provider != null) { 6745 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 6746 } else { 6747 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 6748 onInitializeAccessibilityNodeInfo(info); 6749 return info; 6750 } 6751 } 6752 6753 /** 6754 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 6755 * The base implementation sets: 6756 * <ul> 6757 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 6758 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 6759 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 6760 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 6761 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 6762 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 6763 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 6764 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 6765 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 6766 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 6767 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 6768 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 6769 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 6770 * </ul> 6771 * <p> 6772 * Subclasses should override this method, call the super implementation, 6773 * and set additional attributes. 6774 * </p> 6775 * <p> 6776 * If an {@link AccessibilityDelegate} has been specified via calling 6777 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6778 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 6779 * is responsible for handling this call. 6780 * </p> 6781 * 6782 * @param info The instance to initialize. 6783 */ 6784 @CallSuper 6785 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 6786 if (mAccessibilityDelegate != null) { 6787 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 6788 } else { 6789 onInitializeAccessibilityNodeInfoInternal(info); 6790 } 6791 } 6792 6793 /** 6794 * Gets the location of this view in screen coordinates. 6795 * 6796 * @param outRect The output location 6797 * @hide 6798 */ 6799 public void getBoundsOnScreen(Rect outRect) { 6800 getBoundsOnScreen(outRect, false); 6801 } 6802 6803 /** 6804 * Gets the location of this view in screen coordinates. 6805 * 6806 * @param outRect The output location 6807 * @param clipToParent Whether to clip child bounds to the parent ones. 6808 * @hide 6809 */ 6810 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 6811 if (mAttachInfo == null) { 6812 return; 6813 } 6814 6815 RectF position = mAttachInfo.mTmpTransformRect; 6816 position.set(0, 0, mRight - mLeft, mBottom - mTop); 6817 6818 if (!hasIdentityMatrix()) { 6819 getMatrix().mapRect(position); 6820 } 6821 6822 position.offset(mLeft, mTop); 6823 6824 ViewParent parent = mParent; 6825 while (parent instanceof View) { 6826 View parentView = (View) parent; 6827 6828 position.offset(-parentView.mScrollX, -parentView.mScrollY); 6829 6830 if (clipToParent) { 6831 position.left = Math.max(position.left, 0); 6832 position.top = Math.max(position.top, 0); 6833 position.right = Math.min(position.right, parentView.getWidth()); 6834 position.bottom = Math.min(position.bottom, parentView.getHeight()); 6835 } 6836 6837 if (!parentView.hasIdentityMatrix()) { 6838 parentView.getMatrix().mapRect(position); 6839 } 6840 6841 position.offset(parentView.mLeft, parentView.mTop); 6842 6843 parent = parentView.mParent; 6844 } 6845 6846 if (parent instanceof ViewRootImpl) { 6847 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 6848 position.offset(0, -viewRootImpl.mCurScrollY); 6849 } 6850 6851 position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 6852 6853 outRect.set(Math.round(position.left), Math.round(position.top), 6854 Math.round(position.right), Math.round(position.bottom)); 6855 } 6856 6857 /** 6858 * Return the class name of this object to be used for accessibility purposes. 6859 * Subclasses should only override this if they are implementing something that 6860 * should be seen as a completely new class of view when used by accessibility, 6861 * unrelated to the class it is deriving from. This is used to fill in 6862 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 6863 */ 6864 public CharSequence getAccessibilityClassName() { 6865 return View.class.getName(); 6866 } 6867 6868 /** 6869 * Called when assist structure is being retrieved from a view as part of 6870 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 6871 * @param structure Fill in with structured view data. The default implementation 6872 * fills in all data that can be inferred from the view itself. 6873 * 6874 * @deprecated As of API O sub-classes should override 6875 * {@link #onProvideStructure(ViewStructure, int)} instead. 6876 */ 6877 // TODO(b/33197203): set proper API above 6878 @Deprecated 6879 public void onProvideStructure(ViewStructure structure) { 6880 onProvideStructure(structure, 0); 6881 } 6882 6883 /** 6884 * Called when assist structure is being retrieved from a view as part of 6885 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} or as part 6886 * of an auto-fill request. 6887 * 6888 * <p>The default implementation fills in all data that can be inferred from the view itself. 6889 * 6890 * <p>The structure must be filled according to the request type, which is set in the 6891 * {@code flags} parameter - see the documentation on each flag for more details. 6892 * 6893 * @param structure Fill in with structured view data. The default implementation 6894 * fills in all data that can be inferred from the view itself. 6895 * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and 6896 * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info). 6897 */ 6898 public void onProvideStructure(ViewStructure structure, int flags) { 6899 boolean forAutoFill = (flags 6900 & (View.ASSIST_FLAG_SANITIZED_TEXT 6901 | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0; 6902 final int id = mID; 6903 if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0 6904 && (id&0x0000ffff) != 0) { 6905 String pkg, type, entry; 6906 try { 6907 final Resources res = getResources(); 6908 entry = res.getResourceEntryName(id); 6909 type = res.getResourceTypeName(id); 6910 pkg = res.getResourcePackageName(id); 6911 } catch (Resources.NotFoundException e) { 6912 entry = type = pkg = null; 6913 } 6914 structure.setId(id, pkg, type, entry); 6915 } else { 6916 structure.setId(id, null, null, null); 6917 } 6918 6919 if (forAutoFill) { 6920 // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to 6921 // reuse the accessibility id to save space. 6922 structure.setAutoFillId(getAccessibilityViewId()); 6923 } 6924 6925 structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop); 6926 if (!hasIdentityMatrix()) { 6927 structure.setTransformation(getMatrix()); 6928 } 6929 structure.setElevation(getZ()); 6930 structure.setVisibility(getVisibility()); 6931 structure.setEnabled(isEnabled()); 6932 if (isClickable()) { 6933 structure.setClickable(true); 6934 } 6935 if (isFocusable()) { 6936 structure.setFocusable(true); 6937 } 6938 if (isFocused()) { 6939 structure.setFocused(true); 6940 } 6941 if (isAccessibilityFocused()) { 6942 structure.setAccessibilityFocused(true); 6943 } 6944 if (isSelected()) { 6945 structure.setSelected(true); 6946 } 6947 if (isActivated()) { 6948 structure.setActivated(true); 6949 } 6950 if (isLongClickable()) { 6951 structure.setLongClickable(true); 6952 } 6953 if (this instanceof Checkable) { 6954 structure.setCheckable(true); 6955 if (((Checkable)this).isChecked()) { 6956 structure.setChecked(true); 6957 } 6958 } 6959 if (isContextClickable()) { 6960 structure.setContextClickable(true); 6961 } 6962 structure.setClassName(getAccessibilityClassName().toString()); 6963 structure.setContentDescription(getContentDescription()); 6964 } 6965 6966 /** 6967 * Called when assist structure is being retrieved from a view as part of 6968 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 6969 * generate additional virtual structure under this view. The defaullt implementation 6970 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 6971 * view's virtual accessibility nodes, if any. You can override this for a more 6972 * optimal implementation providing this data. 6973 * 6974 * @deprecated As of API O, sub-classes should override 6975 * {@link #onProvideVirtualStructure(ViewStructure, int)} instead. 6976 */ 6977 // TODO(b/33197203): set proper API above 6978 @Deprecated 6979 public void onProvideVirtualStructure(ViewStructure structure) { 6980 onProvideVirtualStructure(structure, 0); 6981 } 6982 6983 /** 6984 * Called when assist structure is being retrieved from a view as part of 6985 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} or as part 6986 * of an auto-fill request to generate additional virtual structure under this view. 6987 * 6988 * <p>The defaullt implementation uses {@link #getAccessibilityNodeProvider()} to try to 6989 * generate this from the view's virtual accessibility nodes, if any. You can override this 6990 * for a more optimal implementation providing this data. 6991 * 6992 * <p>The structure must be filled according to the request type, which is set in the 6993 * {@code flags} parameter - see the documentation on each flag for more details. 6994 * 6995 * @param structure Fill in with structured view data. 6996 * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and 6997 * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info). 6998 */ 6999 public void onProvideVirtualStructure(ViewStructure structure, int flags) { 7000 boolean sanitize = (flags & View.ASSIST_FLAG_SANITIZED_TEXT) != 0; 7001 7002 if (sanitize) { 7003 // TODO(b/33197203): change populateVirtualStructure so it sanitizes data in this case. 7004 return; 7005 } 7006 7007 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7008 if (provider != null) { 7009 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7010 structure.setChildCount(1); 7011 ViewStructure root = structure.newChild(0); 7012 populateVirtualStructure(root, provider, info, flags); 7013 info.recycle(); 7014 } 7015 } 7016 7017 private void populateVirtualStructure(ViewStructure structure, 7018 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, int flags) { 7019 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 7020 null, null, null); 7021 Rect rect = structure.getTempRect(); 7022 info.getBoundsInParent(rect); 7023 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 7024 structure.setVisibility(VISIBLE); 7025 structure.setEnabled(info.isEnabled()); 7026 if (info.isClickable()) { 7027 structure.setClickable(true); 7028 } 7029 if (info.isFocusable()) { 7030 structure.setFocusable(true); 7031 } 7032 if (info.isFocused()) { 7033 structure.setFocused(true); 7034 } 7035 if (info.isAccessibilityFocused()) { 7036 structure.setAccessibilityFocused(true); 7037 } 7038 if (info.isSelected()) { 7039 structure.setSelected(true); 7040 } 7041 if (info.isLongClickable()) { 7042 structure.setLongClickable(true); 7043 } 7044 if (info.isCheckable()) { 7045 structure.setCheckable(true); 7046 if (info.isChecked()) { 7047 structure.setChecked(true); 7048 } 7049 } 7050 if (info.isContextClickable()) { 7051 structure.setContextClickable(true); 7052 } 7053 CharSequence cname = info.getClassName(); 7054 structure.setClassName(cname != null ? cname.toString() : null); 7055 structure.setContentDescription(info.getContentDescription()); 7056 if (info.getText() != null || info.getError() != null) { 7057 structure.setText(info.getText(), info.getTextSelectionStart(), 7058 info.getTextSelectionEnd()); 7059 } 7060 final int NCHILDREN = info.getChildCount(); 7061 if (NCHILDREN > 0) { 7062 structure.setChildCount(NCHILDREN); 7063 for (int i=0; i<NCHILDREN; i++) { 7064 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 7065 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 7066 ViewStructure child = structure.newChild(i); 7067 populateVirtualStructure(child, provider, cinfo, flags); 7068 cinfo.recycle(); 7069 } 7070 } 7071 } 7072 7073 /** 7074 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 7075 * implementation calls {@link #onProvideStructure} and 7076 * {@link #onProvideVirtualStructure}. 7077 * 7078 * @deprecated As of API O, sub-classes should override 7079 * {@link #dispatchProvideStructure(ViewStructure, int)} instead. 7080 */ 7081 // TODO(b/33197203): set proper API above 7082 @Deprecated 7083 public void dispatchProvideStructure(ViewStructure structure) { 7084 dispatchProvideStructure(structure, 0); 7085 } 7086 7087 /** 7088 * Dispatch creation of {@link ViewStructure} down the hierarchy. 7089 * 7090 * <p>The structure must be filled according to the request type, which is set in the 7091 * {@code flags} parameter - see the documentation on each flag for more details. 7092 * 7093 * <p>The default implementation calls {@link #onProvideStructure(ViewStructure, int)} and 7094 * {@link #onProvideVirtualStructure(ViewStructure, int)}. 7095 * 7096 * @param structure Fill in with structured view data. 7097 * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and 7098 * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info). 7099 */ 7100 public void dispatchProvideStructure(ViewStructure structure, int flags) { 7101 boolean forAutoFill = (flags 7102 & (View.ASSIST_FLAG_SANITIZED_TEXT 7103 | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0; 7104 7105 boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked(); 7106 if (!blocked) { 7107 onProvideStructure(structure, flags); 7108 onProvideVirtualStructure(structure, flags); 7109 } else { 7110 structure.setClassName(getAccessibilityClassName().toString()); 7111 structure.setAssistBlocked(true); 7112 } 7113 } 7114 7115 /** 7116 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 7117 * 7118 * Note: Called from the default {@link AccessibilityDelegate}. 7119 * 7120 * @hide 7121 */ 7122 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 7123 if (mAttachInfo == null) { 7124 return; 7125 } 7126 7127 Rect bounds = mAttachInfo.mTmpInvalRect; 7128 7129 getDrawingRect(bounds); 7130 info.setBoundsInParent(bounds); 7131 7132 getBoundsOnScreen(bounds, true); 7133 info.setBoundsInScreen(bounds); 7134 7135 ViewParent parent = getParentForAccessibility(); 7136 if (parent instanceof View) { 7137 info.setParent((View) parent); 7138 } 7139 7140 if (mID != View.NO_ID) { 7141 View rootView = getRootView(); 7142 if (rootView == null) { 7143 rootView = this; 7144 } 7145 7146 View label = rootView.findLabelForView(this, mID); 7147 if (label != null) { 7148 info.setLabeledBy(label); 7149 } 7150 7151 if ((mAttachInfo.mAccessibilityFetchFlags 7152 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 7153 && Resources.resourceHasPackage(mID)) { 7154 try { 7155 String viewId = getResources().getResourceName(mID); 7156 info.setViewIdResourceName(viewId); 7157 } catch (Resources.NotFoundException nfe) { 7158 /* ignore */ 7159 } 7160 } 7161 } 7162 7163 if (mLabelForId != View.NO_ID) { 7164 View rootView = getRootView(); 7165 if (rootView == null) { 7166 rootView = this; 7167 } 7168 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 7169 if (labeled != null) { 7170 info.setLabelFor(labeled); 7171 } 7172 } 7173 7174 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 7175 View rootView = getRootView(); 7176 if (rootView == null) { 7177 rootView = this; 7178 } 7179 View next = rootView.findViewInsideOutShouldExist(this, 7180 mAccessibilityTraversalBeforeId); 7181 if (next != null && next.includeForAccessibility()) { 7182 info.setTraversalBefore(next); 7183 } 7184 } 7185 7186 if (mAccessibilityTraversalAfterId != View.NO_ID) { 7187 View rootView = getRootView(); 7188 if (rootView == null) { 7189 rootView = this; 7190 } 7191 View next = rootView.findViewInsideOutShouldExist(this, 7192 mAccessibilityTraversalAfterId); 7193 if (next != null && next.includeForAccessibility()) { 7194 info.setTraversalAfter(next); 7195 } 7196 } 7197 7198 info.setVisibleToUser(isVisibleToUser()); 7199 7200 info.setImportantForAccessibility(isImportantForAccessibility()); 7201 info.setPackageName(mContext.getPackageName()); 7202 info.setClassName(getAccessibilityClassName()); 7203 info.setContentDescription(getContentDescription()); 7204 7205 info.setEnabled(isEnabled()); 7206 info.setClickable(isClickable()); 7207 info.setFocusable(isFocusable()); 7208 info.setFocused(isFocused()); 7209 info.setAccessibilityFocused(isAccessibilityFocused()); 7210 info.setSelected(isSelected()); 7211 info.setLongClickable(isLongClickable()); 7212 info.setContextClickable(isContextClickable()); 7213 info.setLiveRegion(getAccessibilityLiveRegion()); 7214 7215 // TODO: These make sense only if we are in an AdapterView but all 7216 // views can be selected. Maybe from accessibility perspective 7217 // we should report as selectable view in an AdapterView. 7218 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 7219 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 7220 7221 if (isFocusable()) { 7222 if (isFocused()) { 7223 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 7224 } else { 7225 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 7226 } 7227 } 7228 7229 if (!isAccessibilityFocused()) { 7230 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 7231 } else { 7232 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 7233 } 7234 7235 if (isClickable() && isEnabled()) { 7236 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 7237 } 7238 7239 if (isLongClickable() && isEnabled()) { 7240 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 7241 } 7242 7243 if (isContextClickable() && isEnabled()) { 7244 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 7245 } 7246 7247 CharSequence text = getIterableTextForAccessibility(); 7248 if (text != null && text.length() > 0) { 7249 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 7250 7251 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 7252 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 7253 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 7254 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 7255 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 7256 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 7257 } 7258 7259 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 7260 populateAccessibilityNodeInfoDrawingOrderInParent(info); 7261 } 7262 7263 /** 7264 * Determine the order in which this view will be drawn relative to its siblings for a11y 7265 * 7266 * @param info The info whose drawing order should be populated 7267 */ 7268 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 7269 /* 7270 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 7271 * drawing order may not be well-defined, and some Views with custom drawing order may 7272 * not be initialized sufficiently to respond properly getChildDrawingOrder. 7273 */ 7274 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 7275 info.setDrawingOrder(0); 7276 return; 7277 } 7278 int drawingOrderInParent = 1; 7279 // Iterate up the hierarchy if parents are not important for a11y 7280 View viewAtDrawingLevel = this; 7281 final ViewParent parent = getParentForAccessibility(); 7282 while (viewAtDrawingLevel != parent) { 7283 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 7284 if (!(currentParent instanceof ViewGroup)) { 7285 // Should only happen for the Decor 7286 drawingOrderInParent = 0; 7287 break; 7288 } else { 7289 final ViewGroup parentGroup = (ViewGroup) currentParent; 7290 final int childCount = parentGroup.getChildCount(); 7291 if (childCount > 1) { 7292 List<View> preorderedList = parentGroup.buildOrderedChildList(); 7293 if (preorderedList != null) { 7294 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 7295 for (int i = 0; i < childDrawIndex; i++) { 7296 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 7297 } 7298 } else { 7299 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 7300 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 7301 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 7302 .getChildDrawingOrder(childCount, childIndex) : childIndex; 7303 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 7304 if (childDrawIndex != 0) { 7305 for (int i = 0; i < numChildrenToIterate; i++) { 7306 final int otherDrawIndex = (customOrder ? 7307 parentGroup.getChildDrawingOrder(childCount, i) : i); 7308 if (otherDrawIndex < childDrawIndex) { 7309 drawingOrderInParent += 7310 numViewsForAccessibility(parentGroup.getChildAt(i)); 7311 } 7312 } 7313 } 7314 } 7315 } 7316 } 7317 viewAtDrawingLevel = (View) currentParent; 7318 } 7319 info.setDrawingOrder(drawingOrderInParent); 7320 } 7321 7322 private static int numViewsForAccessibility(View view) { 7323 if (view != null) { 7324 if (view.includeForAccessibility()) { 7325 return 1; 7326 } else if (view instanceof ViewGroup) { 7327 return ((ViewGroup) view).getNumChildrenForAccessibility(); 7328 } 7329 } 7330 return 0; 7331 } 7332 7333 private View findLabelForView(View view, int labeledId) { 7334 if (mMatchLabelForPredicate == null) { 7335 mMatchLabelForPredicate = new MatchLabelForPredicate(); 7336 } 7337 mMatchLabelForPredicate.mLabeledId = labeledId; 7338 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 7339 } 7340 7341 /** 7342 * Computes whether this view is visible to the user. Such a view is 7343 * attached, visible, all its predecessors are visible, it is not clipped 7344 * entirely by its predecessors, and has an alpha greater than zero. 7345 * 7346 * @return Whether the view is visible on the screen. 7347 * 7348 * @hide 7349 */ 7350 protected boolean isVisibleToUser() { 7351 return isVisibleToUser(null); 7352 } 7353 7354 /** 7355 * Computes whether the given portion of this view is visible to the user. 7356 * Such a view is attached, visible, all its predecessors are visible, 7357 * has an alpha greater than zero, and the specified portion is not 7358 * clipped entirely by its predecessors. 7359 * 7360 * @param boundInView the portion of the view to test; coordinates should be relative; may be 7361 * <code>null</code>, and the entire view will be tested in this case. 7362 * When <code>true</code> is returned by the function, the actual visible 7363 * region will be stored in this parameter; that is, if boundInView is fully 7364 * contained within the view, no modification will be made, otherwise regions 7365 * outside of the visible area of the view will be clipped. 7366 * 7367 * @return Whether the specified portion of the view is visible on the screen. 7368 * 7369 * @hide 7370 */ 7371 protected boolean isVisibleToUser(Rect boundInView) { 7372 if (mAttachInfo != null) { 7373 // Attached to invisible window means this view is not visible. 7374 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 7375 return false; 7376 } 7377 // An invisible predecessor or one with alpha zero means 7378 // that this view is not visible to the user. 7379 Object current = this; 7380 while (current instanceof View) { 7381 View view = (View) current; 7382 // We have attach info so this view is attached and there is no 7383 // need to check whether we reach to ViewRootImpl on the way up. 7384 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 7385 view.getVisibility() != VISIBLE) { 7386 return false; 7387 } 7388 current = view.mParent; 7389 } 7390 // Check if the view is entirely covered by its predecessors. 7391 Rect visibleRect = mAttachInfo.mTmpInvalRect; 7392 Point offset = mAttachInfo.mPoint; 7393 if (!getGlobalVisibleRect(visibleRect, offset)) { 7394 return false; 7395 } 7396 // Check if the visible portion intersects the rectangle of interest. 7397 if (boundInView != null) { 7398 visibleRect.offset(-offset.x, -offset.y); 7399 return boundInView.intersect(visibleRect); 7400 } 7401 return true; 7402 } 7403 return false; 7404 } 7405 7406 /** 7407 * Returns the delegate for implementing accessibility support via 7408 * composition. For more details see {@link AccessibilityDelegate}. 7409 * 7410 * @return The delegate, or null if none set. 7411 * 7412 * @hide 7413 */ 7414 public AccessibilityDelegate getAccessibilityDelegate() { 7415 return mAccessibilityDelegate; 7416 } 7417 7418 /** 7419 * Sets a delegate for implementing accessibility support via composition 7420 * (as opposed to inheritance). For more details, see 7421 * {@link AccessibilityDelegate}. 7422 * <p> 7423 * <strong>Note:</strong> On platform versions prior to 7424 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 7425 * views in the {@code android.widget.*} package are called <i>before</i> 7426 * host methods. This prevents certain properties such as class name from 7427 * being modified by overriding 7428 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 7429 * as any changes will be overwritten by the host class. 7430 * <p> 7431 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 7432 * methods are called <i>after</i> host methods, which all properties to be 7433 * modified without being overwritten by the host class. 7434 * 7435 * @param delegate the object to which accessibility method calls should be 7436 * delegated 7437 * @see AccessibilityDelegate 7438 */ 7439 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 7440 mAccessibilityDelegate = delegate; 7441 } 7442 7443 /** 7444 * Gets the provider for managing a virtual view hierarchy rooted at this View 7445 * and reported to {@link android.accessibilityservice.AccessibilityService}s 7446 * that explore the window content. 7447 * <p> 7448 * If this method returns an instance, this instance is responsible for managing 7449 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 7450 * View including the one representing the View itself. Similarly the returned 7451 * instance is responsible for performing accessibility actions on any virtual 7452 * view or the root view itself. 7453 * </p> 7454 * <p> 7455 * If an {@link AccessibilityDelegate} has been specified via calling 7456 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7457 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 7458 * is responsible for handling this call. 7459 * </p> 7460 * 7461 * @return The provider. 7462 * 7463 * @see AccessibilityNodeProvider 7464 */ 7465 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 7466 if (mAccessibilityDelegate != null) { 7467 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 7468 } else { 7469 return null; 7470 } 7471 } 7472 7473 /** 7474 * Gets the unique identifier of this view on the screen for accessibility purposes. 7475 * 7476 * @return The view accessibility id. 7477 * 7478 * @hide 7479 */ 7480 public int getAccessibilityViewId() { 7481 if (mAccessibilityViewId == NO_ID) { 7482 mAccessibilityViewId = sNextAccessibilityViewId++; 7483 } 7484 return mAccessibilityViewId; 7485 } 7486 7487 /** 7488 * Gets the unique identifier of the window in which this View reseides. 7489 * 7490 * @return The window accessibility id. 7491 * 7492 * @hide 7493 */ 7494 public int getAccessibilityWindowId() { 7495 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 7496 : AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 7497 } 7498 7499 /** 7500 * Returns the {@link View}'s content description. 7501 * <p> 7502 * <strong>Note:</strong> Do not override this method, as it will have no 7503 * effect on the content description presented to accessibility services. 7504 * You must call {@link #setContentDescription(CharSequence)} to modify the 7505 * content description. 7506 * 7507 * @return the content description 7508 * @see #setContentDescription(CharSequence) 7509 * @attr ref android.R.styleable#View_contentDescription 7510 */ 7511 @ViewDebug.ExportedProperty(category = "accessibility") 7512 public CharSequence getContentDescription() { 7513 return mContentDescription; 7514 } 7515 7516 /** 7517 * Sets the {@link View}'s content description. 7518 * <p> 7519 * A content description briefly describes the view and is primarily used 7520 * for accessibility support to determine how a view should be presented to 7521 * the user. In the case of a view with no textual representation, such as 7522 * {@link android.widget.ImageButton}, a useful content description 7523 * explains what the view does. For example, an image button with a phone 7524 * icon that is used to place a call may use "Call" as its content 7525 * description. An image of a floppy disk that is used to save a file may 7526 * use "Save". 7527 * 7528 * @param contentDescription The content description. 7529 * @see #getContentDescription() 7530 * @attr ref android.R.styleable#View_contentDescription 7531 */ 7532 @RemotableViewMethod 7533 public void setContentDescription(CharSequence contentDescription) { 7534 if (mContentDescription == null) { 7535 if (contentDescription == null) { 7536 return; 7537 } 7538 } else if (mContentDescription.equals(contentDescription)) { 7539 return; 7540 } 7541 mContentDescription = contentDescription; 7542 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 7543 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 7544 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 7545 notifySubtreeAccessibilityStateChangedIfNeeded(); 7546 } else { 7547 notifyViewAccessibilityStateChangedIfNeeded( 7548 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 7549 } 7550 } 7551 7552 /** 7553 * Sets the id of a view before which this one is visited in accessibility traversal. 7554 * A screen-reader must visit the content of this view before the content of the one 7555 * it precedes. For example, if view B is set to be before view A, then a screen-reader 7556 * will traverse the entire content of B before traversing the entire content of A, 7557 * regardles of what traversal strategy it is using. 7558 * <p> 7559 * Views that do not have specified before/after relationships are traversed in order 7560 * determined by the screen-reader. 7561 * </p> 7562 * <p> 7563 * Setting that this view is before a view that is not important for accessibility 7564 * or if this view is not important for accessibility will have no effect as the 7565 * screen-reader is not aware of unimportant views. 7566 * </p> 7567 * 7568 * @param beforeId The id of a view this one precedes in accessibility traversal. 7569 * 7570 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 7571 * 7572 * @see #setImportantForAccessibility(int) 7573 */ 7574 @RemotableViewMethod 7575 public void setAccessibilityTraversalBefore(int beforeId) { 7576 if (mAccessibilityTraversalBeforeId == beforeId) { 7577 return; 7578 } 7579 mAccessibilityTraversalBeforeId = beforeId; 7580 notifyViewAccessibilityStateChangedIfNeeded( 7581 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7582 } 7583 7584 /** 7585 * Gets the id of a view before which this one is visited in accessibility traversal. 7586 * 7587 * @return The id of a view this one precedes in accessibility traversal if 7588 * specified, otherwise {@link #NO_ID}. 7589 * 7590 * @see #setAccessibilityTraversalBefore(int) 7591 */ 7592 public int getAccessibilityTraversalBefore() { 7593 return mAccessibilityTraversalBeforeId; 7594 } 7595 7596 /** 7597 * Sets the id of a view after which this one is visited in accessibility traversal. 7598 * A screen-reader must visit the content of the other view before the content of this 7599 * one. For example, if view B is set to be after view A, then a screen-reader 7600 * will traverse the entire content of A before traversing the entire content of B, 7601 * regardles of what traversal strategy it is using. 7602 * <p> 7603 * Views that do not have specified before/after relationships are traversed in order 7604 * determined by the screen-reader. 7605 * </p> 7606 * <p> 7607 * Setting that this view is after a view that is not important for accessibility 7608 * or if this view is not important for accessibility will have no effect as the 7609 * screen-reader is not aware of unimportant views. 7610 * </p> 7611 * 7612 * @param afterId The id of a view this one succedees in accessibility traversal. 7613 * 7614 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 7615 * 7616 * @see #setImportantForAccessibility(int) 7617 */ 7618 @RemotableViewMethod 7619 public void setAccessibilityTraversalAfter(int afterId) { 7620 if (mAccessibilityTraversalAfterId == afterId) { 7621 return; 7622 } 7623 mAccessibilityTraversalAfterId = afterId; 7624 notifyViewAccessibilityStateChangedIfNeeded( 7625 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7626 } 7627 7628 /** 7629 * Gets the id of a view after which this one is visited in accessibility traversal. 7630 * 7631 * @return The id of a view this one succeedes in accessibility traversal if 7632 * specified, otherwise {@link #NO_ID}. 7633 * 7634 * @see #setAccessibilityTraversalAfter(int) 7635 */ 7636 public int getAccessibilityTraversalAfter() { 7637 return mAccessibilityTraversalAfterId; 7638 } 7639 7640 /** 7641 * Gets the id of a view for which this view serves as a label for 7642 * accessibility purposes. 7643 * 7644 * @return The labeled view id. 7645 */ 7646 @ViewDebug.ExportedProperty(category = "accessibility") 7647 public int getLabelFor() { 7648 return mLabelForId; 7649 } 7650 7651 /** 7652 * Sets the id of a view for which this view serves as a label for 7653 * accessibility purposes. 7654 * 7655 * @param id The labeled view id. 7656 */ 7657 @RemotableViewMethod 7658 public void setLabelFor(@IdRes int id) { 7659 if (mLabelForId == id) { 7660 return; 7661 } 7662 mLabelForId = id; 7663 if (mLabelForId != View.NO_ID 7664 && mID == View.NO_ID) { 7665 mID = generateViewId(); 7666 } 7667 notifyViewAccessibilityStateChangedIfNeeded( 7668 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7669 } 7670 7671 /** 7672 * Invoked whenever this view loses focus, either by losing window focus or by losing 7673 * focus within its window. This method can be used to clear any state tied to the 7674 * focus. For instance, if a button is held pressed with the trackball and the window 7675 * loses focus, this method can be used to cancel the press. 7676 * 7677 * Subclasses of View overriding this method should always call super.onFocusLost(). 7678 * 7679 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 7680 * @see #onWindowFocusChanged(boolean) 7681 * 7682 * @hide pending API council approval 7683 */ 7684 @CallSuper 7685 protected void onFocusLost() { 7686 resetPressedState(); 7687 } 7688 7689 private void resetPressedState() { 7690 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 7691 return; 7692 } 7693 7694 if (isPressed()) { 7695 setPressed(false); 7696 7697 if (!mHasPerformedLongPress) { 7698 removeLongPressCallback(); 7699 } 7700 } 7701 } 7702 7703 /** 7704 * Returns true if this view has focus 7705 * 7706 * @return True if this view has focus, false otherwise. 7707 */ 7708 @ViewDebug.ExportedProperty(category = "focus") 7709 public boolean isFocused() { 7710 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 7711 } 7712 7713 /** 7714 * Find the view in the hierarchy rooted at this view that currently has 7715 * focus. 7716 * 7717 * @return The view that currently has focus, or null if no focused view can 7718 * be found. 7719 */ 7720 public View findFocus() { 7721 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 7722 } 7723 7724 /** 7725 * Indicates whether this view is one of the set of scrollable containers in 7726 * its window. 7727 * 7728 * @return whether this view is one of the set of scrollable containers in 7729 * its window 7730 * 7731 * @attr ref android.R.styleable#View_isScrollContainer 7732 */ 7733 public boolean isScrollContainer() { 7734 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 7735 } 7736 7737 /** 7738 * Change whether this view is one of the set of scrollable containers in 7739 * its window. This will be used to determine whether the window can 7740 * resize or must pan when a soft input area is open -- scrollable 7741 * containers allow the window to use resize mode since the container 7742 * will appropriately shrink. 7743 * 7744 * @attr ref android.R.styleable#View_isScrollContainer 7745 */ 7746 public void setScrollContainer(boolean isScrollContainer) { 7747 if (isScrollContainer) { 7748 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 7749 mAttachInfo.mScrollContainers.add(this); 7750 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 7751 } 7752 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 7753 } else { 7754 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 7755 mAttachInfo.mScrollContainers.remove(this); 7756 } 7757 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 7758 } 7759 } 7760 7761 /** 7762 * Returns the quality of the drawing cache. 7763 * 7764 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 7765 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 7766 * 7767 * @see #setDrawingCacheQuality(int) 7768 * @see #setDrawingCacheEnabled(boolean) 7769 * @see #isDrawingCacheEnabled() 7770 * 7771 * @attr ref android.R.styleable#View_drawingCacheQuality 7772 */ 7773 @DrawingCacheQuality 7774 public int getDrawingCacheQuality() { 7775 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 7776 } 7777 7778 /** 7779 * Set the drawing cache quality of this view. This value is used only when the 7780 * drawing cache is enabled 7781 * 7782 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 7783 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 7784 * 7785 * @see #getDrawingCacheQuality() 7786 * @see #setDrawingCacheEnabled(boolean) 7787 * @see #isDrawingCacheEnabled() 7788 * 7789 * @attr ref android.R.styleable#View_drawingCacheQuality 7790 */ 7791 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 7792 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 7793 } 7794 7795 /** 7796 * Returns whether the screen should remain on, corresponding to the current 7797 * value of {@link #KEEP_SCREEN_ON}. 7798 * 7799 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 7800 * 7801 * @see #setKeepScreenOn(boolean) 7802 * 7803 * @attr ref android.R.styleable#View_keepScreenOn 7804 */ 7805 public boolean getKeepScreenOn() { 7806 return (mViewFlags & KEEP_SCREEN_ON) != 0; 7807 } 7808 7809 /** 7810 * Controls whether the screen should remain on, modifying the 7811 * value of {@link #KEEP_SCREEN_ON}. 7812 * 7813 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 7814 * 7815 * @see #getKeepScreenOn() 7816 * 7817 * @attr ref android.R.styleable#View_keepScreenOn 7818 */ 7819 public void setKeepScreenOn(boolean keepScreenOn) { 7820 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 7821 } 7822 7823 /** 7824 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 7825 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7826 * 7827 * @attr ref android.R.styleable#View_nextFocusLeft 7828 */ 7829 public int getNextFocusLeftId() { 7830 return mNextFocusLeftId; 7831 } 7832 7833 /** 7834 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 7835 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 7836 * decide automatically. 7837 * 7838 * @attr ref android.R.styleable#View_nextFocusLeft 7839 */ 7840 public void setNextFocusLeftId(int nextFocusLeftId) { 7841 mNextFocusLeftId = nextFocusLeftId; 7842 } 7843 7844 /** 7845 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 7846 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7847 * 7848 * @attr ref android.R.styleable#View_nextFocusRight 7849 */ 7850 public int getNextFocusRightId() { 7851 return mNextFocusRightId; 7852 } 7853 7854 /** 7855 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 7856 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 7857 * decide automatically. 7858 * 7859 * @attr ref android.R.styleable#View_nextFocusRight 7860 */ 7861 public void setNextFocusRightId(int nextFocusRightId) { 7862 mNextFocusRightId = nextFocusRightId; 7863 } 7864 7865 /** 7866 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 7867 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7868 * 7869 * @attr ref android.R.styleable#View_nextFocusUp 7870 */ 7871 public int getNextFocusUpId() { 7872 return mNextFocusUpId; 7873 } 7874 7875 /** 7876 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 7877 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 7878 * decide automatically. 7879 * 7880 * @attr ref android.R.styleable#View_nextFocusUp 7881 */ 7882 public void setNextFocusUpId(int nextFocusUpId) { 7883 mNextFocusUpId = nextFocusUpId; 7884 } 7885 7886 /** 7887 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 7888 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7889 * 7890 * @attr ref android.R.styleable#View_nextFocusDown 7891 */ 7892 public int getNextFocusDownId() { 7893 return mNextFocusDownId; 7894 } 7895 7896 /** 7897 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 7898 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 7899 * decide automatically. 7900 * 7901 * @attr ref android.R.styleable#View_nextFocusDown 7902 */ 7903 public void setNextFocusDownId(int nextFocusDownId) { 7904 mNextFocusDownId = nextFocusDownId; 7905 } 7906 7907 /** 7908 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 7909 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7910 * 7911 * @attr ref android.R.styleable#View_nextFocusForward 7912 */ 7913 public int getNextFocusForwardId() { 7914 return mNextFocusForwardId; 7915 } 7916 7917 /** 7918 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 7919 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 7920 * decide automatically. 7921 * 7922 * @attr ref android.R.styleable#View_nextFocusForward 7923 */ 7924 public void setNextFocusForwardId(int nextFocusForwardId) { 7925 mNextFocusForwardId = nextFocusForwardId; 7926 } 7927 7928 /** 7929 * Gets the id of the root of the next keyboard navigation cluster. 7930 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 7931 * decide automatically. 7932 * 7933 * @attr ref android.R.styleable#View_nextClusterForward 7934 */ 7935 public int getNextClusterForwardId() { 7936 return mNextClusterForwardId; 7937 } 7938 7939 /** 7940 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 7941 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 7942 * decide automatically. 7943 * 7944 * @attr ref android.R.styleable#View_nextClusterForward 7945 */ 7946 public void setNextClusterForwardId(int nextClusterForwardId) { 7947 mNextClusterForwardId = nextClusterForwardId; 7948 } 7949 7950 /** 7951 * Gets the id of the root of the next keyboard navigation section. 7952 * @return The next keyboard navigation section ID, or {@link #NO_ID} if the framework should 7953 * decide automatically. 7954 * 7955 * @attr ref android.R.styleable#View_nextSectionForward 7956 */ 7957 public int getNextSectionForwardId() { 7958 return mNextSectionForwardId; 7959 } 7960 7961 /** 7962 * Sets the id of the view to use as the root of the next keyboard navigation section. 7963 * @param nextSectionForwardId The next section ID, or {@link #NO_ID} if the framework should 7964 * decide automatically. 7965 * 7966 * @attr ref android.R.styleable#View_nextSectionForward 7967 */ 7968 public void setNextSectionForwardId(int nextSectionForwardId) { 7969 mNextSectionForwardId = nextSectionForwardId; 7970 } 7971 7972 /** 7973 * Returns the visibility of this view and all of its ancestors 7974 * 7975 * @return True if this view and all of its ancestors are {@link #VISIBLE} 7976 */ 7977 public boolean isShown() { 7978 View current = this; 7979 //noinspection ConstantConditions 7980 do { 7981 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 7982 return false; 7983 } 7984 ViewParent parent = current.mParent; 7985 if (parent == null) { 7986 return false; // We are not attached to the view root 7987 } 7988 if (!(parent instanceof View)) { 7989 return true; 7990 } 7991 current = (View) parent; 7992 } while (current != null); 7993 7994 return false; 7995 } 7996 7997 /** 7998 * Called by the view hierarchy when the content insets for a window have 7999 * changed, to allow it to adjust its content to fit within those windows. 8000 * The content insets tell you the space that the status bar, input method, 8001 * and other system windows infringe on the application's window. 8002 * 8003 * <p>You do not normally need to deal with this function, since the default 8004 * window decoration given to applications takes care of applying it to the 8005 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 8006 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 8007 * and your content can be placed under those system elements. You can then 8008 * use this method within your view hierarchy if you have parts of your UI 8009 * which you would like to ensure are not being covered. 8010 * 8011 * <p>The default implementation of this method simply applies the content 8012 * insets to the view's padding, consuming that content (modifying the 8013 * insets to be 0), and returning true. This behavior is off by default, but can 8014 * be enabled through {@link #setFitsSystemWindows(boolean)}. 8015 * 8016 * <p>This function's traversal down the hierarchy is depth-first. The same content 8017 * insets object is propagated down the hierarchy, so any changes made to it will 8018 * be seen by all following views (including potentially ones above in 8019 * the hierarchy since this is a depth-first traversal). The first view 8020 * that returns true will abort the entire traversal. 8021 * 8022 * <p>The default implementation works well for a situation where it is 8023 * used with a container that covers the entire window, allowing it to 8024 * apply the appropriate insets to its content on all edges. If you need 8025 * a more complicated layout (such as two different views fitting system 8026 * windows, one on the top of the window, and one on the bottom), 8027 * you can override the method and handle the insets however you would like. 8028 * Note that the insets provided by the framework are always relative to the 8029 * far edges of the window, not accounting for the location of the called view 8030 * within that window. (In fact when this method is called you do not yet know 8031 * where the layout will place the view, as it is done before layout happens.) 8032 * 8033 * <p>Note: unlike many View methods, there is no dispatch phase to this 8034 * call. If you are overriding it in a ViewGroup and want to allow the 8035 * call to continue to your children, you must be sure to call the super 8036 * implementation. 8037 * 8038 * <p>Here is a sample layout that makes use of fitting system windows 8039 * to have controls for a video view placed inside of the window decorations 8040 * that it hides and shows. This can be used with code like the second 8041 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 8042 * 8043 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 8044 * 8045 * @param insets Current content insets of the window. Prior to 8046 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 8047 * the insets or else you and Android will be unhappy. 8048 * 8049 * @return {@code true} if this view applied the insets and it should not 8050 * continue propagating further down the hierarchy, {@code false} otherwise. 8051 * @see #getFitsSystemWindows() 8052 * @see #setFitsSystemWindows(boolean) 8053 * @see #setSystemUiVisibility(int) 8054 * 8055 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 8056 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 8057 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 8058 * to implement handling their own insets. 8059 */ 8060 @Deprecated 8061 protected boolean fitSystemWindows(Rect insets) { 8062 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 8063 if (insets == null) { 8064 // Null insets by definition have already been consumed. 8065 // This call cannot apply insets since there are none to apply, 8066 // so return false. 8067 return false; 8068 } 8069 // If we're not in the process of dispatching the newer apply insets call, 8070 // that means we're not in the compatibility path. Dispatch into the newer 8071 // apply insets path and take things from there. 8072 try { 8073 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 8074 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 8075 } finally { 8076 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 8077 } 8078 } else { 8079 // We're being called from the newer apply insets path. 8080 // Perform the standard fallback behavior. 8081 return fitSystemWindowsInt(insets); 8082 } 8083 } 8084 8085 private boolean fitSystemWindowsInt(Rect insets) { 8086 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 8087 mUserPaddingStart = UNDEFINED_PADDING; 8088 mUserPaddingEnd = UNDEFINED_PADDING; 8089 Rect localInsets = sThreadLocal.get(); 8090 if (localInsets == null) { 8091 localInsets = new Rect(); 8092 sThreadLocal.set(localInsets); 8093 } 8094 boolean res = computeFitSystemWindows(insets, localInsets); 8095 mUserPaddingLeftInitial = localInsets.left; 8096 mUserPaddingRightInitial = localInsets.right; 8097 internalSetPadding(localInsets.left, localInsets.top, 8098 localInsets.right, localInsets.bottom); 8099 return res; 8100 } 8101 return false; 8102 } 8103 8104 /** 8105 * Called when the view should apply {@link WindowInsets} according to its internal policy. 8106 * 8107 * <p>This method should be overridden by views that wish to apply a policy different from or 8108 * in addition to the default behavior. Clients that wish to force a view subtree 8109 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 8110 * 8111 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 8112 * it will be called during dispatch instead of this method. The listener may optionally 8113 * call this method from its own implementation if it wishes to apply the view's default 8114 * insets policy in addition to its own.</p> 8115 * 8116 * <p>Implementations of this method should either return the insets parameter unchanged 8117 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 8118 * that this view applied itself. This allows new inset types added in future platform 8119 * versions to pass through existing implementations unchanged without being erroneously 8120 * consumed.</p> 8121 * 8122 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 8123 * property is set then the view will consume the system window insets and apply them 8124 * as padding for the view.</p> 8125 * 8126 * @param insets Insets to apply 8127 * @return The supplied insets with any applied insets consumed 8128 */ 8129 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 8130 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 8131 // We weren't called from within a direct call to fitSystemWindows, 8132 // call into it as a fallback in case we're in a class that overrides it 8133 // and has logic to perform. 8134 if (fitSystemWindows(insets.getSystemWindowInsets())) { 8135 return insets.consumeSystemWindowInsets(); 8136 } 8137 } else { 8138 // We were called from within a direct call to fitSystemWindows. 8139 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 8140 return insets.consumeSystemWindowInsets(); 8141 } 8142 } 8143 return insets; 8144 } 8145 8146 /** 8147 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 8148 * window insets to this view. The listener's 8149 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 8150 * method will be called instead of the view's 8151 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 8152 * 8153 * @param listener Listener to set 8154 * 8155 * @see #onApplyWindowInsets(WindowInsets) 8156 */ 8157 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 8158 getListenerInfo().mOnApplyWindowInsetsListener = listener; 8159 } 8160 8161 /** 8162 * Request to apply the given window insets to this view or another view in its subtree. 8163 * 8164 * <p>This method should be called by clients wishing to apply insets corresponding to areas 8165 * obscured by window decorations or overlays. This can include the status and navigation bars, 8166 * action bars, input methods and more. New inset categories may be added in the future. 8167 * The method returns the insets provided minus any that were applied by this view or its 8168 * children.</p> 8169 * 8170 * <p>Clients wishing to provide custom behavior should override the 8171 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 8172 * {@link OnApplyWindowInsetsListener} via the 8173 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 8174 * method.</p> 8175 * 8176 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 8177 * </p> 8178 * 8179 * @param insets Insets to apply 8180 * @return The provided insets minus the insets that were consumed 8181 */ 8182 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 8183 try { 8184 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 8185 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 8186 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 8187 } else { 8188 return onApplyWindowInsets(insets); 8189 } 8190 } finally { 8191 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 8192 } 8193 } 8194 8195 /** 8196 * Compute the view's coordinate within the surface. 8197 * 8198 * <p>Computes the coordinates of this view in its surface. The argument 8199 * must be an array of two integers. After the method returns, the array 8200 * contains the x and y location in that order.</p> 8201 * @hide 8202 * @param location an array of two integers in which to hold the coordinates 8203 */ 8204 public void getLocationInSurface(@Size(2) int[] location) { 8205 getLocationInWindow(location); 8206 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 8207 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 8208 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 8209 } 8210 } 8211 8212 /** 8213 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 8214 * only available if the view is attached. 8215 * 8216 * @return WindowInsets from the top of the view hierarchy or null if View is detached 8217 */ 8218 public WindowInsets getRootWindowInsets() { 8219 if (mAttachInfo != null) { 8220 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 8221 } 8222 return null; 8223 } 8224 8225 /** 8226 * @hide Compute the insets that should be consumed by this view and the ones 8227 * that should propagate to those under it. 8228 */ 8229 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 8230 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8231 || mAttachInfo == null 8232 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 8233 && !mAttachInfo.mOverscanRequested)) { 8234 outLocalInsets.set(inoutInsets); 8235 inoutInsets.set(0, 0, 0, 0); 8236 return true; 8237 } else { 8238 // The application wants to take care of fitting system window for 8239 // the content... however we still need to take care of any overscan here. 8240 final Rect overscan = mAttachInfo.mOverscanInsets; 8241 outLocalInsets.set(overscan); 8242 inoutInsets.left -= overscan.left; 8243 inoutInsets.top -= overscan.top; 8244 inoutInsets.right -= overscan.right; 8245 inoutInsets.bottom -= overscan.bottom; 8246 return false; 8247 } 8248 } 8249 8250 /** 8251 * Compute insets that should be consumed by this view and the ones that should propagate 8252 * to those under it. 8253 * 8254 * @param in Insets currently being processed by this View, likely received as a parameter 8255 * to {@link #onApplyWindowInsets(WindowInsets)}. 8256 * @param outLocalInsets A Rect that will receive the insets that should be consumed 8257 * by this view 8258 * @return Insets that should be passed along to views under this one 8259 */ 8260 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 8261 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8262 || mAttachInfo == null 8263 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 8264 outLocalInsets.set(in.getSystemWindowInsets()); 8265 return in.consumeSystemWindowInsets(); 8266 } else { 8267 outLocalInsets.set(0, 0, 0, 0); 8268 return in; 8269 } 8270 } 8271 8272 /** 8273 * Sets whether or not this view should account for system screen decorations 8274 * such as the status bar and inset its content; that is, controlling whether 8275 * the default implementation of {@link #fitSystemWindows(Rect)} will be 8276 * executed. See that method for more details. 8277 * 8278 * <p>Note that if you are providing your own implementation of 8279 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 8280 * flag to true -- your implementation will be overriding the default 8281 * implementation that checks this flag. 8282 * 8283 * @param fitSystemWindows If true, then the default implementation of 8284 * {@link #fitSystemWindows(Rect)} will be executed. 8285 * 8286 * @attr ref android.R.styleable#View_fitsSystemWindows 8287 * @see #getFitsSystemWindows() 8288 * @see #fitSystemWindows(Rect) 8289 * @see #setSystemUiVisibility(int) 8290 */ 8291 public void setFitsSystemWindows(boolean fitSystemWindows) { 8292 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 8293 } 8294 8295 /** 8296 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 8297 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 8298 * will be executed. 8299 * 8300 * @return {@code true} if the default implementation of 8301 * {@link #fitSystemWindows(Rect)} will be executed. 8302 * 8303 * @attr ref android.R.styleable#View_fitsSystemWindows 8304 * @see #setFitsSystemWindows(boolean) 8305 * @see #fitSystemWindows(Rect) 8306 * @see #setSystemUiVisibility(int) 8307 */ 8308 @ViewDebug.ExportedProperty 8309 public boolean getFitsSystemWindows() { 8310 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 8311 } 8312 8313 /** @hide */ 8314 public boolean fitsSystemWindows() { 8315 return getFitsSystemWindows(); 8316 } 8317 8318 /** 8319 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 8320 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 8321 */ 8322 @Deprecated 8323 public void requestFitSystemWindows() { 8324 if (mParent != null) { 8325 mParent.requestFitSystemWindows(); 8326 } 8327 } 8328 8329 /** 8330 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 8331 */ 8332 public void requestApplyInsets() { 8333 requestFitSystemWindows(); 8334 } 8335 8336 /** 8337 * For use by PhoneWindow to make its own system window fitting optional. 8338 * @hide 8339 */ 8340 public void makeOptionalFitsSystemWindows() { 8341 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 8342 } 8343 8344 /** 8345 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 8346 * treat them as such. 8347 * @hide 8348 */ 8349 public void getOutsets(Rect outOutsetRect) { 8350 if (mAttachInfo != null) { 8351 outOutsetRect.set(mAttachInfo.mOutsets); 8352 } else { 8353 outOutsetRect.setEmpty(); 8354 } 8355 } 8356 8357 /** 8358 * Returns the visibility status for this view. 8359 * 8360 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8361 * @attr ref android.R.styleable#View_visibility 8362 */ 8363 @ViewDebug.ExportedProperty(mapping = { 8364 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 8365 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 8366 @ViewDebug.IntToString(from = GONE, to = "GONE") 8367 }) 8368 @Visibility 8369 public int getVisibility() { 8370 return mViewFlags & VISIBILITY_MASK; 8371 } 8372 8373 /** 8374 * Set the visibility state of this view. 8375 * 8376 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8377 * @attr ref android.R.styleable#View_visibility 8378 */ 8379 @RemotableViewMethod 8380 public void setVisibility(@Visibility int visibility) { 8381 setFlags(visibility, VISIBILITY_MASK); 8382 } 8383 8384 /** 8385 * Returns the enabled status for this view. The interpretation of the 8386 * enabled state varies by subclass. 8387 * 8388 * @return True if this view is enabled, false otherwise. 8389 */ 8390 @ViewDebug.ExportedProperty 8391 public boolean isEnabled() { 8392 return (mViewFlags & ENABLED_MASK) == ENABLED; 8393 } 8394 8395 /** 8396 * Set the enabled state of this view. The interpretation of the enabled 8397 * state varies by subclass. 8398 * 8399 * @param enabled True if this view is enabled, false otherwise. 8400 */ 8401 @RemotableViewMethod 8402 public void setEnabled(boolean enabled) { 8403 if (enabled == isEnabled()) return; 8404 8405 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 8406 8407 /* 8408 * The View most likely has to change its appearance, so refresh 8409 * the drawable state. 8410 */ 8411 refreshDrawableState(); 8412 8413 // Invalidate too, since the default behavior for views is to be 8414 // be drawn at 50% alpha rather than to change the drawable. 8415 invalidate(true); 8416 8417 if (!enabled) { 8418 cancelPendingInputEvents(); 8419 } 8420 } 8421 8422 /** 8423 * Set whether this view can receive the focus. 8424 * 8425 * Setting this to false will also ensure that this view is not focusable 8426 * in touch mode. 8427 * 8428 * @param focusable If true, this view can receive the focus. 8429 * 8430 * @see #setFocusableInTouchMode(boolean) 8431 * @attr ref android.R.styleable#View_focusable 8432 */ 8433 public void setFocusable(boolean focusable) { 8434 if (!focusable) { 8435 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 8436 } 8437 setFlags(focusable ? FOCUSABLE : NOT_FOCUSABLE, FOCUSABLE_MASK); 8438 } 8439 8440 /** 8441 * Set whether this view can receive focus while in touch mode. 8442 * 8443 * Setting this to true will also ensure that this view is focusable. 8444 * 8445 * @param focusableInTouchMode If true, this view can receive the focus while 8446 * in touch mode. 8447 * 8448 * @see #setFocusable(boolean) 8449 * @attr ref android.R.styleable#View_focusableInTouchMode 8450 */ 8451 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 8452 // Focusable in touch mode should always be set before the focusable flag 8453 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 8454 // which, in touch mode, will not successfully request focus on this view 8455 // because the focusable in touch mode flag is not set 8456 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 8457 if (focusableInTouchMode) { 8458 setFlags(FOCUSABLE, FOCUSABLE_MASK); 8459 } 8460 } 8461 8462 /** 8463 * Set whether this view should have sound effects enabled for events such as 8464 * clicking and touching. 8465 * 8466 * <p>You may wish to disable sound effects for a view if you already play sounds, 8467 * for instance, a dial key that plays dtmf tones. 8468 * 8469 * @param soundEffectsEnabled whether sound effects are enabled for this view. 8470 * @see #isSoundEffectsEnabled() 8471 * @see #playSoundEffect(int) 8472 * @attr ref android.R.styleable#View_soundEffectsEnabled 8473 */ 8474 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 8475 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 8476 } 8477 8478 /** 8479 * @return whether this view should have sound effects enabled for events such as 8480 * clicking and touching. 8481 * 8482 * @see #setSoundEffectsEnabled(boolean) 8483 * @see #playSoundEffect(int) 8484 * @attr ref android.R.styleable#View_soundEffectsEnabled 8485 */ 8486 @ViewDebug.ExportedProperty 8487 public boolean isSoundEffectsEnabled() { 8488 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 8489 } 8490 8491 /** 8492 * Set whether this view should have haptic feedback for events such as 8493 * long presses. 8494 * 8495 * <p>You may wish to disable haptic feedback if your view already controls 8496 * its own haptic feedback. 8497 * 8498 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 8499 * @see #isHapticFeedbackEnabled() 8500 * @see #performHapticFeedback(int) 8501 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8502 */ 8503 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 8504 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 8505 } 8506 8507 /** 8508 * @return whether this view should have haptic feedback enabled for events 8509 * long presses. 8510 * 8511 * @see #setHapticFeedbackEnabled(boolean) 8512 * @see #performHapticFeedback(int) 8513 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8514 */ 8515 @ViewDebug.ExportedProperty 8516 public boolean isHapticFeedbackEnabled() { 8517 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 8518 } 8519 8520 /** 8521 * Returns the layout direction for this view. 8522 * 8523 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 8524 * {@link #LAYOUT_DIRECTION_RTL}, 8525 * {@link #LAYOUT_DIRECTION_INHERIT} or 8526 * {@link #LAYOUT_DIRECTION_LOCALE}. 8527 * 8528 * @attr ref android.R.styleable#View_layoutDirection 8529 * 8530 * @hide 8531 */ 8532 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8533 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 8534 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 8535 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 8536 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 8537 }) 8538 @LayoutDir 8539 public int getRawLayoutDirection() { 8540 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 8541 } 8542 8543 /** 8544 * Set the layout direction for this view. This will propagate a reset of layout direction 8545 * resolution to the view's children and resolve layout direction for this view. 8546 * 8547 * @param layoutDirection the layout direction to set. Should be one of: 8548 * 8549 * {@link #LAYOUT_DIRECTION_LTR}, 8550 * {@link #LAYOUT_DIRECTION_RTL}, 8551 * {@link #LAYOUT_DIRECTION_INHERIT}, 8552 * {@link #LAYOUT_DIRECTION_LOCALE}. 8553 * 8554 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 8555 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 8556 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 8557 * 8558 * @attr ref android.R.styleable#View_layoutDirection 8559 */ 8560 @RemotableViewMethod 8561 public void setLayoutDirection(@LayoutDir int layoutDirection) { 8562 if (getRawLayoutDirection() != layoutDirection) { 8563 // Reset the current layout direction and the resolved one 8564 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 8565 resetRtlProperties(); 8566 // Set the new layout direction (filtered) 8567 mPrivateFlags2 |= 8568 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 8569 // We need to resolve all RTL properties as they all depend on layout direction 8570 resolveRtlPropertiesIfNeeded(); 8571 requestLayout(); 8572 invalidate(true); 8573 } 8574 } 8575 8576 /** 8577 * Returns the resolved layout direction for this view. 8578 * 8579 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 8580 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 8581 * 8582 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 8583 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 8584 * 8585 * @attr ref android.R.styleable#View_layoutDirection 8586 */ 8587 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8588 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 8589 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 8590 }) 8591 @ResolvedLayoutDir 8592 public int getLayoutDirection() { 8593 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 8594 if (targetSdkVersion < JELLY_BEAN_MR1) { 8595 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 8596 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 8597 } 8598 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 8599 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 8600 } 8601 8602 /** 8603 * Indicates whether or not this view's layout is right-to-left. This is resolved from 8604 * layout attribute and/or the inherited value from the parent 8605 * 8606 * @return true if the layout is right-to-left. 8607 * 8608 * @hide 8609 */ 8610 @ViewDebug.ExportedProperty(category = "layout") 8611 public boolean isLayoutRtl() { 8612 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 8613 } 8614 8615 /** 8616 * Indicates whether the view is currently tracking transient state that the 8617 * app should not need to concern itself with saving and restoring, but that 8618 * the framework should take special note to preserve when possible. 8619 * 8620 * <p>A view with transient state cannot be trivially rebound from an external 8621 * data source, such as an adapter binding item views in a list. This may be 8622 * because the view is performing an animation, tracking user selection 8623 * of content, or similar.</p> 8624 * 8625 * @return true if the view has transient state 8626 */ 8627 @ViewDebug.ExportedProperty(category = "layout") 8628 public boolean hasTransientState() { 8629 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 8630 } 8631 8632 /** 8633 * Set whether this view is currently tracking transient state that the 8634 * framework should attempt to preserve when possible. This flag is reference counted, 8635 * so every call to setHasTransientState(true) should be paired with a later call 8636 * to setHasTransientState(false). 8637 * 8638 * <p>A view with transient state cannot be trivially rebound from an external 8639 * data source, such as an adapter binding item views in a list. This may be 8640 * because the view is performing an animation, tracking user selection 8641 * of content, or similar.</p> 8642 * 8643 * @param hasTransientState true if this view has transient state 8644 */ 8645 public void setHasTransientState(boolean hasTransientState) { 8646 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 8647 mTransientStateCount - 1; 8648 if (mTransientStateCount < 0) { 8649 mTransientStateCount = 0; 8650 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 8651 "unmatched pair of setHasTransientState calls"); 8652 } else if ((hasTransientState && mTransientStateCount == 1) || 8653 (!hasTransientState && mTransientStateCount == 0)) { 8654 // update flag if we've just incremented up from 0 or decremented down to 0 8655 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 8656 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 8657 if (mParent != null) { 8658 try { 8659 mParent.childHasTransientStateChanged(this, hasTransientState); 8660 } catch (AbstractMethodError e) { 8661 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 8662 " does not fully implement ViewParent", e); 8663 } 8664 } 8665 } 8666 } 8667 8668 /** 8669 * Returns true if this view is currently attached to a window. 8670 */ 8671 public boolean isAttachedToWindow() { 8672 return mAttachInfo != null; 8673 } 8674 8675 /** 8676 * Returns true if this view has been through at least one layout since it 8677 * was last attached to or detached from a window. 8678 */ 8679 public boolean isLaidOut() { 8680 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 8681 } 8682 8683 /** 8684 * If this view doesn't do any drawing on its own, set this flag to 8685 * allow further optimizations. By default, this flag is not set on 8686 * View, but could be set on some View subclasses such as ViewGroup. 8687 * 8688 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 8689 * you should clear this flag. 8690 * 8691 * @param willNotDraw whether or not this View draw on its own 8692 */ 8693 public void setWillNotDraw(boolean willNotDraw) { 8694 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 8695 } 8696 8697 /** 8698 * Returns whether or not this View draws on its own. 8699 * 8700 * @return true if this view has nothing to draw, false otherwise 8701 */ 8702 @ViewDebug.ExportedProperty(category = "drawing") 8703 public boolean willNotDraw() { 8704 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 8705 } 8706 8707 /** 8708 * When a View's drawing cache is enabled, drawing is redirected to an 8709 * offscreen bitmap. Some views, like an ImageView, must be able to 8710 * bypass this mechanism if they already draw a single bitmap, to avoid 8711 * unnecessary usage of the memory. 8712 * 8713 * @param willNotCacheDrawing true if this view does not cache its 8714 * drawing, false otherwise 8715 */ 8716 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 8717 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 8718 } 8719 8720 /** 8721 * Returns whether or not this View can cache its drawing or not. 8722 * 8723 * @return true if this view does not cache its drawing, false otherwise 8724 */ 8725 @ViewDebug.ExportedProperty(category = "drawing") 8726 public boolean willNotCacheDrawing() { 8727 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 8728 } 8729 8730 /** 8731 * Indicates whether this view reacts to click events or not. 8732 * 8733 * @return true if the view is clickable, false otherwise 8734 * 8735 * @see #setClickable(boolean) 8736 * @attr ref android.R.styleable#View_clickable 8737 */ 8738 @ViewDebug.ExportedProperty 8739 public boolean isClickable() { 8740 return (mViewFlags & CLICKABLE) == CLICKABLE; 8741 } 8742 8743 /** 8744 * Enables or disables click events for this view. When a view 8745 * is clickable it will change its state to "pressed" on every click. 8746 * Subclasses should set the view clickable to visually react to 8747 * user's clicks. 8748 * 8749 * @param clickable true to make the view clickable, false otherwise 8750 * 8751 * @see #isClickable() 8752 * @attr ref android.R.styleable#View_clickable 8753 */ 8754 public void setClickable(boolean clickable) { 8755 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 8756 } 8757 8758 /** 8759 * Indicates whether this view reacts to long click events or not. 8760 * 8761 * @return true if the view is long clickable, false otherwise 8762 * 8763 * @see #setLongClickable(boolean) 8764 * @attr ref android.R.styleable#View_longClickable 8765 */ 8766 public boolean isLongClickable() { 8767 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 8768 } 8769 8770 /** 8771 * Enables or disables long click events for this view. When a view is long 8772 * clickable it reacts to the user holding down the button for a longer 8773 * duration than a tap. This event can either launch the listener or a 8774 * context menu. 8775 * 8776 * @param longClickable true to make the view long clickable, false otherwise 8777 * @see #isLongClickable() 8778 * @attr ref android.R.styleable#View_longClickable 8779 */ 8780 public void setLongClickable(boolean longClickable) { 8781 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 8782 } 8783 8784 /** 8785 * Indicates whether this view reacts to context clicks or not. 8786 * 8787 * @return true if the view is context clickable, false otherwise 8788 * @see #setContextClickable(boolean) 8789 * @attr ref android.R.styleable#View_contextClickable 8790 */ 8791 public boolean isContextClickable() { 8792 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 8793 } 8794 8795 /** 8796 * Enables or disables context clicking for this view. This event can launch the listener. 8797 * 8798 * @param contextClickable true to make the view react to a context click, false otherwise 8799 * @see #isContextClickable() 8800 * @attr ref android.R.styleable#View_contextClickable 8801 */ 8802 public void setContextClickable(boolean contextClickable) { 8803 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 8804 } 8805 8806 /** 8807 * Sets the pressed state for this view and provides a touch coordinate for 8808 * animation hinting. 8809 * 8810 * @param pressed Pass true to set the View's internal state to "pressed", 8811 * or false to reverts the View's internal state from a 8812 * previously set "pressed" state. 8813 * @param x The x coordinate of the touch that caused the press 8814 * @param y The y coordinate of the touch that caused the press 8815 */ 8816 private void setPressed(boolean pressed, float x, float y) { 8817 if (pressed) { 8818 drawableHotspotChanged(x, y); 8819 } 8820 8821 setPressed(pressed); 8822 } 8823 8824 /** 8825 * Sets the pressed state for this view. 8826 * 8827 * @see #isClickable() 8828 * @see #setClickable(boolean) 8829 * 8830 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 8831 * the View's internal state from a previously set "pressed" state. 8832 */ 8833 public void setPressed(boolean pressed) { 8834 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 8835 8836 if (pressed) { 8837 mPrivateFlags |= PFLAG_PRESSED; 8838 } else { 8839 mPrivateFlags &= ~PFLAG_PRESSED; 8840 } 8841 8842 if (needsRefresh) { 8843 refreshDrawableState(); 8844 } 8845 dispatchSetPressed(pressed); 8846 } 8847 8848 /** 8849 * Dispatch setPressed to all of this View's children. 8850 * 8851 * @see #setPressed(boolean) 8852 * 8853 * @param pressed The new pressed state 8854 */ 8855 protected void dispatchSetPressed(boolean pressed) { 8856 } 8857 8858 /** 8859 * Indicates whether the view is currently in pressed state. Unless 8860 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 8861 * the pressed state. 8862 * 8863 * @see #setPressed(boolean) 8864 * @see #isClickable() 8865 * @see #setClickable(boolean) 8866 * 8867 * @return true if the view is currently pressed, false otherwise 8868 */ 8869 @ViewDebug.ExportedProperty 8870 public boolean isPressed() { 8871 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 8872 } 8873 8874 /** 8875 * @hide 8876 * Indicates whether this view will participate in data collection through 8877 * {@link ViewStructure}. If true, it will not provide any data 8878 * for itself or its children. If false, the normal data collection will be allowed. 8879 * 8880 * @return Returns false if assist data collection is not blocked, else true. 8881 * 8882 * @see #setAssistBlocked(boolean) 8883 * @attr ref android.R.styleable#View_assistBlocked 8884 */ 8885 public boolean isAssistBlocked() { 8886 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 8887 } 8888 8889 /** 8890 * @hide 8891 * Indicates whether this view will participate in data collection through 8892 * {@link ViewStructure} for auto-fill purposes. 8893 * 8894 * <p>If {@code true}, it will not provide any data for itself or its children. 8895 * <p>If {@code false}, the normal data collection will be allowed. 8896 * 8897 * @return Returns {@code false} if assist data collection for auto-fill is not blocked, 8898 * else {@code true}. 8899 * 8900 * TODO(b/33197203): update / remove javadoc tags below 8901 * @see #setAssistBlocked(boolean) 8902 * @attr ref android.R.styleable#View_assistBlocked 8903 */ 8904 public boolean isAutoFillBlocked() { 8905 return false; // TODO(b/33197203): properly implement it 8906 } 8907 8908 /** 8909 * @hide 8910 * Controls whether assist data collection from this view and its children is enabled 8911 * (that is, whether {@link #onProvideStructure} and 8912 * {@link #onProvideVirtualStructure} will be called). The default value is false, 8913 * allowing normal assist collection. Setting this to false will disable assist collection. 8914 * 8915 * @param enabled Set to true to <em>disable</em> assist data collection, or false 8916 * (the default) to allow it. 8917 * 8918 * @see #isAssistBlocked() 8919 * @see #onProvideStructure 8920 * @see #onProvideVirtualStructure 8921 * @attr ref android.R.styleable#View_assistBlocked 8922 */ 8923 public void setAssistBlocked(boolean enabled) { 8924 if (enabled) { 8925 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 8926 } else { 8927 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 8928 } 8929 } 8930 8931 /** 8932 * Indicates whether this view will save its state (that is, 8933 * whether its {@link #onSaveInstanceState} method will be called). 8934 * 8935 * @return Returns true if the view state saving is enabled, else false. 8936 * 8937 * @see #setSaveEnabled(boolean) 8938 * @attr ref android.R.styleable#View_saveEnabled 8939 */ 8940 public boolean isSaveEnabled() { 8941 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 8942 } 8943 8944 /** 8945 * Controls whether the saving of this view's state is 8946 * enabled (that is, whether its {@link #onSaveInstanceState} method 8947 * will be called). Note that even if freezing is enabled, the 8948 * view still must have an id assigned to it (via {@link #setId(int)}) 8949 * for its state to be saved. This flag can only disable the 8950 * saving of this view; any child views may still have their state saved. 8951 * 8952 * @param enabled Set to false to <em>disable</em> state saving, or true 8953 * (the default) to allow it. 8954 * 8955 * @see #isSaveEnabled() 8956 * @see #setId(int) 8957 * @see #onSaveInstanceState() 8958 * @attr ref android.R.styleable#View_saveEnabled 8959 */ 8960 public void setSaveEnabled(boolean enabled) { 8961 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 8962 } 8963 8964 /** 8965 * Gets whether the framework should discard touches when the view's 8966 * window is obscured by another visible window. 8967 * Refer to the {@link View} security documentation for more details. 8968 * 8969 * @return True if touch filtering is enabled. 8970 * 8971 * @see #setFilterTouchesWhenObscured(boolean) 8972 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 8973 */ 8974 @ViewDebug.ExportedProperty 8975 public boolean getFilterTouchesWhenObscured() { 8976 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 8977 } 8978 8979 /** 8980 * Sets whether the framework should discard touches when the view's 8981 * window is obscured by another visible window. 8982 * Refer to the {@link View} security documentation for more details. 8983 * 8984 * @param enabled True if touch filtering should be enabled. 8985 * 8986 * @see #getFilterTouchesWhenObscured 8987 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 8988 */ 8989 public void setFilterTouchesWhenObscured(boolean enabled) { 8990 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 8991 FILTER_TOUCHES_WHEN_OBSCURED); 8992 } 8993 8994 /** 8995 * Indicates whether the entire hierarchy under this view will save its 8996 * state when a state saving traversal occurs from its parent. The default 8997 * is true; if false, these views will not be saved unless 8998 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 8999 * 9000 * @return Returns true if the view state saving from parent is enabled, else false. 9001 * 9002 * @see #setSaveFromParentEnabled(boolean) 9003 */ 9004 public boolean isSaveFromParentEnabled() { 9005 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 9006 } 9007 9008 /** 9009 * Controls whether the entire hierarchy under this view will save its 9010 * state when a state saving traversal occurs from its parent. The default 9011 * is true; if false, these views will not be saved unless 9012 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9013 * 9014 * @param enabled Set to false to <em>disable</em> state saving, or true 9015 * (the default) to allow it. 9016 * 9017 * @see #isSaveFromParentEnabled() 9018 * @see #setId(int) 9019 * @see #onSaveInstanceState() 9020 */ 9021 public void setSaveFromParentEnabled(boolean enabled) { 9022 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 9023 } 9024 9025 9026 /** 9027 * Returns whether this View is able to take focus. 9028 * 9029 * @return True if this view can take focus, or false otherwise. 9030 * @attr ref android.R.styleable#View_focusable 9031 */ 9032 @ViewDebug.ExportedProperty(category = "focus") 9033 public final boolean isFocusable() { 9034 return FOCUSABLE == (mViewFlags & FOCUSABLE_MASK); 9035 } 9036 9037 /** 9038 * When a view is focusable, it may not want to take focus when in touch mode. 9039 * For example, a button would like focus when the user is navigating via a D-pad 9040 * so that the user can click on it, but once the user starts touching the screen, 9041 * the button shouldn't take focus 9042 * @return Whether the view is focusable in touch mode. 9043 * @attr ref android.R.styleable#View_focusableInTouchMode 9044 */ 9045 @ViewDebug.ExportedProperty 9046 public final boolean isFocusableInTouchMode() { 9047 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 9048 } 9049 9050 /** 9051 * Find the nearest view in the specified direction that can take focus. 9052 * This does not actually give focus to that view. 9053 * 9054 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9055 * 9056 * @return The nearest focusable in the specified direction, or null if none 9057 * can be found. 9058 */ 9059 public View focusSearch(@FocusRealDirection int direction) { 9060 if (mParent != null) { 9061 return mParent.focusSearch(this, direction); 9062 } else { 9063 return null; 9064 } 9065 } 9066 9067 /** 9068 * Returns whether this View is a root of a keyboard navigation cluster. 9069 * 9070 * @return True if this view is a root of a cluster, or false otherwise. 9071 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9072 */ 9073 @ViewDebug.ExportedProperty(category = "keyboardNavigationCluster") 9074 public final boolean isKeyboardNavigationCluster() { 9075 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 9076 } 9077 9078 /** 9079 * Set whether this view is a root of a keyboard navigation cluster. 9080 * 9081 * @param isCluster If true, this view is a root of a cluster. 9082 * 9083 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9084 */ 9085 public void setKeyboardNavigationCluster(boolean isCluster) { 9086 if (isCluster) { 9087 mPrivateFlags3 |= PFLAG3_CLUSTER; 9088 } else { 9089 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 9090 } 9091 } 9092 9093 /** 9094 * Returns whether this View is a root of a keyboard navigation section. 9095 * 9096 * @return True if this view is a root of a section, or false otherwise. 9097 * @attr ref android.R.styleable#View_keyboardNavigationSection 9098 */ 9099 @ViewDebug.ExportedProperty(category = "keyboardNavigationSection") 9100 public final boolean isKeyboardNavigationSection() { 9101 return (mPrivateFlags3 & PFLAG3_SECTION) != 0; 9102 } 9103 9104 /** 9105 * Set whether this view is a root of a keyboard navigation section. 9106 * 9107 * @param isSection If true, this view is a root of a section. 9108 * 9109 * @attr ref android.R.styleable#View_keyboardNavigationSection 9110 */ 9111 public void setKeyboardNavigationSection(boolean isSection) { 9112 if (isSection) { 9113 mPrivateFlags3 |= PFLAG3_SECTION; 9114 } else { 9115 mPrivateFlags3 &= ~PFLAG3_SECTION; 9116 } 9117 } 9118 9119 final boolean isKeyboardNavigationGroupOfType(@KeyboardNavigationGroupType int groupType) { 9120 switch (groupType) { 9121 case KEYBOARD_NAVIGATION_GROUP_CLUSTER: 9122 return isKeyboardNavigationCluster(); 9123 case KEYBOARD_NAVIGATION_GROUP_SECTION: 9124 return isKeyboardNavigationSection(); 9125 default: 9126 throw new IllegalArgumentException( 9127 "Unknown keyboard navigation group type: " + groupType); 9128 } 9129 } 9130 9131 /** 9132 * Find the nearest keyboard navigation group in the specified direction. The group type can be 9133 * either a cluster or a section. 9134 * This does not actually give focus to that group. 9135 * 9136 * @param groupType Type of the keyboard navigation group 9137 * @param currentGroup The starting point of the search. Null means the current group is not 9138 * found yet 9139 * @param direction Direction to look 9140 * 9141 * @return The nearest keyboard navigation group in the specified direction, or null if none 9142 * can be found 9143 */ 9144 public View keyboardNavigationGroupSearch( 9145 @KeyboardNavigationGroupType int groupType, View currentGroup, int direction) { 9146 if (isKeyboardNavigationGroupOfType(groupType)) { 9147 currentGroup = this; 9148 } 9149 if (isRootNamespace() 9150 || (groupType == KEYBOARD_NAVIGATION_GROUP_SECTION 9151 && isKeyboardNavigationCluster())) { 9152 // Root namespace means we should consider ourselves the top of the 9153 // tree for group searching; otherwise we could be group searching 9154 // into other tabs. see LocalActivityManager and TabHost for more info. 9155 // In addition, a cluster node works as a root for section searches. 9156 return FocusFinder.getInstance().findNextKeyboardNavigationGroup( 9157 groupType, this, currentGroup, direction); 9158 } else if (mParent != null) { 9159 return mParent.keyboardNavigationGroupSearch( 9160 groupType, currentGroup, direction); 9161 } 9162 return null; 9163 } 9164 9165 /** 9166 * This method is the last chance for the focused view and its ancestors to 9167 * respond to an arrow key. This is called when the focused view did not 9168 * consume the key internally, nor could the view system find a new view in 9169 * the requested direction to give focus to. 9170 * 9171 * @param focused The currently focused view. 9172 * @param direction The direction focus wants to move. One of FOCUS_UP, 9173 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 9174 * @return True if the this view consumed this unhandled move. 9175 */ 9176 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 9177 return false; 9178 } 9179 9180 /** 9181 * If a user manually specified the next view id for a particular direction, 9182 * use the root to look up the view. 9183 * @param root The root view of the hierarchy containing this view. 9184 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 9185 * or FOCUS_BACKWARD. 9186 * @return The user specified next view, or null if there is none. 9187 */ 9188 View findUserSetNextFocus(View root, @FocusDirection int direction) { 9189 switch (direction) { 9190 case FOCUS_LEFT: 9191 if (mNextFocusLeftId == View.NO_ID) return null; 9192 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 9193 case FOCUS_RIGHT: 9194 if (mNextFocusRightId == View.NO_ID) return null; 9195 return findViewInsideOutShouldExist(root, mNextFocusRightId); 9196 case FOCUS_UP: 9197 if (mNextFocusUpId == View.NO_ID) return null; 9198 return findViewInsideOutShouldExist(root, mNextFocusUpId); 9199 case FOCUS_DOWN: 9200 if (mNextFocusDownId == View.NO_ID) return null; 9201 return findViewInsideOutShouldExist(root, mNextFocusDownId); 9202 case FOCUS_FORWARD: 9203 if (mNextFocusForwardId == View.NO_ID) return null; 9204 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 9205 case FOCUS_BACKWARD: { 9206 if (mID == View.NO_ID) return null; 9207 final int id = mID; 9208 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 9209 @Override 9210 public boolean apply(View t) { 9211 return t.mNextFocusForwardId == id; 9212 } 9213 }); 9214 } 9215 } 9216 return null; 9217 } 9218 9219 private View findViewInsideOutShouldExist(View root, int id) { 9220 if (mMatchIdPredicate == null) { 9221 mMatchIdPredicate = new MatchIdPredicate(); 9222 } 9223 mMatchIdPredicate.mId = id; 9224 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 9225 if (result == null) { 9226 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 9227 } 9228 return result; 9229 } 9230 9231 /** 9232 * Find and return all focusable views that are descendants of this view, 9233 * possibly including this view if it is focusable itself. 9234 * 9235 * @param direction The direction of the focus 9236 * @return A list of focusable views 9237 */ 9238 public ArrayList<View> getFocusables(@FocusDirection int direction) { 9239 ArrayList<View> result = new ArrayList<View>(24); 9240 addFocusables(result, direction); 9241 return result; 9242 } 9243 9244 /** 9245 * Add any focusable views that are descendants of this view (possibly 9246 * including this view if it is focusable itself) to views. If we are in touch mode, 9247 * only add views that are also focusable in touch mode. 9248 * 9249 * @param views Focusable views found so far 9250 * @param direction The direction of the focus 9251 */ 9252 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 9253 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 9254 } 9255 9256 /** 9257 * Adds any focusable views that are descendants of this view (possibly 9258 * including this view if it is focusable itself) to views. This method 9259 * adds all focusable views regardless if we are in touch mode or 9260 * only views focusable in touch mode if we are in touch mode or 9261 * only views that can take accessibility focus if accessibility is enabled 9262 * depending on the focusable mode parameter. 9263 * 9264 * @param views Focusable views found so far or null if all we are interested is 9265 * the number of focusables. 9266 * @param direction The direction of the focus. 9267 * @param focusableMode The type of focusables to be added. 9268 * 9269 * @see #FOCUSABLES_ALL 9270 * @see #FOCUSABLES_TOUCH_MODE 9271 */ 9272 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 9273 @FocusableMode int focusableMode) { 9274 if (views == null) { 9275 return; 9276 } 9277 if (!isFocusable()) { 9278 return; 9279 } 9280 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 9281 && !isFocusableInTouchMode()) { 9282 return; 9283 } 9284 views.add(this); 9285 } 9286 9287 /** 9288 * Adds any keyboard navigation group roots that are descendants of this view (possibly 9289 * including this view if it is a group root itself) to views. The group type can be either a 9290 * cluster or a section. 9291 * 9292 * @param groupType Type of the keyboard navigation group 9293 * @param views Keyboard navigation group roots found so far 9294 * @param direction Direction to look 9295 */ 9296 public void addKeyboardNavigationGroups( 9297 @KeyboardNavigationGroupType int groupType, 9298 @NonNull Collection<View> views, 9299 int direction) { 9300 if (!(isKeyboardNavigationGroupOfType(groupType))) { 9301 return; 9302 } 9303 views.add(this); 9304 } 9305 9306 /** 9307 * Finds the Views that contain given text. The containment is case insensitive. 9308 * The search is performed by either the text that the View renders or the content 9309 * description that describes the view for accessibility purposes and the view does 9310 * not render or both. Clients can specify how the search is to be performed via 9311 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 9312 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 9313 * 9314 * @param outViews The output list of matching Views. 9315 * @param searched The text to match against. 9316 * 9317 * @see #FIND_VIEWS_WITH_TEXT 9318 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 9319 * @see #setContentDescription(CharSequence) 9320 */ 9321 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 9322 @FindViewFlags int flags) { 9323 if (getAccessibilityNodeProvider() != null) { 9324 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 9325 outViews.add(this); 9326 } 9327 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 9328 && (searched != null && searched.length() > 0) 9329 && (mContentDescription != null && mContentDescription.length() > 0)) { 9330 String searchedLowerCase = searched.toString().toLowerCase(); 9331 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 9332 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 9333 outViews.add(this); 9334 } 9335 } 9336 } 9337 9338 /** 9339 * Find and return all touchable views that are descendants of this view, 9340 * possibly including this view if it is touchable itself. 9341 * 9342 * @return A list of touchable views 9343 */ 9344 public ArrayList<View> getTouchables() { 9345 ArrayList<View> result = new ArrayList<View>(); 9346 addTouchables(result); 9347 return result; 9348 } 9349 9350 /** 9351 * Add any touchable views that are descendants of this view (possibly 9352 * including this view if it is touchable itself) to views. 9353 * 9354 * @param views Touchable views found so far 9355 */ 9356 public void addTouchables(ArrayList<View> views) { 9357 final int viewFlags = mViewFlags; 9358 9359 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 9360 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 9361 && (viewFlags & ENABLED_MASK) == ENABLED) { 9362 views.add(this); 9363 } 9364 } 9365 9366 /** 9367 * Returns whether this View is accessibility focused. 9368 * 9369 * @return True if this View is accessibility focused. 9370 */ 9371 public boolean isAccessibilityFocused() { 9372 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 9373 } 9374 9375 /** 9376 * Call this to try to give accessibility focus to this view. 9377 * 9378 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 9379 * returns false or the view is no visible or the view already has accessibility 9380 * focus. 9381 * 9382 * See also {@link #focusSearch(int)}, which is what you call to say that you 9383 * have focus, and you want your parent to look for the next one. 9384 * 9385 * @return Whether this view actually took accessibility focus. 9386 * 9387 * @hide 9388 */ 9389 public boolean requestAccessibilityFocus() { 9390 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 9391 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 9392 return false; 9393 } 9394 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9395 return false; 9396 } 9397 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 9398 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 9399 ViewRootImpl viewRootImpl = getViewRootImpl(); 9400 if (viewRootImpl != null) { 9401 viewRootImpl.setAccessibilityFocus(this, null); 9402 } 9403 invalidate(); 9404 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 9405 return true; 9406 } 9407 return false; 9408 } 9409 9410 /** 9411 * Call this to try to clear accessibility focus of this view. 9412 * 9413 * See also {@link #focusSearch(int)}, which is what you call to say that you 9414 * have focus, and you want your parent to look for the next one. 9415 * 9416 * @hide 9417 */ 9418 public void clearAccessibilityFocus() { 9419 clearAccessibilityFocusNoCallbacks(0); 9420 9421 // Clear the global reference of accessibility focus if this view or 9422 // any of its descendants had accessibility focus. This will NOT send 9423 // an event or update internal state if focus is cleared from a 9424 // descendant view, which may leave views in inconsistent states. 9425 final ViewRootImpl viewRootImpl = getViewRootImpl(); 9426 if (viewRootImpl != null) { 9427 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 9428 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 9429 viewRootImpl.setAccessibilityFocus(null, null); 9430 } 9431 } 9432 } 9433 9434 private void sendAccessibilityHoverEvent(int eventType) { 9435 // Since we are not delivering to a client accessibility events from not 9436 // important views (unless the clinet request that) we need to fire the 9437 // event from the deepest view exposed to the client. As a consequence if 9438 // the user crosses a not exposed view the client will see enter and exit 9439 // of the exposed predecessor followed by and enter and exit of that same 9440 // predecessor when entering and exiting the not exposed descendant. This 9441 // is fine since the client has a clear idea which view is hovered at the 9442 // price of a couple more events being sent. This is a simple and 9443 // working solution. 9444 View source = this; 9445 while (true) { 9446 if (source.includeForAccessibility()) { 9447 source.sendAccessibilityEvent(eventType); 9448 return; 9449 } 9450 ViewParent parent = source.getParent(); 9451 if (parent instanceof View) { 9452 source = (View) parent; 9453 } else { 9454 return; 9455 } 9456 } 9457 } 9458 9459 /** 9460 * Clears accessibility focus without calling any callback methods 9461 * normally invoked in {@link #clearAccessibilityFocus()}. This method 9462 * is used separately from that one for clearing accessibility focus when 9463 * giving this focus to another view. 9464 * 9465 * @param action The action, if any, that led to focus being cleared. Set to 9466 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 9467 * the window. 9468 */ 9469 void clearAccessibilityFocusNoCallbacks(int action) { 9470 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 9471 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 9472 invalidate(); 9473 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 9474 AccessibilityEvent event = AccessibilityEvent.obtain( 9475 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 9476 event.setAction(action); 9477 if (mAccessibilityDelegate != null) { 9478 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 9479 } else { 9480 sendAccessibilityEventUnchecked(event); 9481 } 9482 } 9483 } 9484 } 9485 9486 /** 9487 * Call this to try to give focus to a specific view or to one of its 9488 * descendants. 9489 * 9490 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9491 * false), or if it is focusable and it is not focusable in touch mode 9492 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9493 * 9494 * See also {@link #focusSearch(int)}, which is what you call to say that you 9495 * have focus, and you want your parent to look for the next one. 9496 * 9497 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 9498 * {@link #FOCUS_DOWN} and <code>null</code>. 9499 * 9500 * @return Whether this view or one of its descendants actually took focus. 9501 */ 9502 public final boolean requestFocus() { 9503 return requestFocus(View.FOCUS_DOWN); 9504 } 9505 9506 /** 9507 * Gives focus to the last focused view in the view hierarchy that has this view as a root. 9508 * If the last focused view cannot be found, fall back to calling {@link #requestFocus()}. 9509 * Nested keyboard navigation clusters are excluded from the hierarchy considered for saving the 9510 * last focus. 9511 * 9512 * @return Whether this view or one of its descendants actually took focus. 9513 */ 9514 public boolean restoreLastFocus() { 9515 return requestFocus(); 9516 } 9517 9518 /** 9519 * Call this to try to give focus to a specific view or to one of its 9520 * descendants and give it a hint about what direction focus is heading. 9521 * 9522 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9523 * false), or if it is focusable and it is not focusable in touch mode 9524 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9525 * 9526 * See also {@link #focusSearch(int)}, which is what you call to say that you 9527 * have focus, and you want your parent to look for the next one. 9528 * 9529 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 9530 * <code>null</code> set for the previously focused rectangle. 9531 * 9532 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9533 * @return Whether this view or one of its descendants actually took focus. 9534 */ 9535 public final boolean requestFocus(int direction) { 9536 return requestFocus(direction, null); 9537 } 9538 9539 /** 9540 * Call this to try to give focus to a specific view or to one of its descendants 9541 * and give it hints about the direction and a specific rectangle that the focus 9542 * is coming from. The rectangle can help give larger views a finer grained hint 9543 * about where focus is coming from, and therefore, where to show selection, or 9544 * forward focus change internally. 9545 * 9546 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9547 * false), or if it is focusable and it is not focusable in touch mode 9548 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9549 * 9550 * A View will not take focus if it is not visible. 9551 * 9552 * A View will not take focus if one of its parents has 9553 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 9554 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 9555 * 9556 * See also {@link #focusSearch(int)}, which is what you call to say that you 9557 * have focus, and you want your parent to look for the next one. 9558 * 9559 * You may wish to override this method if your custom {@link View} has an internal 9560 * {@link View} that it wishes to forward the request to. 9561 * 9562 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9563 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 9564 * to give a finer grained hint about where focus is coming from. May be null 9565 * if there is no hint. 9566 * @return Whether this view or one of its descendants actually took focus. 9567 */ 9568 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 9569 return requestFocusNoSearch(direction, previouslyFocusedRect); 9570 } 9571 9572 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 9573 // need to be focusable 9574 if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE || 9575 (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9576 return false; 9577 } 9578 9579 // need to be focusable in touch mode if in touch mode 9580 if (isInTouchMode() && 9581 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 9582 return false; 9583 } 9584 9585 // need to not have any parents blocking us 9586 if (hasAncestorThatBlocksDescendantFocus()) { 9587 return false; 9588 } 9589 9590 handleFocusGainInternal(direction, previouslyFocusedRect); 9591 return true; 9592 } 9593 9594 /** 9595 * Call this to try to give focus to a specific view or to one of its descendants. This is a 9596 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 9597 * touch mode to request focus when they are touched. 9598 * 9599 * @return Whether this view or one of its descendants actually took focus. 9600 * 9601 * @see #isInTouchMode() 9602 * 9603 */ 9604 public final boolean requestFocusFromTouch() { 9605 // Leave touch mode if we need to 9606 if (isInTouchMode()) { 9607 ViewRootImpl viewRoot = getViewRootImpl(); 9608 if (viewRoot != null) { 9609 viewRoot.ensureTouchMode(false); 9610 } 9611 } 9612 return requestFocus(View.FOCUS_DOWN); 9613 } 9614 9615 /** 9616 * @return Whether any ancestor of this view blocks descendant focus. 9617 */ 9618 private boolean hasAncestorThatBlocksDescendantFocus() { 9619 final boolean focusableInTouchMode = isFocusableInTouchMode(); 9620 ViewParent ancestor = mParent; 9621 while (ancestor instanceof ViewGroup) { 9622 final ViewGroup vgAncestor = (ViewGroup) ancestor; 9623 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 9624 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 9625 return true; 9626 } else { 9627 ancestor = vgAncestor.getParent(); 9628 } 9629 } 9630 return false; 9631 } 9632 9633 /** 9634 * Gets the mode for determining whether this View is important for accessibility. 9635 * A view is important for accessibility if it fires accessibility events and if it 9636 * is reported to accessibility services that query the screen. 9637 * 9638 * @return The mode for determining whether a view is important for accessibility, one 9639 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 9640 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 9641 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 9642 * 9643 * @attr ref android.R.styleable#View_importantForAccessibility 9644 * 9645 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9646 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9647 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9648 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9649 */ 9650 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 9651 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 9652 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 9653 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 9654 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 9655 to = "noHideDescendants") 9656 }) 9657 public int getImportantForAccessibility() { 9658 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9659 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9660 } 9661 9662 /** 9663 * Sets the live region mode for this view. This indicates to accessibility 9664 * services whether they should automatically notify the user about changes 9665 * to the view's content description or text, or to the content descriptions 9666 * or text of the view's children (where applicable). 9667 * <p> 9668 * For example, in a login screen with a TextView that displays an "incorrect 9669 * password" notification, that view should be marked as a live region with 9670 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9671 * <p> 9672 * To disable change notifications for this view, use 9673 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 9674 * mode for most views. 9675 * <p> 9676 * To indicate that the user should be notified of changes, use 9677 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9678 * <p> 9679 * If the view's changes should interrupt ongoing speech and notify the user 9680 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 9681 * 9682 * @param mode The live region mode for this view, one of: 9683 * <ul> 9684 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 9685 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 9686 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 9687 * </ul> 9688 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9689 */ 9690 public void setAccessibilityLiveRegion(int mode) { 9691 if (mode != getAccessibilityLiveRegion()) { 9692 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9693 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 9694 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9695 notifyViewAccessibilityStateChangedIfNeeded( 9696 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9697 } 9698 } 9699 9700 /** 9701 * Gets the live region mode for this View. 9702 * 9703 * @return The live region mode for the view. 9704 * 9705 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9706 * 9707 * @see #setAccessibilityLiveRegion(int) 9708 */ 9709 public int getAccessibilityLiveRegion() { 9710 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 9711 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 9712 } 9713 9714 /** 9715 * Sets how to determine whether this view is important for accessibility 9716 * which is if it fires accessibility events and if it is reported to 9717 * accessibility services that query the screen. 9718 * 9719 * @param mode How to determine whether this view is important for accessibility. 9720 * 9721 * @attr ref android.R.styleable#View_importantForAccessibility 9722 * 9723 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9724 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9725 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9726 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9727 */ 9728 public void setImportantForAccessibility(int mode) { 9729 final int oldMode = getImportantForAccessibility(); 9730 if (mode != oldMode) { 9731 final boolean hideDescendants = 9732 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 9733 9734 // If this node or its descendants are no longer important, try to 9735 // clear accessibility focus. 9736 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 9737 final View focusHost = findAccessibilityFocusHost(hideDescendants); 9738 if (focusHost != null) { 9739 focusHost.clearAccessibilityFocus(); 9740 } 9741 } 9742 9743 // If we're moving between AUTO and another state, we might not need 9744 // to send a subtree changed notification. We'll store the computed 9745 // importance, since we'll need to check it later to make sure. 9746 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 9747 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 9748 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 9749 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9750 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 9751 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9752 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 9753 notifySubtreeAccessibilityStateChangedIfNeeded(); 9754 } else { 9755 notifyViewAccessibilityStateChangedIfNeeded( 9756 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9757 } 9758 } 9759 } 9760 9761 /** 9762 * Returns the view within this view's hierarchy that is hosting 9763 * accessibility focus. 9764 * 9765 * @param searchDescendants whether to search for focus in descendant views 9766 * @return the view hosting accessibility focus, or {@code null} 9767 */ 9768 private View findAccessibilityFocusHost(boolean searchDescendants) { 9769 if (isAccessibilityFocusedViewOrHost()) { 9770 return this; 9771 } 9772 9773 if (searchDescendants) { 9774 final ViewRootImpl viewRoot = getViewRootImpl(); 9775 if (viewRoot != null) { 9776 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 9777 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 9778 return focusHost; 9779 } 9780 } 9781 } 9782 9783 return null; 9784 } 9785 9786 /** 9787 * Computes whether this view should be exposed for accessibility. In 9788 * general, views that are interactive or provide information are exposed 9789 * while views that serve only as containers are hidden. 9790 * <p> 9791 * If an ancestor of this view has importance 9792 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 9793 * returns <code>false</code>. 9794 * <p> 9795 * Otherwise, the value is computed according to the view's 9796 * {@link #getImportantForAccessibility()} value: 9797 * <ol> 9798 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 9799 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 9800 * </code> 9801 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 9802 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 9803 * view satisfies any of the following: 9804 * <ul> 9805 * <li>Is actionable, e.g. {@link #isClickable()}, 9806 * {@link #isLongClickable()}, or {@link #isFocusable()} 9807 * <li>Has an {@link AccessibilityDelegate} 9808 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 9809 * {@link OnKeyListener}, etc. 9810 * <li>Is an accessibility live region, e.g. 9811 * {@link #getAccessibilityLiveRegion()} is not 9812 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 9813 * </ul> 9814 * </ol> 9815 * 9816 * @return Whether the view is exposed for accessibility. 9817 * @see #setImportantForAccessibility(int) 9818 * @see #getImportantForAccessibility() 9819 */ 9820 public boolean isImportantForAccessibility() { 9821 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9822 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9823 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 9824 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 9825 return false; 9826 } 9827 9828 // Check parent mode to ensure we're not hidden. 9829 ViewParent parent = mParent; 9830 while (parent instanceof View) { 9831 if (((View) parent).getImportantForAccessibility() 9832 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 9833 return false; 9834 } 9835 parent = parent.getParent(); 9836 } 9837 9838 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 9839 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 9840 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 9841 } 9842 9843 /** 9844 * Gets the parent for accessibility purposes. Note that the parent for 9845 * accessibility is not necessary the immediate parent. It is the first 9846 * predecessor that is important for accessibility. 9847 * 9848 * @return The parent for accessibility purposes. 9849 */ 9850 public ViewParent getParentForAccessibility() { 9851 if (mParent instanceof View) { 9852 View parentView = (View) mParent; 9853 if (parentView.includeForAccessibility()) { 9854 return mParent; 9855 } else { 9856 return mParent.getParentForAccessibility(); 9857 } 9858 } 9859 return null; 9860 } 9861 9862 /** 9863 * Adds the children of this View relevant for accessibility to the given list 9864 * as output. Since some Views are not important for accessibility the added 9865 * child views are not necessarily direct children of this view, rather they are 9866 * the first level of descendants important for accessibility. 9867 * 9868 * @param outChildren The output list that will receive children for accessibility. 9869 */ 9870 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 9871 9872 } 9873 9874 /** 9875 * Whether to regard this view for accessibility. A view is regarded for 9876 * accessibility if it is important for accessibility or the querying 9877 * accessibility service has explicitly requested that view not 9878 * important for accessibility are regarded. 9879 * 9880 * @return Whether to regard the view for accessibility. 9881 * 9882 * @hide 9883 */ 9884 public boolean includeForAccessibility() { 9885 if (mAttachInfo != null) { 9886 return (mAttachInfo.mAccessibilityFetchFlags 9887 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 9888 || isImportantForAccessibility(); 9889 } 9890 return false; 9891 } 9892 9893 /** 9894 * Returns whether the View is considered actionable from 9895 * accessibility perspective. Such view are important for 9896 * accessibility. 9897 * 9898 * @return True if the view is actionable for accessibility. 9899 * 9900 * @hide 9901 */ 9902 public boolean isActionableForAccessibility() { 9903 return (isClickable() || isLongClickable() || isFocusable()); 9904 } 9905 9906 /** 9907 * Returns whether the View has registered callbacks which makes it 9908 * important for accessibility. 9909 * 9910 * @return True if the view is actionable for accessibility. 9911 */ 9912 private boolean hasListenersForAccessibility() { 9913 ListenerInfo info = getListenerInfo(); 9914 return mTouchDelegate != null || info.mOnKeyListener != null 9915 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 9916 || info.mOnHoverListener != null || info.mOnDragListener != null; 9917 } 9918 9919 /** 9920 * Notifies that the accessibility state of this view changed. The change 9921 * is local to this view and does not represent structural changes such 9922 * as children and parent. For example, the view became focusable. The 9923 * notification is at at most once every 9924 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 9925 * to avoid unnecessary load to the system. Also once a view has a pending 9926 * notification this method is a NOP until the notification has been sent. 9927 * 9928 * @hide 9929 */ 9930 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 9931 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 9932 return; 9933 } 9934 if (mSendViewStateChangedAccessibilityEvent == null) { 9935 mSendViewStateChangedAccessibilityEvent = 9936 new SendViewStateChangedAccessibilityEvent(); 9937 } 9938 mSendViewStateChangedAccessibilityEvent.runOrPost(changeType); 9939 } 9940 9941 /** 9942 * Notifies that the accessibility state of this view changed. The change 9943 * is *not* local to this view and does represent structural changes such 9944 * as children and parent. For example, the view size changed. The 9945 * notification is at at most once every 9946 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 9947 * to avoid unnecessary load to the system. Also once a view has a pending 9948 * notification this method is a NOP until the notification has been sent. 9949 * 9950 * @hide 9951 */ 9952 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 9953 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 9954 return; 9955 } 9956 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 9957 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 9958 if (mParent != null) { 9959 try { 9960 mParent.notifySubtreeAccessibilityStateChanged( 9961 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 9962 } catch (AbstractMethodError e) { 9963 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 9964 " does not fully implement ViewParent", e); 9965 } 9966 } 9967 } 9968 } 9969 9970 /** 9971 * Change the visibility of the View without triggering any other changes. This is 9972 * important for transitions, where visibility changes should not adjust focus or 9973 * trigger a new layout. This is only used when the visibility has already been changed 9974 * and we need a transient value during an animation. When the animation completes, 9975 * the original visibility value is always restored. 9976 * 9977 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9978 * @hide 9979 */ 9980 public void setTransitionVisibility(@Visibility int visibility) { 9981 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 9982 } 9983 9984 /** 9985 * Reset the flag indicating the accessibility state of the subtree rooted 9986 * at this view changed. 9987 */ 9988 void resetSubtreeAccessibilityStateChanged() { 9989 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 9990 } 9991 9992 /** 9993 * Report an accessibility action to this view's parents for delegated processing. 9994 * 9995 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 9996 * call this method to delegate an accessibility action to a supporting parent. If the parent 9997 * returns true from its 9998 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 9999 * method this method will return true to signify that the action was consumed.</p> 10000 * 10001 * <p>This method is useful for implementing nested scrolling child views. If 10002 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 10003 * a custom view implementation may invoke this method to allow a parent to consume the 10004 * scroll first. If this method returns true the custom view should skip its own scrolling 10005 * behavior.</p> 10006 * 10007 * @param action Accessibility action to delegate 10008 * @param arguments Optional action arguments 10009 * @return true if the action was consumed by a parent 10010 */ 10011 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 10012 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 10013 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 10014 return true; 10015 } 10016 } 10017 return false; 10018 } 10019 10020 /** 10021 * Performs the specified accessibility action on the view. For 10022 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 10023 * <p> 10024 * If an {@link AccessibilityDelegate} has been specified via calling 10025 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10026 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 10027 * is responsible for handling this call. 10028 * </p> 10029 * 10030 * <p>The default implementation will delegate 10031 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 10032 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 10033 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 10034 * 10035 * @param action The action to perform. 10036 * @param arguments Optional action arguments. 10037 * @return Whether the action was performed. 10038 */ 10039 public boolean performAccessibilityAction(int action, Bundle arguments) { 10040 if (mAccessibilityDelegate != null) { 10041 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 10042 } else { 10043 return performAccessibilityActionInternal(action, arguments); 10044 } 10045 } 10046 10047 /** 10048 * @see #performAccessibilityAction(int, Bundle) 10049 * 10050 * Note: Called from the default {@link AccessibilityDelegate}. 10051 * 10052 * @hide 10053 */ 10054 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 10055 if (isNestedScrollingEnabled() 10056 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 10057 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 10058 || action == R.id.accessibilityActionScrollUp 10059 || action == R.id.accessibilityActionScrollLeft 10060 || action == R.id.accessibilityActionScrollDown 10061 || action == R.id.accessibilityActionScrollRight)) { 10062 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 10063 return true; 10064 } 10065 } 10066 10067 switch (action) { 10068 case AccessibilityNodeInfo.ACTION_CLICK: { 10069 if (isClickable()) { 10070 performClick(); 10071 return true; 10072 } 10073 } break; 10074 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 10075 if (isLongClickable()) { 10076 performLongClick(); 10077 return true; 10078 } 10079 } break; 10080 case AccessibilityNodeInfo.ACTION_FOCUS: { 10081 if (!hasFocus()) { 10082 // Get out of touch mode since accessibility 10083 // wants to move focus around. 10084 getViewRootImpl().ensureTouchMode(false); 10085 return requestFocus(); 10086 } 10087 } break; 10088 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 10089 if (hasFocus()) { 10090 clearFocus(); 10091 return !isFocused(); 10092 } 10093 } break; 10094 case AccessibilityNodeInfo.ACTION_SELECT: { 10095 if (!isSelected()) { 10096 setSelected(true); 10097 return isSelected(); 10098 } 10099 } break; 10100 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 10101 if (isSelected()) { 10102 setSelected(false); 10103 return !isSelected(); 10104 } 10105 } break; 10106 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 10107 if (!isAccessibilityFocused()) { 10108 return requestAccessibilityFocus(); 10109 } 10110 } break; 10111 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 10112 if (isAccessibilityFocused()) { 10113 clearAccessibilityFocus(); 10114 return true; 10115 } 10116 } break; 10117 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 10118 if (arguments != null) { 10119 final int granularity = arguments.getInt( 10120 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10121 final boolean extendSelection = arguments.getBoolean( 10122 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10123 return traverseAtGranularity(granularity, true, extendSelection); 10124 } 10125 } break; 10126 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 10127 if (arguments != null) { 10128 final int granularity = arguments.getInt( 10129 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10130 final boolean extendSelection = arguments.getBoolean( 10131 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10132 return traverseAtGranularity(granularity, false, extendSelection); 10133 } 10134 } break; 10135 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 10136 CharSequence text = getIterableTextForAccessibility(); 10137 if (text == null) { 10138 return false; 10139 } 10140 final int start = (arguments != null) ? arguments.getInt( 10141 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 10142 final int end = (arguments != null) ? arguments.getInt( 10143 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 10144 // Only cursor position can be specified (selection length == 0) 10145 if ((getAccessibilitySelectionStart() != start 10146 || getAccessibilitySelectionEnd() != end) 10147 && (start == end)) { 10148 setAccessibilitySelection(start, end); 10149 notifyViewAccessibilityStateChangedIfNeeded( 10150 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10151 return true; 10152 } 10153 } break; 10154 case R.id.accessibilityActionShowOnScreen: { 10155 if (mAttachInfo != null) { 10156 final Rect r = mAttachInfo.mTmpInvalRect; 10157 getDrawingRect(r); 10158 return requestRectangleOnScreen(r, true); 10159 } 10160 } break; 10161 case R.id.accessibilityActionContextClick: { 10162 if (isContextClickable()) { 10163 performContextClick(); 10164 return true; 10165 } 10166 } break; 10167 } 10168 return false; 10169 } 10170 10171 private boolean traverseAtGranularity(int granularity, boolean forward, 10172 boolean extendSelection) { 10173 CharSequence text = getIterableTextForAccessibility(); 10174 if (text == null || text.length() == 0) { 10175 return false; 10176 } 10177 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 10178 if (iterator == null) { 10179 return false; 10180 } 10181 int current = getAccessibilitySelectionEnd(); 10182 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10183 current = forward ? 0 : text.length(); 10184 } 10185 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 10186 if (range == null) { 10187 return false; 10188 } 10189 final int segmentStart = range[0]; 10190 final int segmentEnd = range[1]; 10191 int selectionStart; 10192 int selectionEnd; 10193 if (extendSelection && isAccessibilitySelectionExtendable()) { 10194 selectionStart = getAccessibilitySelectionStart(); 10195 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10196 selectionStart = forward ? segmentStart : segmentEnd; 10197 } 10198 selectionEnd = forward ? segmentEnd : segmentStart; 10199 } else { 10200 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 10201 } 10202 setAccessibilitySelection(selectionStart, selectionEnd); 10203 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 10204 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 10205 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 10206 return true; 10207 } 10208 10209 /** 10210 * Gets the text reported for accessibility purposes. 10211 * 10212 * @return The accessibility text. 10213 * 10214 * @hide 10215 */ 10216 public CharSequence getIterableTextForAccessibility() { 10217 return getContentDescription(); 10218 } 10219 10220 /** 10221 * Gets whether accessibility selection can be extended. 10222 * 10223 * @return If selection is extensible. 10224 * 10225 * @hide 10226 */ 10227 public boolean isAccessibilitySelectionExtendable() { 10228 return false; 10229 } 10230 10231 /** 10232 * @hide 10233 */ 10234 public int getAccessibilitySelectionStart() { 10235 return mAccessibilityCursorPosition; 10236 } 10237 10238 /** 10239 * @hide 10240 */ 10241 public int getAccessibilitySelectionEnd() { 10242 return getAccessibilitySelectionStart(); 10243 } 10244 10245 /** 10246 * @hide 10247 */ 10248 public void setAccessibilitySelection(int start, int end) { 10249 if (start == end && end == mAccessibilityCursorPosition) { 10250 return; 10251 } 10252 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 10253 mAccessibilityCursorPosition = start; 10254 } else { 10255 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 10256 } 10257 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 10258 } 10259 10260 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 10261 int fromIndex, int toIndex) { 10262 if (mParent == null) { 10263 return; 10264 } 10265 AccessibilityEvent event = AccessibilityEvent.obtain( 10266 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 10267 onInitializeAccessibilityEvent(event); 10268 onPopulateAccessibilityEvent(event); 10269 event.setFromIndex(fromIndex); 10270 event.setToIndex(toIndex); 10271 event.setAction(action); 10272 event.setMovementGranularity(granularity); 10273 mParent.requestSendAccessibilityEvent(this, event); 10274 } 10275 10276 /** 10277 * @hide 10278 */ 10279 public TextSegmentIterator getIteratorForGranularity(int granularity) { 10280 switch (granularity) { 10281 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 10282 CharSequence text = getIterableTextForAccessibility(); 10283 if (text != null && text.length() > 0) { 10284 CharacterTextSegmentIterator iterator = 10285 CharacterTextSegmentIterator.getInstance( 10286 mContext.getResources().getConfiguration().locale); 10287 iterator.initialize(text.toString()); 10288 return iterator; 10289 } 10290 } break; 10291 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 10292 CharSequence text = getIterableTextForAccessibility(); 10293 if (text != null && text.length() > 0) { 10294 WordTextSegmentIterator iterator = 10295 WordTextSegmentIterator.getInstance( 10296 mContext.getResources().getConfiguration().locale); 10297 iterator.initialize(text.toString()); 10298 return iterator; 10299 } 10300 } break; 10301 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 10302 CharSequence text = getIterableTextForAccessibility(); 10303 if (text != null && text.length() > 0) { 10304 ParagraphTextSegmentIterator iterator = 10305 ParagraphTextSegmentIterator.getInstance(); 10306 iterator.initialize(text.toString()); 10307 return iterator; 10308 } 10309 } break; 10310 } 10311 return null; 10312 } 10313 10314 /** 10315 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 10316 * and {@link #onFinishTemporaryDetach()}. 10317 * 10318 * <p>This method always returns {@code true} when called directly or indirectly from 10319 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 10320 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 10321 * <ul> 10322 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 10323 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 10324 * </ul> 10325 * </p> 10326 * 10327 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 10328 * and {@link #onFinishTemporaryDetach()}. 10329 */ 10330 public final boolean isTemporarilyDetached() { 10331 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 10332 } 10333 10334 /** 10335 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 10336 * a container View. 10337 */ 10338 @CallSuper 10339 public void dispatchStartTemporaryDetach() { 10340 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 10341 onStartTemporaryDetach(); 10342 } 10343 10344 /** 10345 * This is called when a container is going to temporarily detach a child, with 10346 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 10347 * It will either be followed by {@link #onFinishTemporaryDetach()} or 10348 * {@link #onDetachedFromWindow()} when the container is done. 10349 */ 10350 public void onStartTemporaryDetach() { 10351 removeUnsetPressCallback(); 10352 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 10353 } 10354 10355 /** 10356 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 10357 * a container View. 10358 */ 10359 @CallSuper 10360 public void dispatchFinishTemporaryDetach() { 10361 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 10362 onFinishTemporaryDetach(); 10363 if (hasWindowFocus() && hasFocus()) { 10364 InputMethodManager.getInstance().focusIn(this); 10365 } 10366 } 10367 10368 /** 10369 * Called after {@link #onStartTemporaryDetach} when the container is done 10370 * changing the view. 10371 */ 10372 public void onFinishTemporaryDetach() { 10373 } 10374 10375 /** 10376 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 10377 * for this view's window. Returns null if the view is not currently attached 10378 * to the window. Normally you will not need to use this directly, but 10379 * just use the standard high-level event callbacks like 10380 * {@link #onKeyDown(int, KeyEvent)}. 10381 */ 10382 public KeyEvent.DispatcherState getKeyDispatcherState() { 10383 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 10384 } 10385 10386 /** 10387 * Dispatch a key event before it is processed by any input method 10388 * associated with the view hierarchy. This can be used to intercept 10389 * key events in special situations before the IME consumes them; a 10390 * typical example would be handling the BACK key to update the application's 10391 * UI instead of allowing the IME to see it and close itself. 10392 * 10393 * @param event The key event to be dispatched. 10394 * @return True if the event was handled, false otherwise. 10395 */ 10396 public boolean dispatchKeyEventPreIme(KeyEvent event) { 10397 return onKeyPreIme(event.getKeyCode(), event); 10398 } 10399 10400 /** 10401 * Dispatch a key event to the next view on the focus path. This path runs 10402 * from the top of the view tree down to the currently focused view. If this 10403 * view has focus, it will dispatch to itself. Otherwise it will dispatch 10404 * the next node down the focus path. This method also fires any key 10405 * listeners. 10406 * 10407 * @param event The key event to be dispatched. 10408 * @return True if the event was handled, false otherwise. 10409 */ 10410 public boolean dispatchKeyEvent(KeyEvent event) { 10411 if (mInputEventConsistencyVerifier != null) { 10412 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 10413 } 10414 10415 // Give any attached key listener a first crack at the event. 10416 //noinspection SimplifiableIfStatement 10417 ListenerInfo li = mListenerInfo; 10418 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 10419 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 10420 return true; 10421 } 10422 10423 if (event.dispatch(this, mAttachInfo != null 10424 ? mAttachInfo.mKeyDispatchState : null, this)) { 10425 return true; 10426 } 10427 10428 if (mInputEventConsistencyVerifier != null) { 10429 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10430 } 10431 return false; 10432 } 10433 10434 /** 10435 * Dispatches a key shortcut event. 10436 * 10437 * @param event The key event to be dispatched. 10438 * @return True if the event was handled by the view, false otherwise. 10439 */ 10440 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 10441 return onKeyShortcut(event.getKeyCode(), event); 10442 } 10443 10444 /** 10445 * Pass the touch screen motion event down to the target view, or this 10446 * view if it is the target. 10447 * 10448 * @param event The motion event to be dispatched. 10449 * @return True if the event was handled by the view, false otherwise. 10450 */ 10451 public boolean dispatchTouchEvent(MotionEvent event) { 10452 // If the event should be handled by accessibility focus first. 10453 if (event.isTargetAccessibilityFocus()) { 10454 // We don't have focus or no virtual descendant has it, do not handle the event. 10455 if (!isAccessibilityFocusedViewOrHost()) { 10456 return false; 10457 } 10458 // We have focus and got the event, then use normal event dispatch. 10459 event.setTargetAccessibilityFocus(false); 10460 } 10461 10462 boolean result = false; 10463 10464 if (mInputEventConsistencyVerifier != null) { 10465 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 10466 } 10467 10468 final int actionMasked = event.getActionMasked(); 10469 if (actionMasked == MotionEvent.ACTION_DOWN) { 10470 // Defensive cleanup for new gesture 10471 stopNestedScroll(); 10472 } 10473 10474 if (onFilterTouchEventForSecurity(event)) { 10475 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 10476 result = true; 10477 } 10478 //noinspection SimplifiableIfStatement 10479 ListenerInfo li = mListenerInfo; 10480 if (li != null && li.mOnTouchListener != null 10481 && (mViewFlags & ENABLED_MASK) == ENABLED 10482 && li.mOnTouchListener.onTouch(this, event)) { 10483 result = true; 10484 } 10485 10486 if (!result && onTouchEvent(event)) { 10487 result = true; 10488 } 10489 } 10490 10491 if (!result && mInputEventConsistencyVerifier != null) { 10492 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10493 } 10494 10495 // Clean up after nested scrolls if this is the end of a gesture; 10496 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 10497 // of the gesture. 10498 if (actionMasked == MotionEvent.ACTION_UP || 10499 actionMasked == MotionEvent.ACTION_CANCEL || 10500 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 10501 stopNestedScroll(); 10502 } 10503 10504 return result; 10505 } 10506 10507 boolean isAccessibilityFocusedViewOrHost() { 10508 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 10509 .getAccessibilityFocusedHost() == this); 10510 } 10511 10512 /** 10513 * Filter the touch event to apply security policies. 10514 * 10515 * @param event The motion event to be filtered. 10516 * @return True if the event should be dispatched, false if the event should be dropped. 10517 * 10518 * @see #getFilterTouchesWhenObscured 10519 */ 10520 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 10521 //noinspection RedundantIfStatement 10522 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 10523 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 10524 // Window is obscured, drop this touch. 10525 return false; 10526 } 10527 return true; 10528 } 10529 10530 /** 10531 * Pass a trackball motion event down to the focused view. 10532 * 10533 * @param event The motion event to be dispatched. 10534 * @return True if the event was handled by the view, false otherwise. 10535 */ 10536 public boolean dispatchTrackballEvent(MotionEvent event) { 10537 if (mInputEventConsistencyVerifier != null) { 10538 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 10539 } 10540 10541 return onTrackballEvent(event); 10542 } 10543 10544 /** 10545 * Dispatch a generic motion event. 10546 * <p> 10547 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 10548 * are delivered to the view under the pointer. All other generic motion events are 10549 * delivered to the focused view. Hover events are handled specially and are delivered 10550 * to {@link #onHoverEvent(MotionEvent)}. 10551 * </p> 10552 * 10553 * @param event The motion event to be dispatched. 10554 * @return True if the event was handled by the view, false otherwise. 10555 */ 10556 public boolean dispatchGenericMotionEvent(MotionEvent event) { 10557 if (mInputEventConsistencyVerifier != null) { 10558 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 10559 } 10560 10561 final int source = event.getSource(); 10562 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 10563 final int action = event.getAction(); 10564 if (action == MotionEvent.ACTION_HOVER_ENTER 10565 || action == MotionEvent.ACTION_HOVER_MOVE 10566 || action == MotionEvent.ACTION_HOVER_EXIT) { 10567 if (dispatchHoverEvent(event)) { 10568 return true; 10569 } 10570 } else if (dispatchGenericPointerEvent(event)) { 10571 return true; 10572 } 10573 } else if (dispatchGenericFocusedEvent(event)) { 10574 return true; 10575 } 10576 10577 if (dispatchGenericMotionEventInternal(event)) { 10578 return true; 10579 } 10580 10581 if (mInputEventConsistencyVerifier != null) { 10582 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10583 } 10584 return false; 10585 } 10586 10587 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 10588 //noinspection SimplifiableIfStatement 10589 ListenerInfo li = mListenerInfo; 10590 if (li != null && li.mOnGenericMotionListener != null 10591 && (mViewFlags & ENABLED_MASK) == ENABLED 10592 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 10593 return true; 10594 } 10595 10596 if (onGenericMotionEvent(event)) { 10597 return true; 10598 } 10599 10600 final int actionButton = event.getActionButton(); 10601 switch (event.getActionMasked()) { 10602 case MotionEvent.ACTION_BUTTON_PRESS: 10603 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 10604 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10605 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10606 if (performContextClick(event.getX(), event.getY())) { 10607 mInContextButtonPress = true; 10608 setPressed(true, event.getX(), event.getY()); 10609 removeTapCallback(); 10610 removeLongPressCallback(); 10611 return true; 10612 } 10613 } 10614 break; 10615 10616 case MotionEvent.ACTION_BUTTON_RELEASE: 10617 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10618 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10619 mInContextButtonPress = false; 10620 mIgnoreNextUpEvent = true; 10621 } 10622 break; 10623 } 10624 10625 if (mInputEventConsistencyVerifier != null) { 10626 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10627 } 10628 return false; 10629 } 10630 10631 /** 10632 * Dispatch a hover event. 10633 * <p> 10634 * Do not call this method directly. 10635 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10636 * </p> 10637 * 10638 * @param event The motion event to be dispatched. 10639 * @return True if the event was handled by the view, false otherwise. 10640 */ 10641 protected boolean dispatchHoverEvent(MotionEvent event) { 10642 ListenerInfo li = mListenerInfo; 10643 //noinspection SimplifiableIfStatement 10644 if (li != null && li.mOnHoverListener != null 10645 && (mViewFlags & ENABLED_MASK) == ENABLED 10646 && li.mOnHoverListener.onHover(this, event)) { 10647 return true; 10648 } 10649 10650 return onHoverEvent(event); 10651 } 10652 10653 /** 10654 * Returns true if the view has a child to which it has recently sent 10655 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 10656 * it does not have a hovered child, then it must be the innermost hovered view. 10657 * @hide 10658 */ 10659 protected boolean hasHoveredChild() { 10660 return false; 10661 } 10662 10663 /** 10664 * Dispatch a generic motion event to the view under the first pointer. 10665 * <p> 10666 * Do not call this method directly. 10667 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10668 * </p> 10669 * 10670 * @param event The motion event to be dispatched. 10671 * @return True if the event was handled by the view, false otherwise. 10672 */ 10673 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 10674 return false; 10675 } 10676 10677 /** 10678 * Dispatch a generic motion event to the currently focused view. 10679 * <p> 10680 * Do not call this method directly. 10681 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10682 * </p> 10683 * 10684 * @param event The motion event to be dispatched. 10685 * @return True if the event was handled by the view, false otherwise. 10686 */ 10687 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 10688 return false; 10689 } 10690 10691 /** 10692 * Dispatch a pointer event. 10693 * <p> 10694 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 10695 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 10696 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 10697 * and should not be expected to handle other pointing device features. 10698 * </p> 10699 * 10700 * @param event The motion event to be dispatched. 10701 * @return True if the event was handled by the view, false otherwise. 10702 * @hide 10703 */ 10704 public final boolean dispatchPointerEvent(MotionEvent event) { 10705 if (event.isTouchEvent()) { 10706 return dispatchTouchEvent(event); 10707 } else { 10708 return dispatchGenericMotionEvent(event); 10709 } 10710 } 10711 10712 /** 10713 * Called when the window containing this view gains or loses window focus. 10714 * ViewGroups should override to route to their children. 10715 * 10716 * @param hasFocus True if the window containing this view now has focus, 10717 * false otherwise. 10718 */ 10719 public void dispatchWindowFocusChanged(boolean hasFocus) { 10720 onWindowFocusChanged(hasFocus); 10721 } 10722 10723 /** 10724 * Called when the window containing this view gains or loses focus. Note 10725 * that this is separate from view focus: to receive key events, both 10726 * your view and its window must have focus. If a window is displayed 10727 * on top of yours that takes input focus, then your own window will lose 10728 * focus but the view focus will remain unchanged. 10729 * 10730 * @param hasWindowFocus True if the window containing this view now has 10731 * focus, false otherwise. 10732 */ 10733 public void onWindowFocusChanged(boolean hasWindowFocus) { 10734 InputMethodManager imm = InputMethodManager.peekInstance(); 10735 if (!hasWindowFocus) { 10736 if (isPressed()) { 10737 setPressed(false); 10738 } 10739 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 10740 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10741 imm.focusOut(this); 10742 } 10743 removeLongPressCallback(); 10744 removeTapCallback(); 10745 onFocusLost(); 10746 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10747 imm.focusIn(this); 10748 } 10749 refreshDrawableState(); 10750 } 10751 10752 /** 10753 * Returns true if this view is in a window that currently has window focus. 10754 * Note that this is not the same as the view itself having focus. 10755 * 10756 * @return True if this view is in a window that currently has window focus. 10757 */ 10758 public boolean hasWindowFocus() { 10759 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 10760 } 10761 10762 /** 10763 * Dispatch a view visibility change down the view hierarchy. 10764 * ViewGroups should override to route to their children. 10765 * @param changedView The view whose visibility changed. Could be 'this' or 10766 * an ancestor view. 10767 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 10768 * {@link #INVISIBLE} or {@link #GONE}. 10769 */ 10770 protected void dispatchVisibilityChanged(@NonNull View changedView, 10771 @Visibility int visibility) { 10772 onVisibilityChanged(changedView, visibility); 10773 } 10774 10775 /** 10776 * Called when the visibility of the view or an ancestor of the view has 10777 * changed. 10778 * 10779 * @param changedView The view whose visibility changed. May be 10780 * {@code this} or an ancestor view. 10781 * @param visibility The new visibility, one of {@link #VISIBLE}, 10782 * {@link #INVISIBLE} or {@link #GONE}. 10783 */ 10784 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 10785 } 10786 10787 /** 10788 * Dispatch a hint about whether this view is displayed. For instance, when 10789 * a View moves out of the screen, it might receives a display hint indicating 10790 * the view is not displayed. Applications should not <em>rely</em> on this hint 10791 * as there is no guarantee that they will receive one. 10792 * 10793 * @param hint A hint about whether or not this view is displayed: 10794 * {@link #VISIBLE} or {@link #INVISIBLE}. 10795 */ 10796 public void dispatchDisplayHint(@Visibility int hint) { 10797 onDisplayHint(hint); 10798 } 10799 10800 /** 10801 * Gives this view a hint about whether is displayed or not. For instance, when 10802 * a View moves out of the screen, it might receives a display hint indicating 10803 * the view is not displayed. Applications should not <em>rely</em> on this hint 10804 * as there is no guarantee that they will receive one. 10805 * 10806 * @param hint A hint about whether or not this view is displayed: 10807 * {@link #VISIBLE} or {@link #INVISIBLE}. 10808 */ 10809 protected void onDisplayHint(@Visibility int hint) { 10810 } 10811 10812 /** 10813 * Dispatch a window visibility change down the view hierarchy. 10814 * ViewGroups should override to route to their children. 10815 * 10816 * @param visibility The new visibility of the window. 10817 * 10818 * @see #onWindowVisibilityChanged(int) 10819 */ 10820 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 10821 onWindowVisibilityChanged(visibility); 10822 } 10823 10824 /** 10825 * Called when the window containing has change its visibility 10826 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 10827 * that this tells you whether or not your window is being made visible 10828 * to the window manager; this does <em>not</em> tell you whether or not 10829 * your window is obscured by other windows on the screen, even if it 10830 * is itself visible. 10831 * 10832 * @param visibility The new visibility of the window. 10833 */ 10834 protected void onWindowVisibilityChanged(@Visibility int visibility) { 10835 if (visibility == VISIBLE) { 10836 initialAwakenScrollBars(); 10837 } 10838 } 10839 10840 /** 10841 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 10842 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 10843 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 10844 * 10845 * @param isVisible true if this view's visibility to the user is uninterrupted by its 10846 * ancestors or by window visibility 10847 * @return true if this view is visible to the user, not counting clipping or overlapping 10848 */ 10849 boolean dispatchVisibilityAggregated(boolean isVisible) { 10850 final boolean thisVisible = getVisibility() == VISIBLE; 10851 // If we're not visible but something is telling us we are, ignore it. 10852 if (thisVisible || !isVisible) { 10853 onVisibilityAggregated(isVisible); 10854 } 10855 return thisVisible && isVisible; 10856 } 10857 10858 /** 10859 * Called when the user-visibility of this View is potentially affected by a change 10860 * to this view itself, an ancestor view or the window this view is attached to. 10861 * 10862 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 10863 * and this view's window is also visible 10864 */ 10865 @CallSuper 10866 public void onVisibilityAggregated(boolean isVisible) { 10867 if (isVisible && mAttachInfo != null) { 10868 initialAwakenScrollBars(); 10869 } 10870 10871 final Drawable dr = mBackground; 10872 if (dr != null && isVisible != dr.isVisible()) { 10873 dr.setVisible(isVisible, false); 10874 } 10875 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 10876 if (fg != null && isVisible != fg.isVisible()) { 10877 fg.setVisible(isVisible, false); 10878 } 10879 } 10880 10881 /** 10882 * Returns the current visibility of the window this view is attached to 10883 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 10884 * 10885 * @return Returns the current visibility of the view's window. 10886 */ 10887 @Visibility 10888 public int getWindowVisibility() { 10889 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 10890 } 10891 10892 /** 10893 * Retrieve the overall visible display size in which the window this view is 10894 * attached to has been positioned in. This takes into account screen 10895 * decorations above the window, for both cases where the window itself 10896 * is being position inside of them or the window is being placed under 10897 * then and covered insets are used for the window to position its content 10898 * inside. In effect, this tells you the available area where content can 10899 * be placed and remain visible to users. 10900 * 10901 * <p>This function requires an IPC back to the window manager to retrieve 10902 * the requested information, so should not be used in performance critical 10903 * code like drawing. 10904 * 10905 * @param outRect Filled in with the visible display frame. If the view 10906 * is not attached to a window, this is simply the raw display size. 10907 */ 10908 public void getWindowVisibleDisplayFrame(Rect outRect) { 10909 if (mAttachInfo != null) { 10910 try { 10911 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 10912 } catch (RemoteException e) { 10913 return; 10914 } 10915 // XXX This is really broken, and probably all needs to be done 10916 // in the window manager, and we need to know more about whether 10917 // we want the area behind or in front of the IME. 10918 final Rect insets = mAttachInfo.mVisibleInsets; 10919 outRect.left += insets.left; 10920 outRect.top += insets.top; 10921 outRect.right -= insets.right; 10922 outRect.bottom -= insets.bottom; 10923 return; 10924 } 10925 // The view is not attached to a display so we don't have a context. 10926 // Make a best guess about the display size. 10927 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 10928 d.getRectSize(outRect); 10929 } 10930 10931 /** 10932 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 10933 * is currently in without any insets. 10934 * 10935 * @hide 10936 */ 10937 public void getWindowDisplayFrame(Rect outRect) { 10938 if (mAttachInfo != null) { 10939 try { 10940 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 10941 } catch (RemoteException e) { 10942 return; 10943 } 10944 return; 10945 } 10946 // The view is not attached to a display so we don't have a context. 10947 // Make a best guess about the display size. 10948 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 10949 d.getRectSize(outRect); 10950 } 10951 10952 /** 10953 * Dispatch a notification about a resource configuration change down 10954 * the view hierarchy. 10955 * ViewGroups should override to route to their children. 10956 * 10957 * @param newConfig The new resource configuration. 10958 * 10959 * @see #onConfigurationChanged(android.content.res.Configuration) 10960 */ 10961 public void dispatchConfigurationChanged(Configuration newConfig) { 10962 onConfigurationChanged(newConfig); 10963 } 10964 10965 /** 10966 * Called when the current configuration of the resources being used 10967 * by the application have changed. You can use this to decide when 10968 * to reload resources that can changed based on orientation and other 10969 * configuration characteristics. You only need to use this if you are 10970 * not relying on the normal {@link android.app.Activity} mechanism of 10971 * recreating the activity instance upon a configuration change. 10972 * 10973 * @param newConfig The new resource configuration. 10974 */ 10975 protected void onConfigurationChanged(Configuration newConfig) { 10976 } 10977 10978 /** 10979 * Private function to aggregate all per-view attributes in to the view 10980 * root. 10981 */ 10982 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 10983 performCollectViewAttributes(attachInfo, visibility); 10984 } 10985 10986 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 10987 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 10988 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 10989 attachInfo.mKeepScreenOn = true; 10990 } 10991 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 10992 ListenerInfo li = mListenerInfo; 10993 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 10994 attachInfo.mHasSystemUiListeners = true; 10995 } 10996 } 10997 } 10998 10999 void needGlobalAttributesUpdate(boolean force) { 11000 final AttachInfo ai = mAttachInfo; 11001 if (ai != null && !ai.mRecomputeGlobalAttributes) { 11002 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 11003 || ai.mHasSystemUiListeners) { 11004 ai.mRecomputeGlobalAttributes = true; 11005 } 11006 } 11007 } 11008 11009 /** 11010 * Returns whether the device is currently in touch mode. Touch mode is entered 11011 * once the user begins interacting with the device by touch, and affects various 11012 * things like whether focus is always visible to the user. 11013 * 11014 * @return Whether the device is in touch mode. 11015 */ 11016 @ViewDebug.ExportedProperty 11017 public boolean isInTouchMode() { 11018 if (mAttachInfo != null) { 11019 return mAttachInfo.mInTouchMode; 11020 } else { 11021 return ViewRootImpl.isInTouchMode(); 11022 } 11023 } 11024 11025 /** 11026 * Returns the context the view is running in, through which it can 11027 * access the current theme, resources, etc. 11028 * 11029 * @return The view's Context. 11030 */ 11031 @ViewDebug.CapturedViewProperty 11032 public final Context getContext() { 11033 return mContext; 11034 } 11035 11036 /** 11037 * Handle a key event before it is processed by any input method 11038 * associated with the view hierarchy. This can be used to intercept 11039 * key events in special situations before the IME consumes them; a 11040 * typical example would be handling the BACK key to update the application's 11041 * UI instead of allowing the IME to see it and close itself. 11042 * 11043 * @param keyCode The value in event.getKeyCode(). 11044 * @param event Description of the key event. 11045 * @return If you handled the event, return true. If you want to allow the 11046 * event to be handled by the next receiver, return false. 11047 */ 11048 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 11049 return false; 11050 } 11051 11052 /** 11053 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 11054 * KeyEvent.Callback.onKeyDown()}: perform press of the view 11055 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 11056 * is released, if the view is enabled and clickable. 11057 * <p> 11058 * Key presses in software keyboards will generally NOT trigger this 11059 * listener, although some may elect to do so in some situations. Do not 11060 * rely on this to catch software key presses. 11061 * 11062 * @param keyCode a key code that represents the button pressed, from 11063 * {@link android.view.KeyEvent} 11064 * @param event the KeyEvent object that defines the button action 11065 */ 11066 public boolean onKeyDown(int keyCode, KeyEvent event) { 11067 if (KeyEvent.isConfirmKey(keyCode)) { 11068 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11069 return true; 11070 } 11071 11072 if (event.getRepeatCount() == 0) { 11073 // Long clickable items don't necessarily have to be clickable. 11074 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 11075 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 11076 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 11077 // For the purposes of menu anchoring and drawable hotspots, 11078 // key events are considered to be at the center of the view. 11079 final float x = getWidth() / 2f; 11080 final float y = getHeight() / 2f; 11081 if (clickable) { 11082 setPressed(true, x, y); 11083 } 11084 checkForLongClick(0, x, y); 11085 return true; 11086 } 11087 } 11088 } 11089 11090 return false; 11091 } 11092 11093 /** 11094 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 11095 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 11096 * the event). 11097 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11098 * although some may elect to do so in some situations. Do not rely on this to 11099 * catch software key presses. 11100 */ 11101 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 11102 return false; 11103 } 11104 11105 /** 11106 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 11107 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 11108 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 11109 * or {@link KeyEvent#KEYCODE_SPACE} is released. 11110 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11111 * although some may elect to do so in some situations. Do not rely on this to 11112 * catch software key presses. 11113 * 11114 * @param keyCode A key code that represents the button pressed, from 11115 * {@link android.view.KeyEvent}. 11116 * @param event The KeyEvent object that defines the button action. 11117 */ 11118 public boolean onKeyUp(int keyCode, KeyEvent event) { 11119 if (KeyEvent.isConfirmKey(keyCode)) { 11120 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11121 return true; 11122 } 11123 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 11124 setPressed(false); 11125 11126 if (!mHasPerformedLongPress) { 11127 // This is a tap, so remove the longpress check 11128 removeLongPressCallback(); 11129 return performClick(); 11130 } 11131 } 11132 } 11133 return false; 11134 } 11135 11136 /** 11137 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 11138 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 11139 * the event). 11140 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11141 * although some may elect to do so in some situations. Do not rely on this to 11142 * catch software key presses. 11143 * 11144 * @param keyCode A key code that represents the button pressed, from 11145 * {@link android.view.KeyEvent}. 11146 * @param repeatCount The number of times the action was made. 11147 * @param event The KeyEvent object that defines the button action. 11148 */ 11149 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 11150 return false; 11151 } 11152 11153 /** 11154 * Called on the focused view when a key shortcut event is not handled. 11155 * Override this method to implement local key shortcuts for the View. 11156 * Key shortcuts can also be implemented by setting the 11157 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 11158 * 11159 * @param keyCode The value in event.getKeyCode(). 11160 * @param event Description of the key event. 11161 * @return If you handled the event, return true. If you want to allow the 11162 * event to be handled by the next receiver, return false. 11163 */ 11164 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 11165 return false; 11166 } 11167 11168 /** 11169 * Check whether the called view is a text editor, in which case it 11170 * would make sense to automatically display a soft input window for 11171 * it. Subclasses should override this if they implement 11172 * {@link #onCreateInputConnection(EditorInfo)} to return true if 11173 * a call on that method would return a non-null InputConnection, and 11174 * they are really a first-class editor that the user would normally 11175 * start typing on when the go into a window containing your view. 11176 * 11177 * <p>The default implementation always returns false. This does 11178 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 11179 * will not be called or the user can not otherwise perform edits on your 11180 * view; it is just a hint to the system that this is not the primary 11181 * purpose of this view. 11182 * 11183 * @return Returns true if this view is a text editor, else false. 11184 */ 11185 public boolean onCheckIsTextEditor() { 11186 return false; 11187 } 11188 11189 /** 11190 * Create a new InputConnection for an InputMethod to interact 11191 * with the view. The default implementation returns null, since it doesn't 11192 * support input methods. You can override this to implement such support. 11193 * This is only needed for views that take focus and text input. 11194 * 11195 * <p>When implementing this, you probably also want to implement 11196 * {@link #onCheckIsTextEditor()} to indicate you will return a 11197 * non-null InputConnection.</p> 11198 * 11199 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 11200 * object correctly and in its entirety, so that the connected IME can rely 11201 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 11202 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 11203 * must be filled in with the correct cursor position for IMEs to work correctly 11204 * with your application.</p> 11205 * 11206 * @param outAttrs Fill in with attribute information about the connection. 11207 */ 11208 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 11209 return null; 11210 } 11211 11212 /** 11213 * Called by the {@link android.view.inputmethod.InputMethodManager} 11214 * when a view who is not the current 11215 * input connection target is trying to make a call on the manager. The 11216 * default implementation returns false; you can override this to return 11217 * true for certain views if you are performing InputConnection proxying 11218 * to them. 11219 * @param view The View that is making the InputMethodManager call. 11220 * @return Return true to allow the call, false to reject. 11221 */ 11222 public boolean checkInputConnectionProxy(View view) { 11223 return false; 11224 } 11225 11226 /** 11227 * Show the context menu for this view. It is not safe to hold on to the 11228 * menu after returning from this method. 11229 * 11230 * You should normally not overload this method. Overload 11231 * {@link #onCreateContextMenu(ContextMenu)} or define an 11232 * {@link OnCreateContextMenuListener} to add items to the context menu. 11233 * 11234 * @param menu The context menu to populate 11235 */ 11236 public void createContextMenu(ContextMenu menu) { 11237 ContextMenuInfo menuInfo = getContextMenuInfo(); 11238 11239 // Sets the current menu info so all items added to menu will have 11240 // my extra info set. 11241 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 11242 11243 onCreateContextMenu(menu); 11244 ListenerInfo li = mListenerInfo; 11245 if (li != null && li.mOnCreateContextMenuListener != null) { 11246 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 11247 } 11248 11249 // Clear the extra information so subsequent items that aren't mine don't 11250 // have my extra info. 11251 ((MenuBuilder)menu).setCurrentMenuInfo(null); 11252 11253 if (mParent != null) { 11254 mParent.createContextMenu(menu); 11255 } 11256 } 11257 11258 /** 11259 * Views should implement this if they have extra information to associate 11260 * with the context menu. The return result is supplied as a parameter to 11261 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 11262 * callback. 11263 * 11264 * @return Extra information about the item for which the context menu 11265 * should be shown. This information will vary across different 11266 * subclasses of View. 11267 */ 11268 protected ContextMenuInfo getContextMenuInfo() { 11269 return null; 11270 } 11271 11272 /** 11273 * Views should implement this if the view itself is going to add items to 11274 * the context menu. 11275 * 11276 * @param menu the context menu to populate 11277 */ 11278 protected void onCreateContextMenu(ContextMenu menu) { 11279 } 11280 11281 /** 11282 * Implement this method to handle trackball motion events. The 11283 * <em>relative</em> movement of the trackball since the last event 11284 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 11285 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 11286 * that a movement of 1 corresponds to the user pressing one DPAD key (so 11287 * they will often be fractional values, representing the more fine-grained 11288 * movement information available from a trackball). 11289 * 11290 * @param event The motion event. 11291 * @return True if the event was handled, false otherwise. 11292 */ 11293 public boolean onTrackballEvent(MotionEvent event) { 11294 return false; 11295 } 11296 11297 /** 11298 * Implement this method to handle generic motion events. 11299 * <p> 11300 * Generic motion events describe joystick movements, mouse hovers, track pad 11301 * touches, scroll wheel movements and other input events. The 11302 * {@link MotionEvent#getSource() source} of the motion event specifies 11303 * the class of input that was received. Implementations of this method 11304 * must examine the bits in the source before processing the event. 11305 * The following code example shows how this is done. 11306 * </p><p> 11307 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11308 * are delivered to the view under the pointer. All other generic motion events are 11309 * delivered to the focused view. 11310 * </p> 11311 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 11312 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 11313 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 11314 * // process the joystick movement... 11315 * return true; 11316 * } 11317 * } 11318 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 11319 * switch (event.getAction()) { 11320 * case MotionEvent.ACTION_HOVER_MOVE: 11321 * // process the mouse hover movement... 11322 * return true; 11323 * case MotionEvent.ACTION_SCROLL: 11324 * // process the scroll wheel movement... 11325 * return true; 11326 * } 11327 * } 11328 * return super.onGenericMotionEvent(event); 11329 * }</pre> 11330 * 11331 * @param event The generic motion event being processed. 11332 * @return True if the event was handled, false otherwise. 11333 */ 11334 public boolean onGenericMotionEvent(MotionEvent event) { 11335 return false; 11336 } 11337 11338 /** 11339 * Implement this method to handle hover events. 11340 * <p> 11341 * This method is called whenever a pointer is hovering into, over, or out of the 11342 * bounds of a view and the view is not currently being touched. 11343 * Hover events are represented as pointer events with action 11344 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 11345 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 11346 * </p> 11347 * <ul> 11348 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 11349 * when the pointer enters the bounds of the view.</li> 11350 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 11351 * when the pointer has already entered the bounds of the view and has moved.</li> 11352 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 11353 * when the pointer has exited the bounds of the view or when the pointer is 11354 * about to go down due to a button click, tap, or similar user action that 11355 * causes the view to be touched.</li> 11356 * </ul> 11357 * <p> 11358 * The view should implement this method to return true to indicate that it is 11359 * handling the hover event, such as by changing its drawable state. 11360 * </p><p> 11361 * The default implementation calls {@link #setHovered} to update the hovered state 11362 * of the view when a hover enter or hover exit event is received, if the view 11363 * is enabled and is clickable. The default implementation also sends hover 11364 * accessibility events. 11365 * </p> 11366 * 11367 * @param event The motion event that describes the hover. 11368 * @return True if the view handled the hover event. 11369 * 11370 * @see #isHovered 11371 * @see #setHovered 11372 * @see #onHoverChanged 11373 */ 11374 public boolean onHoverEvent(MotionEvent event) { 11375 // The root view may receive hover (or touch) events that are outside the bounds of 11376 // the window. This code ensures that we only send accessibility events for 11377 // hovers that are actually within the bounds of the root view. 11378 final int action = event.getActionMasked(); 11379 if (!mSendingHoverAccessibilityEvents) { 11380 if ((action == MotionEvent.ACTION_HOVER_ENTER 11381 || action == MotionEvent.ACTION_HOVER_MOVE) 11382 && !hasHoveredChild() 11383 && pointInView(event.getX(), event.getY())) { 11384 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 11385 mSendingHoverAccessibilityEvents = true; 11386 } 11387 } else { 11388 if (action == MotionEvent.ACTION_HOVER_EXIT 11389 || (action == MotionEvent.ACTION_MOVE 11390 && !pointInView(event.getX(), event.getY()))) { 11391 mSendingHoverAccessibilityEvents = false; 11392 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 11393 } 11394 } 11395 11396 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 11397 && event.isFromSource(InputDevice.SOURCE_MOUSE) 11398 && isOnScrollbar(event.getX(), event.getY())) { 11399 awakenScrollBars(); 11400 } 11401 if (isHoverable()) { 11402 switch (action) { 11403 case MotionEvent.ACTION_HOVER_ENTER: 11404 setHovered(true); 11405 break; 11406 case MotionEvent.ACTION_HOVER_EXIT: 11407 setHovered(false); 11408 break; 11409 } 11410 11411 // Dispatch the event to onGenericMotionEvent before returning true. 11412 // This is to provide compatibility with existing applications that 11413 // handled HOVER_MOVE events in onGenericMotionEvent and that would 11414 // break because of the new default handling for hoverable views 11415 // in onHoverEvent. 11416 // Note that onGenericMotionEvent will be called by default when 11417 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 11418 dispatchGenericMotionEventInternal(event); 11419 // The event was already handled by calling setHovered(), so always 11420 // return true. 11421 return true; 11422 } 11423 11424 return false; 11425 } 11426 11427 /** 11428 * Returns true if the view should handle {@link #onHoverEvent} 11429 * by calling {@link #setHovered} to change its hovered state. 11430 * 11431 * @return True if the view is hoverable. 11432 */ 11433 private boolean isHoverable() { 11434 final int viewFlags = mViewFlags; 11435 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11436 return false; 11437 } 11438 11439 return (viewFlags & CLICKABLE) == CLICKABLE 11440 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 11441 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11442 } 11443 11444 /** 11445 * Returns true if the view is currently hovered. 11446 * 11447 * @return True if the view is currently hovered. 11448 * 11449 * @see #setHovered 11450 * @see #onHoverChanged 11451 */ 11452 @ViewDebug.ExportedProperty 11453 public boolean isHovered() { 11454 return (mPrivateFlags & PFLAG_HOVERED) != 0; 11455 } 11456 11457 /** 11458 * Sets whether the view is currently hovered. 11459 * <p> 11460 * Calling this method also changes the drawable state of the view. This 11461 * enables the view to react to hover by using different drawable resources 11462 * to change its appearance. 11463 * </p><p> 11464 * The {@link #onHoverChanged} method is called when the hovered state changes. 11465 * </p> 11466 * 11467 * @param hovered True if the view is hovered. 11468 * 11469 * @see #isHovered 11470 * @see #onHoverChanged 11471 */ 11472 public void setHovered(boolean hovered) { 11473 if (hovered) { 11474 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 11475 mPrivateFlags |= PFLAG_HOVERED; 11476 refreshDrawableState(); 11477 onHoverChanged(true); 11478 } 11479 } else { 11480 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 11481 mPrivateFlags &= ~PFLAG_HOVERED; 11482 refreshDrawableState(); 11483 onHoverChanged(false); 11484 } 11485 } 11486 } 11487 11488 /** 11489 * Implement this method to handle hover state changes. 11490 * <p> 11491 * This method is called whenever the hover state changes as a result of a 11492 * call to {@link #setHovered}. 11493 * </p> 11494 * 11495 * @param hovered The current hover state, as returned by {@link #isHovered}. 11496 * 11497 * @see #isHovered 11498 * @see #setHovered 11499 */ 11500 public void onHoverChanged(boolean hovered) { 11501 } 11502 11503 /** 11504 * Handles scroll bar dragging by mouse input. 11505 * 11506 * @hide 11507 * @param event The motion event. 11508 * 11509 * @return true if the event was handled as a scroll bar dragging, false otherwise. 11510 */ 11511 protected boolean handleScrollBarDragging(MotionEvent event) { 11512 if (mScrollCache == null) { 11513 return false; 11514 } 11515 final float x = event.getX(); 11516 final float y = event.getY(); 11517 final int action = event.getAction(); 11518 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 11519 && action != MotionEvent.ACTION_DOWN) 11520 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 11521 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 11522 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11523 return false; 11524 } 11525 11526 switch (action) { 11527 case MotionEvent.ACTION_MOVE: 11528 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 11529 return false; 11530 } 11531 if (mScrollCache.mScrollBarDraggingState 11532 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 11533 final Rect bounds = mScrollCache.mScrollBarBounds; 11534 getVerticalScrollBarBounds(bounds); 11535 final int range = computeVerticalScrollRange(); 11536 final int offset = computeVerticalScrollOffset(); 11537 final int extent = computeVerticalScrollExtent(); 11538 11539 final int thumbLength = ScrollBarUtils.getThumbLength( 11540 bounds.height(), bounds.width(), extent, range); 11541 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11542 bounds.height(), thumbLength, extent, range, offset); 11543 11544 final float diff = y - mScrollCache.mScrollBarDraggingPos; 11545 final float maxThumbOffset = bounds.height() - thumbLength; 11546 final float newThumbOffset = 11547 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11548 final int height = getHeight(); 11549 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11550 && height > 0 && extent > 0) { 11551 final int newY = Math.round((range - extent) 11552 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 11553 if (newY != getScrollY()) { 11554 mScrollCache.mScrollBarDraggingPos = y; 11555 setScrollY(newY); 11556 } 11557 } 11558 return true; 11559 } 11560 if (mScrollCache.mScrollBarDraggingState 11561 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 11562 final Rect bounds = mScrollCache.mScrollBarBounds; 11563 getHorizontalScrollBarBounds(bounds); 11564 final int range = computeHorizontalScrollRange(); 11565 final int offset = computeHorizontalScrollOffset(); 11566 final int extent = computeHorizontalScrollExtent(); 11567 11568 final int thumbLength = ScrollBarUtils.getThumbLength( 11569 bounds.width(), bounds.height(), extent, range); 11570 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11571 bounds.width(), thumbLength, extent, range, offset); 11572 11573 final float diff = x - mScrollCache.mScrollBarDraggingPos; 11574 final float maxThumbOffset = bounds.width() - thumbLength; 11575 final float newThumbOffset = 11576 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11577 final int width = getWidth(); 11578 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11579 && width > 0 && extent > 0) { 11580 final int newX = Math.round((range - extent) 11581 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 11582 if (newX != getScrollX()) { 11583 mScrollCache.mScrollBarDraggingPos = x; 11584 setScrollX(newX); 11585 } 11586 } 11587 return true; 11588 } 11589 case MotionEvent.ACTION_DOWN: 11590 if (mScrollCache.state == ScrollabilityCache.OFF) { 11591 return false; 11592 } 11593 if (isOnVerticalScrollbarThumb(x, y)) { 11594 mScrollCache.mScrollBarDraggingState = 11595 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 11596 mScrollCache.mScrollBarDraggingPos = y; 11597 return true; 11598 } 11599 if (isOnHorizontalScrollbarThumb(x, y)) { 11600 mScrollCache.mScrollBarDraggingState = 11601 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 11602 mScrollCache.mScrollBarDraggingPos = x; 11603 return true; 11604 } 11605 } 11606 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11607 return false; 11608 } 11609 11610 /** 11611 * Implement this method to handle touch screen motion events. 11612 * <p> 11613 * If this method is used to detect click actions, it is recommended that 11614 * the actions be performed by implementing and calling 11615 * {@link #performClick()}. This will ensure consistent system behavior, 11616 * including: 11617 * <ul> 11618 * <li>obeying click sound preferences 11619 * <li>dispatching OnClickListener calls 11620 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 11621 * accessibility features are enabled 11622 * </ul> 11623 * 11624 * @param event The motion event. 11625 * @return True if the event was handled, false otherwise. 11626 */ 11627 public boolean onTouchEvent(MotionEvent event) { 11628 final float x = event.getX(); 11629 final float y = event.getY(); 11630 final int viewFlags = mViewFlags; 11631 final int action = event.getAction(); 11632 11633 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 11634 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 11635 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11636 11637 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11638 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 11639 setPressed(false); 11640 } 11641 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11642 // A disabled view that is clickable still consumes the touch 11643 // events, it just doesn't respond to them. 11644 return clickable; 11645 } 11646 if (mTouchDelegate != null) { 11647 if (mTouchDelegate.onTouchEvent(event)) { 11648 return true; 11649 } 11650 } 11651 11652 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 11653 switch (action) { 11654 case MotionEvent.ACTION_UP: 11655 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11656 if ((viewFlags & TOOLTIP) == TOOLTIP) { 11657 handleTooltipUp(); 11658 } 11659 if (!clickable) { 11660 removeTapCallback(); 11661 removeLongPressCallback(); 11662 mInContextButtonPress = false; 11663 mHasPerformedLongPress = false; 11664 mIgnoreNextUpEvent = false; 11665 break; 11666 } 11667 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 11668 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 11669 // take focus if we don't have it already and we should in 11670 // touch mode. 11671 boolean focusTaken = false; 11672 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 11673 focusTaken = requestFocus(); 11674 } 11675 11676 if (prepressed) { 11677 // The button is being released before we actually 11678 // showed it as pressed. Make it show the pressed 11679 // state now (before scheduling the click) to ensure 11680 // the user sees it. 11681 setPressed(true, x, y); 11682 } 11683 11684 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 11685 // This is a tap, so remove the longpress check 11686 removeLongPressCallback(); 11687 11688 // Only perform take click actions if we were in the pressed state 11689 if (!focusTaken) { 11690 // Use a Runnable and post this rather than calling 11691 // performClick directly. This lets other visual state 11692 // of the view update before click actions start. 11693 if (mPerformClick == null) { 11694 mPerformClick = new PerformClick(); 11695 } 11696 if (!post(mPerformClick)) { 11697 performClick(); 11698 } 11699 } 11700 } 11701 11702 if (mUnsetPressedState == null) { 11703 mUnsetPressedState = new UnsetPressedState(); 11704 } 11705 11706 if (prepressed) { 11707 postDelayed(mUnsetPressedState, 11708 ViewConfiguration.getPressedStateDuration()); 11709 } else if (!post(mUnsetPressedState)) { 11710 // If the post failed, unpress right now 11711 mUnsetPressedState.run(); 11712 } 11713 11714 removeTapCallback(); 11715 } 11716 mIgnoreNextUpEvent = false; 11717 break; 11718 11719 case MotionEvent.ACTION_DOWN: 11720 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 11721 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 11722 } 11723 mHasPerformedLongPress = false; 11724 11725 if (!clickable) { 11726 checkForLongClick(0, x, y); 11727 break; 11728 } 11729 11730 if (performButtonActionOnTouchDown(event)) { 11731 break; 11732 } 11733 11734 // Walk up the hierarchy to determine if we're inside a scrolling container. 11735 boolean isInScrollingContainer = isInScrollingContainer(); 11736 11737 // For views inside a scrolling container, delay the pressed feedback for 11738 // a short period in case this is a scroll. 11739 if (isInScrollingContainer) { 11740 mPrivateFlags |= PFLAG_PREPRESSED; 11741 if (mPendingCheckForTap == null) { 11742 mPendingCheckForTap = new CheckForTap(); 11743 } 11744 mPendingCheckForTap.x = event.getX(); 11745 mPendingCheckForTap.y = event.getY(); 11746 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 11747 } else { 11748 // Not inside a scrolling container, so show the feedback right away 11749 setPressed(true, x, y); 11750 checkForLongClick(0, x, y); 11751 } 11752 break; 11753 11754 case MotionEvent.ACTION_CANCEL: 11755 if (clickable) { 11756 setPressed(false); 11757 } 11758 removeTapCallback(); 11759 removeLongPressCallback(); 11760 mInContextButtonPress = false; 11761 mHasPerformedLongPress = false; 11762 mIgnoreNextUpEvent = false; 11763 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11764 break; 11765 11766 case MotionEvent.ACTION_MOVE: 11767 if (clickable) { 11768 drawableHotspotChanged(x, y); 11769 } 11770 11771 // Be lenient about moving outside of buttons 11772 if (!pointInView(x, y, mTouchSlop)) { 11773 // Outside button 11774 // Remove any future long press/tap checks 11775 removeTapCallback(); 11776 removeLongPressCallback(); 11777 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 11778 setPressed(false); 11779 } 11780 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11781 } 11782 break; 11783 } 11784 11785 return true; 11786 } 11787 11788 return false; 11789 } 11790 11791 /** 11792 * @hide 11793 */ 11794 public boolean isInScrollingContainer() { 11795 ViewParent p = getParent(); 11796 while (p != null && p instanceof ViewGroup) { 11797 if (((ViewGroup) p).shouldDelayChildPressedState()) { 11798 return true; 11799 } 11800 p = p.getParent(); 11801 } 11802 return false; 11803 } 11804 11805 /** 11806 * Remove the longpress detection timer. 11807 */ 11808 private void removeLongPressCallback() { 11809 if (mPendingCheckForLongPress != null) { 11810 removeCallbacks(mPendingCheckForLongPress); 11811 } 11812 } 11813 11814 /** 11815 * Remove the pending click action 11816 */ 11817 private void removePerformClickCallback() { 11818 if (mPerformClick != null) { 11819 removeCallbacks(mPerformClick); 11820 } 11821 } 11822 11823 /** 11824 * Remove the prepress detection timer. 11825 */ 11826 private void removeUnsetPressCallback() { 11827 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 11828 setPressed(false); 11829 removeCallbacks(mUnsetPressedState); 11830 } 11831 } 11832 11833 /** 11834 * Remove the tap detection timer. 11835 */ 11836 private void removeTapCallback() { 11837 if (mPendingCheckForTap != null) { 11838 mPrivateFlags &= ~PFLAG_PREPRESSED; 11839 removeCallbacks(mPendingCheckForTap); 11840 } 11841 } 11842 11843 /** 11844 * Cancels a pending long press. Your subclass can use this if you 11845 * want the context menu to come up if the user presses and holds 11846 * at the same place, but you don't want it to come up if they press 11847 * and then move around enough to cause scrolling. 11848 */ 11849 public void cancelLongPress() { 11850 removeLongPressCallback(); 11851 11852 /* 11853 * The prepressed state handled by the tap callback is a display 11854 * construct, but the tap callback will post a long press callback 11855 * less its own timeout. Remove it here. 11856 */ 11857 removeTapCallback(); 11858 } 11859 11860 /** 11861 * Remove the pending callback for sending a 11862 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 11863 */ 11864 private void removeSendViewScrolledAccessibilityEventCallback() { 11865 if (mSendViewScrolledAccessibilityEvent != null) { 11866 removeCallbacks(mSendViewScrolledAccessibilityEvent); 11867 mSendViewScrolledAccessibilityEvent.mIsPending = false; 11868 } 11869 } 11870 11871 /** 11872 * Sets the TouchDelegate for this View. 11873 */ 11874 public void setTouchDelegate(TouchDelegate delegate) { 11875 mTouchDelegate = delegate; 11876 } 11877 11878 /** 11879 * Gets the TouchDelegate for this View. 11880 */ 11881 public TouchDelegate getTouchDelegate() { 11882 return mTouchDelegate; 11883 } 11884 11885 /** 11886 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 11887 * 11888 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 11889 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 11890 * available. This method should only be called for touch events. 11891 * 11892 * <p class="note">This api is not intended for most applications. Buffered dispatch 11893 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 11894 * streams will not improve your input latency. Side effects include: increased latency, 11895 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 11896 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 11897 * you.</p> 11898 */ 11899 public final void requestUnbufferedDispatch(MotionEvent event) { 11900 final int action = event.getAction(); 11901 if (mAttachInfo == null 11902 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 11903 || !event.isTouchEvent()) { 11904 return; 11905 } 11906 mAttachInfo.mUnbufferedDispatchRequested = true; 11907 } 11908 11909 /** 11910 * Set flags controlling behavior of this view. 11911 * 11912 * @param flags Constant indicating the value which should be set 11913 * @param mask Constant indicating the bit range that should be changed 11914 */ 11915 void setFlags(int flags, int mask) { 11916 final boolean accessibilityEnabled = 11917 AccessibilityManager.getInstance(mContext).isEnabled(); 11918 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 11919 11920 int old = mViewFlags; 11921 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 11922 11923 int changed = mViewFlags ^ old; 11924 if (changed == 0) { 11925 return; 11926 } 11927 int privateFlags = mPrivateFlags; 11928 11929 /* Check if the FOCUSABLE bit has changed */ 11930 if (((changed & FOCUSABLE_MASK) != 0) && 11931 ((privateFlags & PFLAG_HAS_BOUNDS) !=0)) { 11932 if (((old & FOCUSABLE_MASK) == FOCUSABLE) 11933 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 11934 /* Give up focus if we are no longer focusable */ 11935 clearFocus(); 11936 } else if (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE) 11937 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 11938 /* 11939 * Tell the view system that we are now available to take focus 11940 * if no one else already has it. 11941 */ 11942 if (mParent != null) mParent.focusableViewAvailable(this); 11943 } 11944 } 11945 11946 final int newVisibility = flags & VISIBILITY_MASK; 11947 if (newVisibility == VISIBLE) { 11948 if ((changed & VISIBILITY_MASK) != 0) { 11949 /* 11950 * If this view is becoming visible, invalidate it in case it changed while 11951 * it was not visible. Marking it drawn ensures that the invalidation will 11952 * go through. 11953 */ 11954 mPrivateFlags |= PFLAG_DRAWN; 11955 invalidate(true); 11956 11957 needGlobalAttributesUpdate(true); 11958 11959 // a view becoming visible is worth notifying the parent 11960 // about in case nothing has focus. even if this specific view 11961 // isn't focusable, it may contain something that is, so let 11962 // the root view try to give this focus if nothing else does. 11963 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 11964 mParent.focusableViewAvailable(this); 11965 } 11966 } 11967 } 11968 11969 /* Check if the GONE bit has changed */ 11970 if ((changed & GONE) != 0) { 11971 needGlobalAttributesUpdate(false); 11972 requestLayout(); 11973 11974 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 11975 if (hasFocus()) clearFocus(); 11976 clearAccessibilityFocus(); 11977 destroyDrawingCache(); 11978 if (mParent instanceof View) { 11979 // GONE views noop invalidation, so invalidate the parent 11980 ((View) mParent).invalidate(true); 11981 } 11982 // Mark the view drawn to ensure that it gets invalidated properly the next 11983 // time it is visible and gets invalidated 11984 mPrivateFlags |= PFLAG_DRAWN; 11985 } 11986 if (mAttachInfo != null) { 11987 mAttachInfo.mViewVisibilityChanged = true; 11988 } 11989 } 11990 11991 /* Check if the VISIBLE bit has changed */ 11992 if ((changed & INVISIBLE) != 0) { 11993 needGlobalAttributesUpdate(false); 11994 /* 11995 * If this view is becoming invisible, set the DRAWN flag so that 11996 * the next invalidate() will not be skipped. 11997 */ 11998 mPrivateFlags |= PFLAG_DRAWN; 11999 12000 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 12001 // root view becoming invisible shouldn't clear focus and accessibility focus 12002 if (getRootView() != this) { 12003 if (hasFocus()) clearFocus(); 12004 clearAccessibilityFocus(); 12005 } 12006 } 12007 if (mAttachInfo != null) { 12008 mAttachInfo.mViewVisibilityChanged = true; 12009 } 12010 } 12011 12012 if ((changed & VISIBILITY_MASK) != 0) { 12013 // If the view is invisible, cleanup its display list to free up resources 12014 if (newVisibility != VISIBLE && mAttachInfo != null) { 12015 cleanupDraw(); 12016 } 12017 12018 if (mParent instanceof ViewGroup) { 12019 ((ViewGroup) mParent).onChildVisibilityChanged(this, 12020 (changed & VISIBILITY_MASK), newVisibility); 12021 ((View) mParent).invalidate(true); 12022 } else if (mParent != null) { 12023 mParent.invalidateChild(this, null); 12024 } 12025 12026 if (mAttachInfo != null) { 12027 dispatchVisibilityChanged(this, newVisibility); 12028 12029 // Aggregated visibility changes are dispatched to attached views 12030 // in visible windows where the parent is currently shown/drawn 12031 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 12032 // discounting clipping or overlapping. This makes it a good place 12033 // to change animation states. 12034 if (mParent != null && getWindowVisibility() == VISIBLE && 12035 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 12036 dispatchVisibilityAggregated(newVisibility == VISIBLE); 12037 } 12038 notifySubtreeAccessibilityStateChangedIfNeeded(); 12039 } 12040 } 12041 12042 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 12043 destroyDrawingCache(); 12044 } 12045 12046 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 12047 destroyDrawingCache(); 12048 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12049 invalidateParentCaches(); 12050 } 12051 12052 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 12053 destroyDrawingCache(); 12054 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12055 } 12056 12057 if ((changed & DRAW_MASK) != 0) { 12058 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 12059 if (mBackground != null 12060 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 12061 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12062 } else { 12063 mPrivateFlags |= PFLAG_SKIP_DRAW; 12064 } 12065 } else { 12066 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12067 } 12068 requestLayout(); 12069 invalidate(true); 12070 } 12071 12072 if ((changed & KEEP_SCREEN_ON) != 0) { 12073 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 12074 mParent.recomputeViewAttributes(this); 12075 } 12076 } 12077 12078 if (accessibilityEnabled) { 12079 if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0 12080 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 12081 || (changed & CONTEXT_CLICKABLE) != 0) { 12082 if (oldIncludeForAccessibility != includeForAccessibility()) { 12083 notifySubtreeAccessibilityStateChangedIfNeeded(); 12084 } else { 12085 notifyViewAccessibilityStateChangedIfNeeded( 12086 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12087 } 12088 } else if ((changed & ENABLED_MASK) != 0) { 12089 notifyViewAccessibilityStateChangedIfNeeded( 12090 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12091 } 12092 } 12093 } 12094 12095 /** 12096 * Change the view's z order in the tree, so it's on top of other sibling 12097 * views. This ordering change may affect layout, if the parent container 12098 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 12099 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 12100 * method should be followed by calls to {@link #requestLayout()} and 12101 * {@link View#invalidate()} on the view's parent to force the parent to redraw 12102 * with the new child ordering. 12103 * 12104 * @see ViewGroup#bringChildToFront(View) 12105 */ 12106 public void bringToFront() { 12107 if (mParent != null) { 12108 mParent.bringChildToFront(this); 12109 } 12110 } 12111 12112 /** 12113 * This is called in response to an internal scroll in this view (i.e., the 12114 * view scrolled its own contents). This is typically as a result of 12115 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 12116 * called. 12117 * 12118 * @param l Current horizontal scroll origin. 12119 * @param t Current vertical scroll origin. 12120 * @param oldl Previous horizontal scroll origin. 12121 * @param oldt Previous vertical scroll origin. 12122 */ 12123 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 12124 notifySubtreeAccessibilityStateChangedIfNeeded(); 12125 12126 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 12127 postSendViewScrolledAccessibilityEventCallback(); 12128 } 12129 12130 mBackgroundSizeChanged = true; 12131 if (mForegroundInfo != null) { 12132 mForegroundInfo.mBoundsChanged = true; 12133 } 12134 12135 final AttachInfo ai = mAttachInfo; 12136 if (ai != null) { 12137 ai.mViewScrollChanged = true; 12138 } 12139 12140 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 12141 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 12142 } 12143 } 12144 12145 /** 12146 * Interface definition for a callback to be invoked when the scroll 12147 * X or Y positions of a view change. 12148 * <p> 12149 * <b>Note:</b> Some views handle scrolling independently from View and may 12150 * have their own separate listeners for scroll-type events. For example, 12151 * {@link android.widget.ListView ListView} allows clients to register an 12152 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 12153 * to listen for changes in list scroll position. 12154 * 12155 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 12156 */ 12157 public interface OnScrollChangeListener { 12158 /** 12159 * Called when the scroll position of a view changes. 12160 * 12161 * @param v The view whose scroll position has changed. 12162 * @param scrollX Current horizontal scroll origin. 12163 * @param scrollY Current vertical scroll origin. 12164 * @param oldScrollX Previous horizontal scroll origin. 12165 * @param oldScrollY Previous vertical scroll origin. 12166 */ 12167 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 12168 } 12169 12170 /** 12171 * Interface definition for a callback to be invoked when the layout bounds of a view 12172 * changes due to layout processing. 12173 */ 12174 public interface OnLayoutChangeListener { 12175 /** 12176 * Called when the layout bounds of a view changes due to layout processing. 12177 * 12178 * @param v The view whose bounds have changed. 12179 * @param left The new value of the view's left property. 12180 * @param top The new value of the view's top property. 12181 * @param right The new value of the view's right property. 12182 * @param bottom The new value of the view's bottom property. 12183 * @param oldLeft The previous value of the view's left property. 12184 * @param oldTop The previous value of the view's top property. 12185 * @param oldRight The previous value of the view's right property. 12186 * @param oldBottom The previous value of the view's bottom property. 12187 */ 12188 void onLayoutChange(View v, int left, int top, int right, int bottom, 12189 int oldLeft, int oldTop, int oldRight, int oldBottom); 12190 } 12191 12192 /** 12193 * This is called during layout when the size of this view has changed. If 12194 * you were just added to the view hierarchy, you're called with the old 12195 * values of 0. 12196 * 12197 * @param w Current width of this view. 12198 * @param h Current height of this view. 12199 * @param oldw Old width of this view. 12200 * @param oldh Old height of this view. 12201 */ 12202 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 12203 } 12204 12205 /** 12206 * Called by draw to draw the child views. This may be overridden 12207 * by derived classes to gain control just before its children are drawn 12208 * (but after its own view has been drawn). 12209 * @param canvas the canvas on which to draw the view 12210 */ 12211 protected void dispatchDraw(Canvas canvas) { 12212 12213 } 12214 12215 /** 12216 * Gets the parent of this view. Note that the parent is a 12217 * ViewParent and not necessarily a View. 12218 * 12219 * @return Parent of this view. 12220 */ 12221 public final ViewParent getParent() { 12222 return mParent; 12223 } 12224 12225 /** 12226 * Set the horizontal scrolled position of your view. This will cause a call to 12227 * {@link #onScrollChanged(int, int, int, int)} and the view will be 12228 * invalidated. 12229 * @param value the x position to scroll to 12230 */ 12231 public void setScrollX(int value) { 12232 scrollTo(value, mScrollY); 12233 } 12234 12235 /** 12236 * Set the vertical scrolled position of your view. This will cause a call to 12237 * {@link #onScrollChanged(int, int, int, int)} and the view will be 12238 * invalidated. 12239 * @param value the y position to scroll to 12240 */ 12241 public void setScrollY(int value) { 12242 scrollTo(mScrollX, value); 12243 } 12244 12245 /** 12246 * Return the scrolled left position of this view. This is the left edge of 12247 * the displayed part of your view. You do not need to draw any pixels 12248 * farther left, since those are outside of the frame of your view on 12249 * screen. 12250 * 12251 * @return The left edge of the displayed part of your view, in pixels. 12252 */ 12253 public final int getScrollX() { 12254 return mScrollX; 12255 } 12256 12257 /** 12258 * Return the scrolled top position of this view. This is the top edge of 12259 * the displayed part of your view. You do not need to draw any pixels above 12260 * it, since those are outside of the frame of your view on screen. 12261 * 12262 * @return The top edge of the displayed part of your view, in pixels. 12263 */ 12264 public final int getScrollY() { 12265 return mScrollY; 12266 } 12267 12268 /** 12269 * Return the width of the your view. 12270 * 12271 * @return The width of your view, in pixels. 12272 */ 12273 @ViewDebug.ExportedProperty(category = "layout") 12274 public final int getWidth() { 12275 return mRight - mLeft; 12276 } 12277 12278 /** 12279 * Return the height of your view. 12280 * 12281 * @return The height of your view, in pixels. 12282 */ 12283 @ViewDebug.ExportedProperty(category = "layout") 12284 public final int getHeight() { 12285 return mBottom - mTop; 12286 } 12287 12288 /** 12289 * Return the visible drawing bounds of your view. Fills in the output 12290 * rectangle with the values from getScrollX(), getScrollY(), 12291 * getWidth(), and getHeight(). These bounds do not account for any 12292 * transformation properties currently set on the view, such as 12293 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 12294 * 12295 * @param outRect The (scrolled) drawing bounds of the view. 12296 */ 12297 public void getDrawingRect(Rect outRect) { 12298 outRect.left = mScrollX; 12299 outRect.top = mScrollY; 12300 outRect.right = mScrollX + (mRight - mLeft); 12301 outRect.bottom = mScrollY + (mBottom - mTop); 12302 } 12303 12304 /** 12305 * Like {@link #getMeasuredWidthAndState()}, but only returns the 12306 * raw width component (that is the result is masked by 12307 * {@link #MEASURED_SIZE_MASK}). 12308 * 12309 * @return The raw measured width of this view. 12310 */ 12311 public final int getMeasuredWidth() { 12312 return mMeasuredWidth & MEASURED_SIZE_MASK; 12313 } 12314 12315 /** 12316 * Return the full width measurement information for this view as computed 12317 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 12318 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 12319 * This should be used during measurement and layout calculations only. Use 12320 * {@link #getWidth()} to see how wide a view is after layout. 12321 * 12322 * @return The measured width of this view as a bit mask. 12323 */ 12324 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 12325 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 12326 name = "MEASURED_STATE_TOO_SMALL"), 12327 }) 12328 public final int getMeasuredWidthAndState() { 12329 return mMeasuredWidth; 12330 } 12331 12332 /** 12333 * Like {@link #getMeasuredHeightAndState()}, but only returns the 12334 * raw height component (that is the result is masked by 12335 * {@link #MEASURED_SIZE_MASK}). 12336 * 12337 * @return The raw measured height of this view. 12338 */ 12339 public final int getMeasuredHeight() { 12340 return mMeasuredHeight & MEASURED_SIZE_MASK; 12341 } 12342 12343 /** 12344 * Return the full height measurement information for this view as computed 12345 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 12346 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 12347 * This should be used during measurement and layout calculations only. Use 12348 * {@link #getHeight()} to see how wide a view is after layout. 12349 * 12350 * @return The measured height of this view as a bit mask. 12351 */ 12352 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 12353 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 12354 name = "MEASURED_STATE_TOO_SMALL"), 12355 }) 12356 public final int getMeasuredHeightAndState() { 12357 return mMeasuredHeight; 12358 } 12359 12360 /** 12361 * Return only the state bits of {@link #getMeasuredWidthAndState()} 12362 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 12363 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 12364 * and the height component is at the shifted bits 12365 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 12366 */ 12367 public final int getMeasuredState() { 12368 return (mMeasuredWidth&MEASURED_STATE_MASK) 12369 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 12370 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 12371 } 12372 12373 /** 12374 * The transform matrix of this view, which is calculated based on the current 12375 * rotation, scale, and pivot properties. 12376 * 12377 * @see #getRotation() 12378 * @see #getScaleX() 12379 * @see #getScaleY() 12380 * @see #getPivotX() 12381 * @see #getPivotY() 12382 * @return The current transform matrix for the view 12383 */ 12384 public Matrix getMatrix() { 12385 ensureTransformationInfo(); 12386 final Matrix matrix = mTransformationInfo.mMatrix; 12387 mRenderNode.getMatrix(matrix); 12388 return matrix; 12389 } 12390 12391 /** 12392 * Returns true if the transform matrix is the identity matrix. 12393 * Recomputes the matrix if necessary. 12394 * 12395 * @return True if the transform matrix is the identity matrix, false otherwise. 12396 */ 12397 final boolean hasIdentityMatrix() { 12398 return mRenderNode.hasIdentityMatrix(); 12399 } 12400 12401 void ensureTransformationInfo() { 12402 if (mTransformationInfo == null) { 12403 mTransformationInfo = new TransformationInfo(); 12404 } 12405 } 12406 12407 /** 12408 * Utility method to retrieve the inverse of the current mMatrix property. 12409 * We cache the matrix to avoid recalculating it when transform properties 12410 * have not changed. 12411 * 12412 * @return The inverse of the current matrix of this view. 12413 * @hide 12414 */ 12415 public final Matrix getInverseMatrix() { 12416 ensureTransformationInfo(); 12417 if (mTransformationInfo.mInverseMatrix == null) { 12418 mTransformationInfo.mInverseMatrix = new Matrix(); 12419 } 12420 final Matrix matrix = mTransformationInfo.mInverseMatrix; 12421 mRenderNode.getInverseMatrix(matrix); 12422 return matrix; 12423 } 12424 12425 /** 12426 * Gets the distance along the Z axis from the camera to this view. 12427 * 12428 * @see #setCameraDistance(float) 12429 * 12430 * @return The distance along the Z axis. 12431 */ 12432 public float getCameraDistance() { 12433 final float dpi = mResources.getDisplayMetrics().densityDpi; 12434 return -(mRenderNode.getCameraDistance() * dpi); 12435 } 12436 12437 /** 12438 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 12439 * views are drawn) from the camera to this view. The camera's distance 12440 * affects 3D transformations, for instance rotations around the X and Y 12441 * axis. If the rotationX or rotationY properties are changed and this view is 12442 * large (more than half the size of the screen), it is recommended to always 12443 * use a camera distance that's greater than the height (X axis rotation) or 12444 * the width (Y axis rotation) of this view.</p> 12445 * 12446 * <p>The distance of the camera from the view plane can have an affect on the 12447 * perspective distortion of the view when it is rotated around the x or y axis. 12448 * For example, a large distance will result in a large viewing angle, and there 12449 * will not be much perspective distortion of the view as it rotates. A short 12450 * distance may cause much more perspective distortion upon rotation, and can 12451 * also result in some drawing artifacts if the rotated view ends up partially 12452 * behind the camera (which is why the recommendation is to use a distance at 12453 * least as far as the size of the view, if the view is to be rotated.)</p> 12454 * 12455 * <p>The distance is expressed in "depth pixels." The default distance depends 12456 * on the screen density. For instance, on a medium density display, the 12457 * default distance is 1280. On a high density display, the default distance 12458 * is 1920.</p> 12459 * 12460 * <p>If you want to specify a distance that leads to visually consistent 12461 * results across various densities, use the following formula:</p> 12462 * <pre> 12463 * float scale = context.getResources().getDisplayMetrics().density; 12464 * view.setCameraDistance(distance * scale); 12465 * </pre> 12466 * 12467 * <p>The density scale factor of a high density display is 1.5, 12468 * and 1920 = 1280 * 1.5.</p> 12469 * 12470 * @param distance The distance in "depth pixels", if negative the opposite 12471 * value is used 12472 * 12473 * @see #setRotationX(float) 12474 * @see #setRotationY(float) 12475 */ 12476 public void setCameraDistance(float distance) { 12477 final float dpi = mResources.getDisplayMetrics().densityDpi; 12478 12479 invalidateViewProperty(true, false); 12480 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 12481 invalidateViewProperty(false, false); 12482 12483 invalidateParentIfNeededAndWasQuickRejected(); 12484 } 12485 12486 /** 12487 * The degrees that the view is rotated around the pivot point. 12488 * 12489 * @see #setRotation(float) 12490 * @see #getPivotX() 12491 * @see #getPivotY() 12492 * 12493 * @return The degrees of rotation. 12494 */ 12495 @ViewDebug.ExportedProperty(category = "drawing") 12496 public float getRotation() { 12497 return mRenderNode.getRotation(); 12498 } 12499 12500 /** 12501 * Sets the degrees that the view is rotated around the pivot point. Increasing values 12502 * result in clockwise rotation. 12503 * 12504 * @param rotation The degrees of rotation. 12505 * 12506 * @see #getRotation() 12507 * @see #getPivotX() 12508 * @see #getPivotY() 12509 * @see #setRotationX(float) 12510 * @see #setRotationY(float) 12511 * 12512 * @attr ref android.R.styleable#View_rotation 12513 */ 12514 public void setRotation(float rotation) { 12515 if (rotation != getRotation()) { 12516 // Double-invalidation is necessary to capture view's old and new areas 12517 invalidateViewProperty(true, false); 12518 mRenderNode.setRotation(rotation); 12519 invalidateViewProperty(false, true); 12520 12521 invalidateParentIfNeededAndWasQuickRejected(); 12522 notifySubtreeAccessibilityStateChangedIfNeeded(); 12523 } 12524 } 12525 12526 /** 12527 * The degrees that the view is rotated around the vertical axis through the pivot point. 12528 * 12529 * @see #getPivotX() 12530 * @see #getPivotY() 12531 * @see #setRotationY(float) 12532 * 12533 * @return The degrees of Y rotation. 12534 */ 12535 @ViewDebug.ExportedProperty(category = "drawing") 12536 public float getRotationY() { 12537 return mRenderNode.getRotationY(); 12538 } 12539 12540 /** 12541 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 12542 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 12543 * down the y axis. 12544 * 12545 * When rotating large views, it is recommended to adjust the camera distance 12546 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12547 * 12548 * @param rotationY The degrees of Y rotation. 12549 * 12550 * @see #getRotationY() 12551 * @see #getPivotX() 12552 * @see #getPivotY() 12553 * @see #setRotation(float) 12554 * @see #setRotationX(float) 12555 * @see #setCameraDistance(float) 12556 * 12557 * @attr ref android.R.styleable#View_rotationY 12558 */ 12559 public void setRotationY(float rotationY) { 12560 if (rotationY != getRotationY()) { 12561 invalidateViewProperty(true, false); 12562 mRenderNode.setRotationY(rotationY); 12563 invalidateViewProperty(false, true); 12564 12565 invalidateParentIfNeededAndWasQuickRejected(); 12566 notifySubtreeAccessibilityStateChangedIfNeeded(); 12567 } 12568 } 12569 12570 /** 12571 * The degrees that the view is rotated around the horizontal axis through the pivot point. 12572 * 12573 * @see #getPivotX() 12574 * @see #getPivotY() 12575 * @see #setRotationX(float) 12576 * 12577 * @return The degrees of X rotation. 12578 */ 12579 @ViewDebug.ExportedProperty(category = "drawing") 12580 public float getRotationX() { 12581 return mRenderNode.getRotationX(); 12582 } 12583 12584 /** 12585 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 12586 * Increasing values result in clockwise rotation from the viewpoint of looking down the 12587 * x axis. 12588 * 12589 * When rotating large views, it is recommended to adjust the camera distance 12590 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12591 * 12592 * @param rotationX The degrees of X rotation. 12593 * 12594 * @see #getRotationX() 12595 * @see #getPivotX() 12596 * @see #getPivotY() 12597 * @see #setRotation(float) 12598 * @see #setRotationY(float) 12599 * @see #setCameraDistance(float) 12600 * 12601 * @attr ref android.R.styleable#View_rotationX 12602 */ 12603 public void setRotationX(float rotationX) { 12604 if (rotationX != getRotationX()) { 12605 invalidateViewProperty(true, false); 12606 mRenderNode.setRotationX(rotationX); 12607 invalidateViewProperty(false, true); 12608 12609 invalidateParentIfNeededAndWasQuickRejected(); 12610 notifySubtreeAccessibilityStateChangedIfNeeded(); 12611 } 12612 } 12613 12614 /** 12615 * The amount that the view is scaled in x around the pivot point, as a proportion of 12616 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 12617 * 12618 * <p>By default, this is 1.0f. 12619 * 12620 * @see #getPivotX() 12621 * @see #getPivotY() 12622 * @return The scaling factor. 12623 */ 12624 @ViewDebug.ExportedProperty(category = "drawing") 12625 public float getScaleX() { 12626 return mRenderNode.getScaleX(); 12627 } 12628 12629 /** 12630 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 12631 * the view's unscaled width. A value of 1 means that no scaling is applied. 12632 * 12633 * @param scaleX The scaling factor. 12634 * @see #getPivotX() 12635 * @see #getPivotY() 12636 * 12637 * @attr ref android.R.styleable#View_scaleX 12638 */ 12639 public void setScaleX(float scaleX) { 12640 if (scaleX != getScaleX()) { 12641 invalidateViewProperty(true, false); 12642 mRenderNode.setScaleX(scaleX); 12643 invalidateViewProperty(false, true); 12644 12645 invalidateParentIfNeededAndWasQuickRejected(); 12646 notifySubtreeAccessibilityStateChangedIfNeeded(); 12647 } 12648 } 12649 12650 /** 12651 * The amount that the view is scaled in y around the pivot point, as a proportion of 12652 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 12653 * 12654 * <p>By default, this is 1.0f. 12655 * 12656 * @see #getPivotX() 12657 * @see #getPivotY() 12658 * @return The scaling factor. 12659 */ 12660 @ViewDebug.ExportedProperty(category = "drawing") 12661 public float getScaleY() { 12662 return mRenderNode.getScaleY(); 12663 } 12664 12665 /** 12666 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 12667 * the view's unscaled width. A value of 1 means that no scaling is applied. 12668 * 12669 * @param scaleY The scaling factor. 12670 * @see #getPivotX() 12671 * @see #getPivotY() 12672 * 12673 * @attr ref android.R.styleable#View_scaleY 12674 */ 12675 public void setScaleY(float scaleY) { 12676 if (scaleY != getScaleY()) { 12677 invalidateViewProperty(true, false); 12678 mRenderNode.setScaleY(scaleY); 12679 invalidateViewProperty(false, true); 12680 12681 invalidateParentIfNeededAndWasQuickRejected(); 12682 notifySubtreeAccessibilityStateChangedIfNeeded(); 12683 } 12684 } 12685 12686 /** 12687 * The x location of the point around which the view is {@link #setRotation(float) rotated} 12688 * and {@link #setScaleX(float) scaled}. 12689 * 12690 * @see #getRotation() 12691 * @see #getScaleX() 12692 * @see #getScaleY() 12693 * @see #getPivotY() 12694 * @return The x location of the pivot point. 12695 * 12696 * @attr ref android.R.styleable#View_transformPivotX 12697 */ 12698 @ViewDebug.ExportedProperty(category = "drawing") 12699 public float getPivotX() { 12700 return mRenderNode.getPivotX(); 12701 } 12702 12703 /** 12704 * Sets the x location of the point around which the view is 12705 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 12706 * By default, the pivot point is centered on the object. 12707 * Setting this property disables this behavior and causes the view to use only the 12708 * explicitly set pivotX and pivotY values. 12709 * 12710 * @param pivotX The x location of the pivot point. 12711 * @see #getRotation() 12712 * @see #getScaleX() 12713 * @see #getScaleY() 12714 * @see #getPivotY() 12715 * 12716 * @attr ref android.R.styleable#View_transformPivotX 12717 */ 12718 public void setPivotX(float pivotX) { 12719 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 12720 invalidateViewProperty(true, false); 12721 mRenderNode.setPivotX(pivotX); 12722 invalidateViewProperty(false, true); 12723 12724 invalidateParentIfNeededAndWasQuickRejected(); 12725 } 12726 } 12727 12728 /** 12729 * The y location of the point around which the view is {@link #setRotation(float) rotated} 12730 * and {@link #setScaleY(float) scaled}. 12731 * 12732 * @see #getRotation() 12733 * @see #getScaleX() 12734 * @see #getScaleY() 12735 * @see #getPivotY() 12736 * @return The y location of the pivot point. 12737 * 12738 * @attr ref android.R.styleable#View_transformPivotY 12739 */ 12740 @ViewDebug.ExportedProperty(category = "drawing") 12741 public float getPivotY() { 12742 return mRenderNode.getPivotY(); 12743 } 12744 12745 /** 12746 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 12747 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 12748 * Setting this property disables this behavior and causes the view to use only the 12749 * explicitly set pivotX and pivotY values. 12750 * 12751 * @param pivotY The y location of the pivot point. 12752 * @see #getRotation() 12753 * @see #getScaleX() 12754 * @see #getScaleY() 12755 * @see #getPivotY() 12756 * 12757 * @attr ref android.R.styleable#View_transformPivotY 12758 */ 12759 public void setPivotY(float pivotY) { 12760 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 12761 invalidateViewProperty(true, false); 12762 mRenderNode.setPivotY(pivotY); 12763 invalidateViewProperty(false, true); 12764 12765 invalidateParentIfNeededAndWasQuickRejected(); 12766 } 12767 } 12768 12769 /** 12770 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 12771 * completely transparent and 1 means the view is completely opaque. 12772 * 12773 * <p>By default this is 1.0f. 12774 * @return The opacity of the view. 12775 */ 12776 @ViewDebug.ExportedProperty(category = "drawing") 12777 public float getAlpha() { 12778 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 12779 } 12780 12781 /** 12782 * Sets the behavior for overlapping rendering for this view (see {@link 12783 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 12784 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 12785 * providing the value which is then used internally. That is, when {@link 12786 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 12787 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 12788 * instead. 12789 * 12790 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 12791 * instead of that returned by {@link #hasOverlappingRendering()}. 12792 * 12793 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 12794 */ 12795 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 12796 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 12797 if (hasOverlappingRendering) { 12798 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 12799 } else { 12800 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 12801 } 12802 } 12803 12804 /** 12805 * Returns the value for overlapping rendering that is used internally. This is either 12806 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 12807 * the return value of {@link #hasOverlappingRendering()}, otherwise. 12808 * 12809 * @return The value for overlapping rendering being used internally. 12810 */ 12811 public final boolean getHasOverlappingRendering() { 12812 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 12813 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 12814 hasOverlappingRendering(); 12815 } 12816 12817 /** 12818 * Returns whether this View has content which overlaps. 12819 * 12820 * <p>This function, intended to be overridden by specific View types, is an optimization when 12821 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 12822 * an offscreen buffer and then composited into place, which can be expensive. If the view has 12823 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 12824 * directly. An example of overlapping rendering is a TextView with a background image, such as 12825 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 12826 * ImageView with only the foreground image. The default implementation returns true; subclasses 12827 * should override if they have cases which can be optimized.</p> 12828 * 12829 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 12830 * necessitates that a View return true if it uses the methods internally without passing the 12831 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 12832 * 12833 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 12834 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 12835 * 12836 * @return true if the content in this view might overlap, false otherwise. 12837 */ 12838 @ViewDebug.ExportedProperty(category = "drawing") 12839 public boolean hasOverlappingRendering() { 12840 return true; 12841 } 12842 12843 /** 12844 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 12845 * completely transparent and 1 means the view is completely opaque. 12846 * 12847 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 12848 * can have significant performance implications, especially for large views. It is best to use 12849 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 12850 * 12851 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 12852 * strongly recommended for performance reasons to either override 12853 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 12854 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 12855 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 12856 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 12857 * of rendering cost, even for simple or small views. Starting with 12858 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 12859 * applied to the view at the rendering level.</p> 12860 * 12861 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 12862 * responsible for applying the opacity itself.</p> 12863 * 12864 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 12865 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 12866 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 12867 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 12868 * 12869 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 12870 * value will clip a View to its bounds, unless the View returns <code>false</code> from 12871 * {@link #hasOverlappingRendering}.</p> 12872 * 12873 * @param alpha The opacity of the view. 12874 * 12875 * @see #hasOverlappingRendering() 12876 * @see #setLayerType(int, android.graphics.Paint) 12877 * 12878 * @attr ref android.R.styleable#View_alpha 12879 */ 12880 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 12881 ensureTransformationInfo(); 12882 if (mTransformationInfo.mAlpha != alpha) { 12883 // Report visibility changes, which can affect children, to accessibility 12884 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 12885 notifySubtreeAccessibilityStateChangedIfNeeded(); 12886 } 12887 mTransformationInfo.mAlpha = alpha; 12888 if (onSetAlpha((int) (alpha * 255))) { 12889 mPrivateFlags |= PFLAG_ALPHA_SET; 12890 // subclass is handling alpha - don't optimize rendering cache invalidation 12891 invalidateParentCaches(); 12892 invalidate(true); 12893 } else { 12894 mPrivateFlags &= ~PFLAG_ALPHA_SET; 12895 invalidateViewProperty(true, false); 12896 mRenderNode.setAlpha(getFinalAlpha()); 12897 } 12898 } 12899 } 12900 12901 /** 12902 * Faster version of setAlpha() which performs the same steps except there are 12903 * no calls to invalidate(). The caller of this function should perform proper invalidation 12904 * on the parent and this object. The return value indicates whether the subclass handles 12905 * alpha (the return value for onSetAlpha()). 12906 * 12907 * @param alpha The new value for the alpha property 12908 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 12909 * the new value for the alpha property is different from the old value 12910 */ 12911 boolean setAlphaNoInvalidation(float alpha) { 12912 ensureTransformationInfo(); 12913 if (mTransformationInfo.mAlpha != alpha) { 12914 mTransformationInfo.mAlpha = alpha; 12915 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 12916 if (subclassHandlesAlpha) { 12917 mPrivateFlags |= PFLAG_ALPHA_SET; 12918 return true; 12919 } else { 12920 mPrivateFlags &= ~PFLAG_ALPHA_SET; 12921 mRenderNode.setAlpha(getFinalAlpha()); 12922 } 12923 } 12924 return false; 12925 } 12926 12927 /** 12928 * This property is hidden and intended only for use by the Fade transition, which 12929 * animates it to produce a visual translucency that does not side-effect (or get 12930 * affected by) the real alpha property. This value is composited with the other 12931 * alpha value (and the AlphaAnimation value, when that is present) to produce 12932 * a final visual translucency result, which is what is passed into the DisplayList. 12933 * 12934 * @hide 12935 */ 12936 public void setTransitionAlpha(float alpha) { 12937 ensureTransformationInfo(); 12938 if (mTransformationInfo.mTransitionAlpha != alpha) { 12939 mTransformationInfo.mTransitionAlpha = alpha; 12940 mPrivateFlags &= ~PFLAG_ALPHA_SET; 12941 invalidateViewProperty(true, false); 12942 mRenderNode.setAlpha(getFinalAlpha()); 12943 } 12944 } 12945 12946 /** 12947 * Calculates the visual alpha of this view, which is a combination of the actual 12948 * alpha value and the transitionAlpha value (if set). 12949 */ 12950 private float getFinalAlpha() { 12951 if (mTransformationInfo != null) { 12952 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 12953 } 12954 return 1; 12955 } 12956 12957 /** 12958 * This property is hidden and intended only for use by the Fade transition, which 12959 * animates it to produce a visual translucency that does not side-effect (or get 12960 * affected by) the real alpha property. This value is composited with the other 12961 * alpha value (and the AlphaAnimation value, when that is present) to produce 12962 * a final visual translucency result, which is what is passed into the DisplayList. 12963 * 12964 * @hide 12965 */ 12966 @ViewDebug.ExportedProperty(category = "drawing") 12967 public float getTransitionAlpha() { 12968 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 12969 } 12970 12971 /** 12972 * Top position of this view relative to its parent. 12973 * 12974 * @return The top of this view, in pixels. 12975 */ 12976 @ViewDebug.CapturedViewProperty 12977 public final int getTop() { 12978 return mTop; 12979 } 12980 12981 /** 12982 * Sets the top position of this view relative to its parent. This method is meant to be called 12983 * by the layout system and should not generally be called otherwise, because the property 12984 * may be changed at any time by the layout. 12985 * 12986 * @param top The top of this view, in pixels. 12987 */ 12988 public final void setTop(int top) { 12989 if (top != mTop) { 12990 final boolean matrixIsIdentity = hasIdentityMatrix(); 12991 if (matrixIsIdentity) { 12992 if (mAttachInfo != null) { 12993 int minTop; 12994 int yLoc; 12995 if (top < mTop) { 12996 minTop = top; 12997 yLoc = top - mTop; 12998 } else { 12999 minTop = mTop; 13000 yLoc = 0; 13001 } 13002 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 13003 } 13004 } else { 13005 // Double-invalidation is necessary to capture view's old and new areas 13006 invalidate(true); 13007 } 13008 13009 int width = mRight - mLeft; 13010 int oldHeight = mBottom - mTop; 13011 13012 mTop = top; 13013 mRenderNode.setTop(mTop); 13014 13015 sizeChange(width, mBottom - mTop, width, oldHeight); 13016 13017 if (!matrixIsIdentity) { 13018 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13019 invalidate(true); 13020 } 13021 mBackgroundSizeChanged = true; 13022 if (mForegroundInfo != null) { 13023 mForegroundInfo.mBoundsChanged = true; 13024 } 13025 invalidateParentIfNeeded(); 13026 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13027 // View was rejected last time it was drawn by its parent; this may have changed 13028 invalidateParentIfNeeded(); 13029 } 13030 } 13031 } 13032 13033 /** 13034 * Bottom position of this view relative to its parent. 13035 * 13036 * @return The bottom of this view, in pixels. 13037 */ 13038 @ViewDebug.CapturedViewProperty 13039 public final int getBottom() { 13040 return mBottom; 13041 } 13042 13043 /** 13044 * True if this view has changed since the last time being drawn. 13045 * 13046 * @return The dirty state of this view. 13047 */ 13048 public boolean isDirty() { 13049 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 13050 } 13051 13052 /** 13053 * Sets the bottom position of this view relative to its parent. This method is meant to be 13054 * called by the layout system and should not generally be called otherwise, because the 13055 * property may be changed at any time by the layout. 13056 * 13057 * @param bottom The bottom of this view, in pixels. 13058 */ 13059 public final void setBottom(int bottom) { 13060 if (bottom != mBottom) { 13061 final boolean matrixIsIdentity = hasIdentityMatrix(); 13062 if (matrixIsIdentity) { 13063 if (mAttachInfo != null) { 13064 int maxBottom; 13065 if (bottom < mBottom) { 13066 maxBottom = mBottom; 13067 } else { 13068 maxBottom = bottom; 13069 } 13070 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 13071 } 13072 } else { 13073 // Double-invalidation is necessary to capture view's old and new areas 13074 invalidate(true); 13075 } 13076 13077 int width = mRight - mLeft; 13078 int oldHeight = mBottom - mTop; 13079 13080 mBottom = bottom; 13081 mRenderNode.setBottom(mBottom); 13082 13083 sizeChange(width, mBottom - mTop, width, oldHeight); 13084 13085 if (!matrixIsIdentity) { 13086 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13087 invalidate(true); 13088 } 13089 mBackgroundSizeChanged = true; 13090 if (mForegroundInfo != null) { 13091 mForegroundInfo.mBoundsChanged = true; 13092 } 13093 invalidateParentIfNeeded(); 13094 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13095 // View was rejected last time it was drawn by its parent; this may have changed 13096 invalidateParentIfNeeded(); 13097 } 13098 } 13099 } 13100 13101 /** 13102 * Left position of this view relative to its parent. 13103 * 13104 * @return The left edge of this view, in pixels. 13105 */ 13106 @ViewDebug.CapturedViewProperty 13107 public final int getLeft() { 13108 return mLeft; 13109 } 13110 13111 /** 13112 * Sets the left position of this view relative to its parent. This method is meant to be called 13113 * by the layout system and should not generally be called otherwise, because the property 13114 * may be changed at any time by the layout. 13115 * 13116 * @param left The left of this view, in pixels. 13117 */ 13118 public final void setLeft(int left) { 13119 if (left != mLeft) { 13120 final boolean matrixIsIdentity = hasIdentityMatrix(); 13121 if (matrixIsIdentity) { 13122 if (mAttachInfo != null) { 13123 int minLeft; 13124 int xLoc; 13125 if (left < mLeft) { 13126 minLeft = left; 13127 xLoc = left - mLeft; 13128 } else { 13129 minLeft = mLeft; 13130 xLoc = 0; 13131 } 13132 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 13133 } 13134 } else { 13135 // Double-invalidation is necessary to capture view's old and new areas 13136 invalidate(true); 13137 } 13138 13139 int oldWidth = mRight - mLeft; 13140 int height = mBottom - mTop; 13141 13142 mLeft = left; 13143 mRenderNode.setLeft(left); 13144 13145 sizeChange(mRight - mLeft, height, oldWidth, height); 13146 13147 if (!matrixIsIdentity) { 13148 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13149 invalidate(true); 13150 } 13151 mBackgroundSizeChanged = true; 13152 if (mForegroundInfo != null) { 13153 mForegroundInfo.mBoundsChanged = true; 13154 } 13155 invalidateParentIfNeeded(); 13156 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13157 // View was rejected last time it was drawn by its parent; this may have changed 13158 invalidateParentIfNeeded(); 13159 } 13160 } 13161 } 13162 13163 /** 13164 * Right position of this view relative to its parent. 13165 * 13166 * @return The right edge of this view, in pixels. 13167 */ 13168 @ViewDebug.CapturedViewProperty 13169 public final int getRight() { 13170 return mRight; 13171 } 13172 13173 /** 13174 * Sets the right position of this view relative to its parent. This method is meant to be called 13175 * by the layout system and should not generally be called otherwise, because the property 13176 * may be changed at any time by the layout. 13177 * 13178 * @param right The right of this view, in pixels. 13179 */ 13180 public final void setRight(int right) { 13181 if (right != mRight) { 13182 final boolean matrixIsIdentity = hasIdentityMatrix(); 13183 if (matrixIsIdentity) { 13184 if (mAttachInfo != null) { 13185 int maxRight; 13186 if (right < mRight) { 13187 maxRight = mRight; 13188 } else { 13189 maxRight = right; 13190 } 13191 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 13192 } 13193 } else { 13194 // Double-invalidation is necessary to capture view's old and new areas 13195 invalidate(true); 13196 } 13197 13198 int oldWidth = mRight - mLeft; 13199 int height = mBottom - mTop; 13200 13201 mRight = right; 13202 mRenderNode.setRight(mRight); 13203 13204 sizeChange(mRight - mLeft, height, oldWidth, height); 13205 13206 if (!matrixIsIdentity) { 13207 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13208 invalidate(true); 13209 } 13210 mBackgroundSizeChanged = true; 13211 if (mForegroundInfo != null) { 13212 mForegroundInfo.mBoundsChanged = true; 13213 } 13214 invalidateParentIfNeeded(); 13215 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13216 // View was rejected last time it was drawn by its parent; this may have changed 13217 invalidateParentIfNeeded(); 13218 } 13219 } 13220 } 13221 13222 /** 13223 * The visual x position of this view, in pixels. This is equivalent to the 13224 * {@link #setTranslationX(float) translationX} property plus the current 13225 * {@link #getLeft() left} property. 13226 * 13227 * @return The visual x position of this view, in pixels. 13228 */ 13229 @ViewDebug.ExportedProperty(category = "drawing") 13230 public float getX() { 13231 return mLeft + getTranslationX(); 13232 } 13233 13234 /** 13235 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 13236 * {@link #setTranslationX(float) translationX} property to be the difference between 13237 * the x value passed in and the current {@link #getLeft() left} property. 13238 * 13239 * @param x The visual x position of this view, in pixels. 13240 */ 13241 public void setX(float x) { 13242 setTranslationX(x - mLeft); 13243 } 13244 13245 /** 13246 * The visual y position of this view, in pixels. This is equivalent to the 13247 * {@link #setTranslationY(float) translationY} property plus the current 13248 * {@link #getTop() top} property. 13249 * 13250 * @return The visual y position of this view, in pixels. 13251 */ 13252 @ViewDebug.ExportedProperty(category = "drawing") 13253 public float getY() { 13254 return mTop + getTranslationY(); 13255 } 13256 13257 /** 13258 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 13259 * {@link #setTranslationY(float) translationY} property to be the difference between 13260 * the y value passed in and the current {@link #getTop() top} property. 13261 * 13262 * @param y The visual y position of this view, in pixels. 13263 */ 13264 public void setY(float y) { 13265 setTranslationY(y - mTop); 13266 } 13267 13268 /** 13269 * The visual z position of this view, in pixels. This is equivalent to the 13270 * {@link #setTranslationZ(float) translationZ} property plus the current 13271 * {@link #getElevation() elevation} property. 13272 * 13273 * @return The visual z position of this view, in pixels. 13274 */ 13275 @ViewDebug.ExportedProperty(category = "drawing") 13276 public float getZ() { 13277 return getElevation() + getTranslationZ(); 13278 } 13279 13280 /** 13281 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 13282 * {@link #setTranslationZ(float) translationZ} property to be the difference between 13283 * the x value passed in and the current {@link #getElevation() elevation} property. 13284 * 13285 * @param z The visual z position of this view, in pixels. 13286 */ 13287 public void setZ(float z) { 13288 setTranslationZ(z - getElevation()); 13289 } 13290 13291 /** 13292 * The base elevation of this view relative to its parent, in pixels. 13293 * 13294 * @return The base depth position of the view, in pixels. 13295 */ 13296 @ViewDebug.ExportedProperty(category = "drawing") 13297 public float getElevation() { 13298 return mRenderNode.getElevation(); 13299 } 13300 13301 /** 13302 * Sets the base elevation of this view, in pixels. 13303 * 13304 * @attr ref android.R.styleable#View_elevation 13305 */ 13306 public void setElevation(float elevation) { 13307 if (elevation != getElevation()) { 13308 invalidateViewProperty(true, false); 13309 mRenderNode.setElevation(elevation); 13310 invalidateViewProperty(false, true); 13311 13312 invalidateParentIfNeededAndWasQuickRejected(); 13313 } 13314 } 13315 13316 /** 13317 * The horizontal location of this view relative to its {@link #getLeft() left} position. 13318 * This position is post-layout, in addition to wherever the object's 13319 * layout placed it. 13320 * 13321 * @return The horizontal position of this view relative to its left position, in pixels. 13322 */ 13323 @ViewDebug.ExportedProperty(category = "drawing") 13324 public float getTranslationX() { 13325 return mRenderNode.getTranslationX(); 13326 } 13327 13328 /** 13329 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 13330 * This effectively positions the object post-layout, in addition to wherever the object's 13331 * layout placed it. 13332 * 13333 * @param translationX The horizontal position of this view relative to its left position, 13334 * in pixels. 13335 * 13336 * @attr ref android.R.styleable#View_translationX 13337 */ 13338 public void setTranslationX(float translationX) { 13339 if (translationX != getTranslationX()) { 13340 invalidateViewProperty(true, false); 13341 mRenderNode.setTranslationX(translationX); 13342 invalidateViewProperty(false, true); 13343 13344 invalidateParentIfNeededAndWasQuickRejected(); 13345 notifySubtreeAccessibilityStateChangedIfNeeded(); 13346 } 13347 } 13348 13349 /** 13350 * The vertical location of this view relative to its {@link #getTop() top} position. 13351 * This position is post-layout, in addition to wherever the object's 13352 * layout placed it. 13353 * 13354 * @return The vertical position of this view relative to its top position, 13355 * in pixels. 13356 */ 13357 @ViewDebug.ExportedProperty(category = "drawing") 13358 public float getTranslationY() { 13359 return mRenderNode.getTranslationY(); 13360 } 13361 13362 /** 13363 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 13364 * This effectively positions the object post-layout, in addition to wherever the object's 13365 * layout placed it. 13366 * 13367 * @param translationY The vertical position of this view relative to its top position, 13368 * in pixels. 13369 * 13370 * @attr ref android.R.styleable#View_translationY 13371 */ 13372 public void setTranslationY(float translationY) { 13373 if (translationY != getTranslationY()) { 13374 invalidateViewProperty(true, false); 13375 mRenderNode.setTranslationY(translationY); 13376 invalidateViewProperty(false, true); 13377 13378 invalidateParentIfNeededAndWasQuickRejected(); 13379 notifySubtreeAccessibilityStateChangedIfNeeded(); 13380 } 13381 } 13382 13383 /** 13384 * The depth location of this view relative to its {@link #getElevation() elevation}. 13385 * 13386 * @return The depth of this view relative to its elevation. 13387 */ 13388 @ViewDebug.ExportedProperty(category = "drawing") 13389 public float getTranslationZ() { 13390 return mRenderNode.getTranslationZ(); 13391 } 13392 13393 /** 13394 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 13395 * 13396 * @attr ref android.R.styleable#View_translationZ 13397 */ 13398 public void setTranslationZ(float translationZ) { 13399 if (translationZ != getTranslationZ()) { 13400 invalidateViewProperty(true, false); 13401 mRenderNode.setTranslationZ(translationZ); 13402 invalidateViewProperty(false, true); 13403 13404 invalidateParentIfNeededAndWasQuickRejected(); 13405 } 13406 } 13407 13408 /** @hide */ 13409 public void setAnimationMatrix(Matrix matrix) { 13410 invalidateViewProperty(true, false); 13411 mRenderNode.setAnimationMatrix(matrix); 13412 invalidateViewProperty(false, true); 13413 13414 invalidateParentIfNeededAndWasQuickRejected(); 13415 } 13416 13417 /** 13418 * Returns the current StateListAnimator if exists. 13419 * 13420 * @return StateListAnimator or null if it does not exists 13421 * @see #setStateListAnimator(android.animation.StateListAnimator) 13422 */ 13423 public StateListAnimator getStateListAnimator() { 13424 return mStateListAnimator; 13425 } 13426 13427 /** 13428 * Attaches the provided StateListAnimator to this View. 13429 * <p> 13430 * Any previously attached StateListAnimator will be detached. 13431 * 13432 * @param stateListAnimator The StateListAnimator to update the view 13433 * @see {@link android.animation.StateListAnimator} 13434 */ 13435 public void setStateListAnimator(StateListAnimator stateListAnimator) { 13436 if (mStateListAnimator == stateListAnimator) { 13437 return; 13438 } 13439 if (mStateListAnimator != null) { 13440 mStateListAnimator.setTarget(null); 13441 } 13442 mStateListAnimator = stateListAnimator; 13443 if (stateListAnimator != null) { 13444 stateListAnimator.setTarget(this); 13445 if (isAttachedToWindow()) { 13446 stateListAnimator.setState(getDrawableState()); 13447 } 13448 } 13449 } 13450 13451 /** 13452 * Returns whether the Outline should be used to clip the contents of the View. 13453 * <p> 13454 * Note that this flag will only be respected if the View's Outline returns true from 13455 * {@link Outline#canClip()}. 13456 * 13457 * @see #setOutlineProvider(ViewOutlineProvider) 13458 * @see #setClipToOutline(boolean) 13459 */ 13460 public final boolean getClipToOutline() { 13461 return mRenderNode.getClipToOutline(); 13462 } 13463 13464 /** 13465 * Sets whether the View's Outline should be used to clip the contents of the View. 13466 * <p> 13467 * Only a single non-rectangular clip can be applied on a View at any time. 13468 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 13469 * circular reveal} animation take priority over Outline clipping, and 13470 * child Outline clipping takes priority over Outline clipping done by a 13471 * parent. 13472 * <p> 13473 * Note that this flag will only be respected if the View's Outline returns true from 13474 * {@link Outline#canClip()}. 13475 * 13476 * @see #setOutlineProvider(ViewOutlineProvider) 13477 * @see #getClipToOutline() 13478 */ 13479 public void setClipToOutline(boolean clipToOutline) { 13480 damageInParent(); 13481 if (getClipToOutline() != clipToOutline) { 13482 mRenderNode.setClipToOutline(clipToOutline); 13483 } 13484 } 13485 13486 // correspond to the enum values of View_outlineProvider 13487 private static final int PROVIDER_BACKGROUND = 0; 13488 private static final int PROVIDER_NONE = 1; 13489 private static final int PROVIDER_BOUNDS = 2; 13490 private static final int PROVIDER_PADDED_BOUNDS = 3; 13491 private void setOutlineProviderFromAttribute(int providerInt) { 13492 switch (providerInt) { 13493 case PROVIDER_BACKGROUND: 13494 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 13495 break; 13496 case PROVIDER_NONE: 13497 setOutlineProvider(null); 13498 break; 13499 case PROVIDER_BOUNDS: 13500 setOutlineProvider(ViewOutlineProvider.BOUNDS); 13501 break; 13502 case PROVIDER_PADDED_BOUNDS: 13503 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 13504 break; 13505 } 13506 } 13507 13508 /** 13509 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 13510 * the shape of the shadow it casts, and enables outline clipping. 13511 * <p> 13512 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 13513 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 13514 * outline provider with this method allows this behavior to be overridden. 13515 * <p> 13516 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 13517 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 13518 * <p> 13519 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 13520 * 13521 * @see #setClipToOutline(boolean) 13522 * @see #getClipToOutline() 13523 * @see #getOutlineProvider() 13524 */ 13525 public void setOutlineProvider(ViewOutlineProvider provider) { 13526 mOutlineProvider = provider; 13527 invalidateOutline(); 13528 } 13529 13530 /** 13531 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 13532 * that defines the shape of the shadow it casts, and enables outline clipping. 13533 * 13534 * @see #setOutlineProvider(ViewOutlineProvider) 13535 */ 13536 public ViewOutlineProvider getOutlineProvider() { 13537 return mOutlineProvider; 13538 } 13539 13540 /** 13541 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 13542 * 13543 * @see #setOutlineProvider(ViewOutlineProvider) 13544 */ 13545 public void invalidateOutline() { 13546 rebuildOutline(); 13547 13548 notifySubtreeAccessibilityStateChangedIfNeeded(); 13549 invalidateViewProperty(false, false); 13550 } 13551 13552 /** 13553 * Internal version of {@link #invalidateOutline()} which invalidates the 13554 * outline without invalidating the view itself. This is intended to be called from 13555 * within methods in the View class itself which are the result of the view being 13556 * invalidated already. For example, when we are drawing the background of a View, 13557 * we invalidate the outline in case it changed in the meantime, but we do not 13558 * need to invalidate the view because we're already drawing the background as part 13559 * of drawing the view in response to an earlier invalidation of the view. 13560 */ 13561 private void rebuildOutline() { 13562 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 13563 if (mAttachInfo == null) return; 13564 13565 if (mOutlineProvider == null) { 13566 // no provider, remove outline 13567 mRenderNode.setOutline(null); 13568 } else { 13569 final Outline outline = mAttachInfo.mTmpOutline; 13570 outline.setEmpty(); 13571 outline.setAlpha(1.0f); 13572 13573 mOutlineProvider.getOutline(this, outline); 13574 mRenderNode.setOutline(outline); 13575 } 13576 } 13577 13578 /** 13579 * HierarchyViewer only 13580 * 13581 * @hide 13582 */ 13583 @ViewDebug.ExportedProperty(category = "drawing") 13584 public boolean hasShadow() { 13585 return mRenderNode.hasShadow(); 13586 } 13587 13588 13589 /** @hide */ 13590 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 13591 mRenderNode.setRevealClip(shouldClip, x, y, radius); 13592 invalidateViewProperty(false, false); 13593 } 13594 13595 /** 13596 * Hit rectangle in parent's coordinates 13597 * 13598 * @param outRect The hit rectangle of the view. 13599 */ 13600 public void getHitRect(Rect outRect) { 13601 if (hasIdentityMatrix() || mAttachInfo == null) { 13602 outRect.set(mLeft, mTop, mRight, mBottom); 13603 } else { 13604 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 13605 tmpRect.set(0, 0, getWidth(), getHeight()); 13606 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 13607 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 13608 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 13609 } 13610 } 13611 13612 /** 13613 * Determines whether the given point, in local coordinates is inside the view. 13614 */ 13615 /*package*/ final boolean pointInView(float localX, float localY) { 13616 return pointInView(localX, localY, 0); 13617 } 13618 13619 /** 13620 * Utility method to determine whether the given point, in local coordinates, 13621 * is inside the view, where the area of the view is expanded by the slop factor. 13622 * This method is called while processing touch-move events to determine if the event 13623 * is still within the view. 13624 * 13625 * @hide 13626 */ 13627 public boolean pointInView(float localX, float localY, float slop) { 13628 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 13629 localY < ((mBottom - mTop) + slop); 13630 } 13631 13632 /** 13633 * When a view has focus and the user navigates away from it, the next view is searched for 13634 * starting from the rectangle filled in by this method. 13635 * 13636 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 13637 * of the view. However, if your view maintains some idea of internal selection, 13638 * such as a cursor, or a selected row or column, you should override this method and 13639 * fill in a more specific rectangle. 13640 * 13641 * @param r The rectangle to fill in, in this view's coordinates. 13642 */ 13643 public void getFocusedRect(Rect r) { 13644 getDrawingRect(r); 13645 } 13646 13647 /** 13648 * If some part of this view is not clipped by any of its parents, then 13649 * return that area in r in global (root) coordinates. To convert r to local 13650 * coordinates (without taking possible View rotations into account), offset 13651 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 13652 * If the view is completely clipped or translated out, return false. 13653 * 13654 * @param r If true is returned, r holds the global coordinates of the 13655 * visible portion of this view. 13656 * @param globalOffset If true is returned, globalOffset holds the dx,dy 13657 * between this view and its root. globalOffet may be null. 13658 * @return true if r is non-empty (i.e. part of the view is visible at the 13659 * root level. 13660 */ 13661 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 13662 int width = mRight - mLeft; 13663 int height = mBottom - mTop; 13664 if (width > 0 && height > 0) { 13665 r.set(0, 0, width, height); 13666 if (globalOffset != null) { 13667 globalOffset.set(-mScrollX, -mScrollY); 13668 } 13669 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 13670 } 13671 return false; 13672 } 13673 13674 public final boolean getGlobalVisibleRect(Rect r) { 13675 return getGlobalVisibleRect(r, null); 13676 } 13677 13678 public final boolean getLocalVisibleRect(Rect r) { 13679 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 13680 if (getGlobalVisibleRect(r, offset)) { 13681 r.offset(-offset.x, -offset.y); // make r local 13682 return true; 13683 } 13684 return false; 13685 } 13686 13687 /** 13688 * Offset this view's vertical location by the specified number of pixels. 13689 * 13690 * @param offset the number of pixels to offset the view by 13691 */ 13692 public void offsetTopAndBottom(int offset) { 13693 if (offset != 0) { 13694 final boolean matrixIsIdentity = hasIdentityMatrix(); 13695 if (matrixIsIdentity) { 13696 if (isHardwareAccelerated()) { 13697 invalidateViewProperty(false, false); 13698 } else { 13699 final ViewParent p = mParent; 13700 if (p != null && mAttachInfo != null) { 13701 final Rect r = mAttachInfo.mTmpInvalRect; 13702 int minTop; 13703 int maxBottom; 13704 int yLoc; 13705 if (offset < 0) { 13706 minTop = mTop + offset; 13707 maxBottom = mBottom; 13708 yLoc = offset; 13709 } else { 13710 minTop = mTop; 13711 maxBottom = mBottom + offset; 13712 yLoc = 0; 13713 } 13714 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 13715 p.invalidateChild(this, r); 13716 } 13717 } 13718 } else { 13719 invalidateViewProperty(false, false); 13720 } 13721 13722 mTop += offset; 13723 mBottom += offset; 13724 mRenderNode.offsetTopAndBottom(offset); 13725 if (isHardwareAccelerated()) { 13726 invalidateViewProperty(false, false); 13727 invalidateParentIfNeededAndWasQuickRejected(); 13728 } else { 13729 if (!matrixIsIdentity) { 13730 invalidateViewProperty(false, true); 13731 } 13732 invalidateParentIfNeeded(); 13733 } 13734 notifySubtreeAccessibilityStateChangedIfNeeded(); 13735 } 13736 } 13737 13738 /** 13739 * Offset this view's horizontal location by the specified amount of pixels. 13740 * 13741 * @param offset the number of pixels to offset the view by 13742 */ 13743 public void offsetLeftAndRight(int offset) { 13744 if (offset != 0) { 13745 final boolean matrixIsIdentity = hasIdentityMatrix(); 13746 if (matrixIsIdentity) { 13747 if (isHardwareAccelerated()) { 13748 invalidateViewProperty(false, false); 13749 } else { 13750 final ViewParent p = mParent; 13751 if (p != null && mAttachInfo != null) { 13752 final Rect r = mAttachInfo.mTmpInvalRect; 13753 int minLeft; 13754 int maxRight; 13755 if (offset < 0) { 13756 minLeft = mLeft + offset; 13757 maxRight = mRight; 13758 } else { 13759 minLeft = mLeft; 13760 maxRight = mRight + offset; 13761 } 13762 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 13763 p.invalidateChild(this, r); 13764 } 13765 } 13766 } else { 13767 invalidateViewProperty(false, false); 13768 } 13769 13770 mLeft += offset; 13771 mRight += offset; 13772 mRenderNode.offsetLeftAndRight(offset); 13773 if (isHardwareAccelerated()) { 13774 invalidateViewProperty(false, false); 13775 invalidateParentIfNeededAndWasQuickRejected(); 13776 } else { 13777 if (!matrixIsIdentity) { 13778 invalidateViewProperty(false, true); 13779 } 13780 invalidateParentIfNeeded(); 13781 } 13782 notifySubtreeAccessibilityStateChangedIfNeeded(); 13783 } 13784 } 13785 13786 /** 13787 * Get the LayoutParams associated with this view. All views should have 13788 * layout parameters. These supply parameters to the <i>parent</i> of this 13789 * view specifying how it should be arranged. There are many subclasses of 13790 * ViewGroup.LayoutParams, and these correspond to the different subclasses 13791 * of ViewGroup that are responsible for arranging their children. 13792 * 13793 * This method may return null if this View is not attached to a parent 13794 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 13795 * was not invoked successfully. When a View is attached to a parent 13796 * ViewGroup, this method must not return null. 13797 * 13798 * @return The LayoutParams associated with this view, or null if no 13799 * parameters have been set yet 13800 */ 13801 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 13802 public ViewGroup.LayoutParams getLayoutParams() { 13803 return mLayoutParams; 13804 } 13805 13806 /** 13807 * Set the layout parameters associated with this view. These supply 13808 * parameters to the <i>parent</i> of this view specifying how it should be 13809 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 13810 * correspond to the different subclasses of ViewGroup that are responsible 13811 * for arranging their children. 13812 * 13813 * @param params The layout parameters for this view, cannot be null 13814 */ 13815 public void setLayoutParams(ViewGroup.LayoutParams params) { 13816 if (params == null) { 13817 throw new NullPointerException("Layout parameters cannot be null"); 13818 } 13819 mLayoutParams = params; 13820 resolveLayoutParams(); 13821 if (mParent instanceof ViewGroup) { 13822 ((ViewGroup) mParent).onSetLayoutParams(this, params); 13823 } 13824 requestLayout(); 13825 } 13826 13827 /** 13828 * Resolve the layout parameters depending on the resolved layout direction 13829 * 13830 * @hide 13831 */ 13832 public void resolveLayoutParams() { 13833 if (mLayoutParams != null) { 13834 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 13835 } 13836 } 13837 13838 /** 13839 * Set the scrolled position of your view. This will cause a call to 13840 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13841 * invalidated. 13842 * @param x the x position to scroll to 13843 * @param y the y position to scroll to 13844 */ 13845 public void scrollTo(int x, int y) { 13846 if (mScrollX != x || mScrollY != y) { 13847 int oldX = mScrollX; 13848 int oldY = mScrollY; 13849 mScrollX = x; 13850 mScrollY = y; 13851 invalidateParentCaches(); 13852 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 13853 if (!awakenScrollBars()) { 13854 postInvalidateOnAnimation(); 13855 } 13856 } 13857 } 13858 13859 /** 13860 * Move the scrolled position of your view. This will cause a call to 13861 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13862 * invalidated. 13863 * @param x the amount of pixels to scroll by horizontally 13864 * @param y the amount of pixels to scroll by vertically 13865 */ 13866 public void scrollBy(int x, int y) { 13867 scrollTo(mScrollX + x, mScrollY + y); 13868 } 13869 13870 /** 13871 * <p>Trigger the scrollbars to draw. When invoked this method starts an 13872 * animation to fade the scrollbars out after a default delay. If a subclass 13873 * provides animated scrolling, the start delay should equal the duration 13874 * of the scrolling animation.</p> 13875 * 13876 * <p>The animation starts only if at least one of the scrollbars is 13877 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 13878 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 13879 * this method returns true, and false otherwise. If the animation is 13880 * started, this method calls {@link #invalidate()}; in that case the 13881 * caller should not call {@link #invalidate()}.</p> 13882 * 13883 * <p>This method should be invoked every time a subclass directly updates 13884 * the scroll parameters.</p> 13885 * 13886 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 13887 * and {@link #scrollTo(int, int)}.</p> 13888 * 13889 * @return true if the animation is played, false otherwise 13890 * 13891 * @see #awakenScrollBars(int) 13892 * @see #scrollBy(int, int) 13893 * @see #scrollTo(int, int) 13894 * @see #isHorizontalScrollBarEnabled() 13895 * @see #isVerticalScrollBarEnabled() 13896 * @see #setHorizontalScrollBarEnabled(boolean) 13897 * @see #setVerticalScrollBarEnabled(boolean) 13898 */ 13899 protected boolean awakenScrollBars() { 13900 return mScrollCache != null && 13901 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 13902 } 13903 13904 /** 13905 * Trigger the scrollbars to draw. 13906 * This method differs from awakenScrollBars() only in its default duration. 13907 * initialAwakenScrollBars() will show the scroll bars for longer than 13908 * usual to give the user more of a chance to notice them. 13909 * 13910 * @return true if the animation is played, false otherwise. 13911 */ 13912 private boolean initialAwakenScrollBars() { 13913 return mScrollCache != null && 13914 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 13915 } 13916 13917 /** 13918 * <p> 13919 * Trigger the scrollbars to draw. When invoked this method starts an 13920 * animation to fade the scrollbars out after a fixed delay. If a subclass 13921 * provides animated scrolling, the start delay should equal the duration of 13922 * the scrolling animation. 13923 * </p> 13924 * 13925 * <p> 13926 * The animation starts only if at least one of the scrollbars is enabled, 13927 * as specified by {@link #isHorizontalScrollBarEnabled()} and 13928 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 13929 * this method returns true, and false otherwise. If the animation is 13930 * started, this method calls {@link #invalidate()}; in that case the caller 13931 * should not call {@link #invalidate()}. 13932 * </p> 13933 * 13934 * <p> 13935 * This method should be invoked every time a subclass directly updates the 13936 * scroll parameters. 13937 * </p> 13938 * 13939 * @param startDelay the delay, in milliseconds, after which the animation 13940 * should start; when the delay is 0, the animation starts 13941 * immediately 13942 * @return true if the animation is played, false otherwise 13943 * 13944 * @see #scrollBy(int, int) 13945 * @see #scrollTo(int, int) 13946 * @see #isHorizontalScrollBarEnabled() 13947 * @see #isVerticalScrollBarEnabled() 13948 * @see #setHorizontalScrollBarEnabled(boolean) 13949 * @see #setVerticalScrollBarEnabled(boolean) 13950 */ 13951 protected boolean awakenScrollBars(int startDelay) { 13952 return awakenScrollBars(startDelay, true); 13953 } 13954 13955 /** 13956 * <p> 13957 * Trigger the scrollbars to draw. When invoked this method starts an 13958 * animation to fade the scrollbars out after a fixed delay. If a subclass 13959 * provides animated scrolling, the start delay should equal the duration of 13960 * the scrolling animation. 13961 * </p> 13962 * 13963 * <p> 13964 * The animation starts only if at least one of the scrollbars is enabled, 13965 * as specified by {@link #isHorizontalScrollBarEnabled()} and 13966 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 13967 * this method returns true, and false otherwise. If the animation is 13968 * started, this method calls {@link #invalidate()} if the invalidate parameter 13969 * is set to true; in that case the caller 13970 * should not call {@link #invalidate()}. 13971 * </p> 13972 * 13973 * <p> 13974 * This method should be invoked every time a subclass directly updates the 13975 * scroll parameters. 13976 * </p> 13977 * 13978 * @param startDelay the delay, in milliseconds, after which the animation 13979 * should start; when the delay is 0, the animation starts 13980 * immediately 13981 * 13982 * @param invalidate Whether this method should call invalidate 13983 * 13984 * @return true if the animation is played, false otherwise 13985 * 13986 * @see #scrollBy(int, int) 13987 * @see #scrollTo(int, int) 13988 * @see #isHorizontalScrollBarEnabled() 13989 * @see #isVerticalScrollBarEnabled() 13990 * @see #setHorizontalScrollBarEnabled(boolean) 13991 * @see #setVerticalScrollBarEnabled(boolean) 13992 */ 13993 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 13994 final ScrollabilityCache scrollCache = mScrollCache; 13995 13996 if (scrollCache == null || !scrollCache.fadeScrollBars) { 13997 return false; 13998 } 13999 14000 if (scrollCache.scrollBar == null) { 14001 scrollCache.scrollBar = new ScrollBarDrawable(); 14002 scrollCache.scrollBar.setState(getDrawableState()); 14003 scrollCache.scrollBar.setCallback(this); 14004 } 14005 14006 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 14007 14008 if (invalidate) { 14009 // Invalidate to show the scrollbars 14010 postInvalidateOnAnimation(); 14011 } 14012 14013 if (scrollCache.state == ScrollabilityCache.OFF) { 14014 // FIXME: this is copied from WindowManagerService. 14015 // We should get this value from the system when it 14016 // is possible to do so. 14017 final int KEY_REPEAT_FIRST_DELAY = 750; 14018 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 14019 } 14020 14021 // Tell mScrollCache when we should start fading. This may 14022 // extend the fade start time if one was already scheduled 14023 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 14024 scrollCache.fadeStartTime = fadeStartTime; 14025 scrollCache.state = ScrollabilityCache.ON; 14026 14027 // Schedule our fader to run, unscheduling any old ones first 14028 if (mAttachInfo != null) { 14029 mAttachInfo.mHandler.removeCallbacks(scrollCache); 14030 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 14031 } 14032 14033 return true; 14034 } 14035 14036 return false; 14037 } 14038 14039 /** 14040 * Do not invalidate views which are not visible and which are not running an animation. They 14041 * will not get drawn and they should not set dirty flags as if they will be drawn 14042 */ 14043 private boolean skipInvalidate() { 14044 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 14045 (!(mParent instanceof ViewGroup) || 14046 !((ViewGroup) mParent).isViewTransitioning(this)); 14047 } 14048 14049 /** 14050 * Mark the area defined by dirty as needing to be drawn. If the view is 14051 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14052 * point in the future. 14053 * <p> 14054 * This must be called from a UI thread. To call from a non-UI thread, call 14055 * {@link #postInvalidate()}. 14056 * <p> 14057 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 14058 * {@code dirty}. 14059 * 14060 * @param dirty the rectangle representing the bounds of the dirty region 14061 */ 14062 public void invalidate(Rect dirty) { 14063 final int scrollX = mScrollX; 14064 final int scrollY = mScrollY; 14065 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 14066 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 14067 } 14068 14069 /** 14070 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 14071 * coordinates of the dirty rect are relative to the view. If the view is 14072 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14073 * point in the future. 14074 * <p> 14075 * This must be called from a UI thread. To call from a non-UI thread, call 14076 * {@link #postInvalidate()}. 14077 * 14078 * @param l the left position of the dirty region 14079 * @param t the top position of the dirty region 14080 * @param r the right position of the dirty region 14081 * @param b the bottom position of the dirty region 14082 */ 14083 public void invalidate(int l, int t, int r, int b) { 14084 final int scrollX = mScrollX; 14085 final int scrollY = mScrollY; 14086 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 14087 } 14088 14089 /** 14090 * Invalidate the whole view. If the view is visible, 14091 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 14092 * the future. 14093 * <p> 14094 * This must be called from a UI thread. To call from a non-UI thread, call 14095 * {@link #postInvalidate()}. 14096 */ 14097 public void invalidate() { 14098 invalidate(true); 14099 } 14100 14101 /** 14102 * This is where the invalidate() work actually happens. A full invalidate() 14103 * causes the drawing cache to be invalidated, but this function can be 14104 * called with invalidateCache set to false to skip that invalidation step 14105 * for cases that do not need it (for example, a component that remains at 14106 * the same dimensions with the same content). 14107 * 14108 * @param invalidateCache Whether the drawing cache for this view should be 14109 * invalidated as well. This is usually true for a full 14110 * invalidate, but may be set to false if the View's contents or 14111 * dimensions have not changed. 14112 */ 14113 void invalidate(boolean invalidateCache) { 14114 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 14115 } 14116 14117 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 14118 boolean fullInvalidate) { 14119 if (mGhostView != null) { 14120 mGhostView.invalidate(true); 14121 return; 14122 } 14123 14124 if (skipInvalidate()) { 14125 return; 14126 } 14127 14128 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 14129 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 14130 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 14131 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 14132 if (fullInvalidate) { 14133 mLastIsOpaque = isOpaque(); 14134 mPrivateFlags &= ~PFLAG_DRAWN; 14135 } 14136 14137 mPrivateFlags |= PFLAG_DIRTY; 14138 14139 if (invalidateCache) { 14140 mPrivateFlags |= PFLAG_INVALIDATED; 14141 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 14142 } 14143 14144 // Propagate the damage rectangle to the parent view. 14145 final AttachInfo ai = mAttachInfo; 14146 final ViewParent p = mParent; 14147 if (p != null && ai != null && l < r && t < b) { 14148 final Rect damage = ai.mTmpInvalRect; 14149 damage.set(l, t, r, b); 14150 p.invalidateChild(this, damage); 14151 } 14152 14153 // Damage the entire projection receiver, if necessary. 14154 if (mBackground != null && mBackground.isProjected()) { 14155 final View receiver = getProjectionReceiver(); 14156 if (receiver != null) { 14157 receiver.damageInParent(); 14158 } 14159 } 14160 } 14161 } 14162 14163 /** 14164 * @return this view's projection receiver, or {@code null} if none exists 14165 */ 14166 private View getProjectionReceiver() { 14167 ViewParent p = getParent(); 14168 while (p != null && p instanceof View) { 14169 final View v = (View) p; 14170 if (v.isProjectionReceiver()) { 14171 return v; 14172 } 14173 p = p.getParent(); 14174 } 14175 14176 return null; 14177 } 14178 14179 /** 14180 * @return whether the view is a projection receiver 14181 */ 14182 private boolean isProjectionReceiver() { 14183 return mBackground != null; 14184 } 14185 14186 /** 14187 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 14188 * set any flags or handle all of the cases handled by the default invalidation methods. 14189 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 14190 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 14191 * walk up the hierarchy, transforming the dirty rect as necessary. 14192 * 14193 * The method also handles normal invalidation logic if display list properties are not 14194 * being used in this view. The invalidateParent and forceRedraw flags are used by that 14195 * backup approach, to handle these cases used in the various property-setting methods. 14196 * 14197 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 14198 * are not being used in this view 14199 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 14200 * list properties are not being used in this view 14201 */ 14202 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 14203 if (!isHardwareAccelerated() 14204 || !mRenderNode.isValid() 14205 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 14206 if (invalidateParent) { 14207 invalidateParentCaches(); 14208 } 14209 if (forceRedraw) { 14210 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14211 } 14212 invalidate(false); 14213 } else { 14214 damageInParent(); 14215 } 14216 } 14217 14218 /** 14219 * Tells the parent view to damage this view's bounds. 14220 * 14221 * @hide 14222 */ 14223 protected void damageInParent() { 14224 final AttachInfo ai = mAttachInfo; 14225 final ViewParent p = mParent; 14226 if (p != null && ai != null) { 14227 final Rect r = ai.mTmpInvalRect; 14228 r.set(0, 0, mRight - mLeft, mBottom - mTop); 14229 if (mParent instanceof ViewGroup) { 14230 ((ViewGroup) mParent).damageChild(this, r); 14231 } else { 14232 mParent.invalidateChild(this, r); 14233 } 14234 } 14235 } 14236 14237 /** 14238 * Utility method to transform a given Rect by the current matrix of this view. 14239 */ 14240 void transformRect(final Rect rect) { 14241 if (!getMatrix().isIdentity()) { 14242 RectF boundingRect = mAttachInfo.mTmpTransformRect; 14243 boundingRect.set(rect); 14244 getMatrix().mapRect(boundingRect); 14245 rect.set((int) Math.floor(boundingRect.left), 14246 (int) Math.floor(boundingRect.top), 14247 (int) Math.ceil(boundingRect.right), 14248 (int) Math.ceil(boundingRect.bottom)); 14249 } 14250 } 14251 14252 /** 14253 * Used to indicate that the parent of this view should clear its caches. This functionality 14254 * is used to force the parent to rebuild its display list (when hardware-accelerated), 14255 * which is necessary when various parent-managed properties of the view change, such as 14256 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 14257 * clears the parent caches and does not causes an invalidate event. 14258 * 14259 * @hide 14260 */ 14261 protected void invalidateParentCaches() { 14262 if (mParent instanceof View) { 14263 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 14264 } 14265 } 14266 14267 /** 14268 * Used to indicate that the parent of this view should be invalidated. This functionality 14269 * is used to force the parent to rebuild its display list (when hardware-accelerated), 14270 * which is necessary when various parent-managed properties of the view change, such as 14271 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 14272 * an invalidation event to the parent. 14273 * 14274 * @hide 14275 */ 14276 protected void invalidateParentIfNeeded() { 14277 if (isHardwareAccelerated() && mParent instanceof View) { 14278 ((View) mParent).invalidate(true); 14279 } 14280 } 14281 14282 /** 14283 * @hide 14284 */ 14285 protected void invalidateParentIfNeededAndWasQuickRejected() { 14286 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 14287 // View was rejected last time it was drawn by its parent; this may have changed 14288 invalidateParentIfNeeded(); 14289 } 14290 } 14291 14292 /** 14293 * Indicates whether this View is opaque. An opaque View guarantees that it will 14294 * draw all the pixels overlapping its bounds using a fully opaque color. 14295 * 14296 * Subclasses of View should override this method whenever possible to indicate 14297 * whether an instance is opaque. Opaque Views are treated in a special way by 14298 * the View hierarchy, possibly allowing it to perform optimizations during 14299 * invalidate/draw passes. 14300 * 14301 * @return True if this View is guaranteed to be fully opaque, false otherwise. 14302 */ 14303 @ViewDebug.ExportedProperty(category = "drawing") 14304 public boolean isOpaque() { 14305 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 14306 getFinalAlpha() >= 1.0f; 14307 } 14308 14309 /** 14310 * @hide 14311 */ 14312 protected void computeOpaqueFlags() { 14313 // Opaque if: 14314 // - Has a background 14315 // - Background is opaque 14316 // - Doesn't have scrollbars or scrollbars overlay 14317 14318 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 14319 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 14320 } else { 14321 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 14322 } 14323 14324 final int flags = mViewFlags; 14325 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 14326 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 14327 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 14328 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 14329 } else { 14330 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 14331 } 14332 } 14333 14334 /** 14335 * @hide 14336 */ 14337 protected boolean hasOpaqueScrollbars() { 14338 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 14339 } 14340 14341 /** 14342 * @return A handler associated with the thread running the View. This 14343 * handler can be used to pump events in the UI events queue. 14344 */ 14345 public Handler getHandler() { 14346 final AttachInfo attachInfo = mAttachInfo; 14347 if (attachInfo != null) { 14348 return attachInfo.mHandler; 14349 } 14350 return null; 14351 } 14352 14353 /** 14354 * Returns the queue of runnable for this view. 14355 * 14356 * @return the queue of runnables for this view 14357 */ 14358 private HandlerActionQueue getRunQueue() { 14359 if (mRunQueue == null) { 14360 mRunQueue = new HandlerActionQueue(); 14361 } 14362 return mRunQueue; 14363 } 14364 14365 /** 14366 * Gets the view root associated with the View. 14367 * @return The view root, or null if none. 14368 * @hide 14369 */ 14370 public ViewRootImpl getViewRootImpl() { 14371 if (mAttachInfo != null) { 14372 return mAttachInfo.mViewRootImpl; 14373 } 14374 return null; 14375 } 14376 14377 /** 14378 * @hide 14379 */ 14380 public ThreadedRenderer getThreadedRenderer() { 14381 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 14382 } 14383 14384 /** 14385 * <p>Causes the Runnable to be added to the message queue. 14386 * The runnable will be run on the user interface thread.</p> 14387 * 14388 * @param action The Runnable that will be executed. 14389 * 14390 * @return Returns true if the Runnable was successfully placed in to the 14391 * message queue. Returns false on failure, usually because the 14392 * looper processing the message queue is exiting. 14393 * 14394 * @see #postDelayed 14395 * @see #removeCallbacks 14396 */ 14397 public boolean post(Runnable action) { 14398 final AttachInfo attachInfo = mAttachInfo; 14399 if (attachInfo != null) { 14400 return attachInfo.mHandler.post(action); 14401 } 14402 14403 // Postpone the runnable until we know on which thread it needs to run. 14404 // Assume that the runnable will be successfully placed after attach. 14405 getRunQueue().post(action); 14406 return true; 14407 } 14408 14409 /** 14410 * <p>Causes the Runnable to be added to the message queue, to be run 14411 * after the specified amount of time elapses. 14412 * The runnable will be run on the user interface thread.</p> 14413 * 14414 * @param action The Runnable that will be executed. 14415 * @param delayMillis The delay (in milliseconds) until the Runnable 14416 * will be executed. 14417 * 14418 * @return true if the Runnable was successfully placed in to the 14419 * message queue. Returns false on failure, usually because the 14420 * looper processing the message queue is exiting. Note that a 14421 * result of true does not mean the Runnable will be processed -- 14422 * if the looper is quit before the delivery time of the message 14423 * occurs then the message will be dropped. 14424 * 14425 * @see #post 14426 * @see #removeCallbacks 14427 */ 14428 public boolean postDelayed(Runnable action, long delayMillis) { 14429 final AttachInfo attachInfo = mAttachInfo; 14430 if (attachInfo != null) { 14431 return attachInfo.mHandler.postDelayed(action, delayMillis); 14432 } 14433 14434 // Postpone the runnable until we know on which thread it needs to run. 14435 // Assume that the runnable will be successfully placed after attach. 14436 getRunQueue().postDelayed(action, delayMillis); 14437 return true; 14438 } 14439 14440 /** 14441 * <p>Causes the Runnable to execute on the next animation time step. 14442 * The runnable will be run on the user interface thread.</p> 14443 * 14444 * @param action The Runnable that will be executed. 14445 * 14446 * @see #postOnAnimationDelayed 14447 * @see #removeCallbacks 14448 */ 14449 public void postOnAnimation(Runnable action) { 14450 final AttachInfo attachInfo = mAttachInfo; 14451 if (attachInfo != null) { 14452 attachInfo.mViewRootImpl.mChoreographer.postCallback( 14453 Choreographer.CALLBACK_ANIMATION, action, null); 14454 } else { 14455 // Postpone the runnable until we know 14456 // on which thread it needs to run. 14457 getRunQueue().post(action); 14458 } 14459 } 14460 14461 /** 14462 * <p>Causes the Runnable to execute on the next animation time step, 14463 * after the specified amount of time elapses. 14464 * The runnable will be run on the user interface thread.</p> 14465 * 14466 * @param action The Runnable that will be executed. 14467 * @param delayMillis The delay (in milliseconds) until the Runnable 14468 * will be executed. 14469 * 14470 * @see #postOnAnimation 14471 * @see #removeCallbacks 14472 */ 14473 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 14474 final AttachInfo attachInfo = mAttachInfo; 14475 if (attachInfo != null) { 14476 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 14477 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 14478 } else { 14479 // Postpone the runnable until we know 14480 // on which thread it needs to run. 14481 getRunQueue().postDelayed(action, delayMillis); 14482 } 14483 } 14484 14485 /** 14486 * <p>Removes the specified Runnable from the message queue.</p> 14487 * 14488 * @param action The Runnable to remove from the message handling queue 14489 * 14490 * @return true if this view could ask the Handler to remove the Runnable, 14491 * false otherwise. When the returned value is true, the Runnable 14492 * may or may not have been actually removed from the message queue 14493 * (for instance, if the Runnable was not in the queue already.) 14494 * 14495 * @see #post 14496 * @see #postDelayed 14497 * @see #postOnAnimation 14498 * @see #postOnAnimationDelayed 14499 */ 14500 public boolean removeCallbacks(Runnable action) { 14501 if (action != null) { 14502 final AttachInfo attachInfo = mAttachInfo; 14503 if (attachInfo != null) { 14504 attachInfo.mHandler.removeCallbacks(action); 14505 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 14506 Choreographer.CALLBACK_ANIMATION, action, null); 14507 } 14508 getRunQueue().removeCallbacks(action); 14509 } 14510 return true; 14511 } 14512 14513 /** 14514 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 14515 * Use this to invalidate the View from a non-UI thread.</p> 14516 * 14517 * <p>This method can be invoked from outside of the UI thread 14518 * only when this View is attached to a window.</p> 14519 * 14520 * @see #invalidate() 14521 * @see #postInvalidateDelayed(long) 14522 */ 14523 public void postInvalidate() { 14524 postInvalidateDelayed(0); 14525 } 14526 14527 /** 14528 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14529 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 14530 * 14531 * <p>This method can be invoked from outside of the UI thread 14532 * only when this View is attached to a window.</p> 14533 * 14534 * @param left The left coordinate of the rectangle to invalidate. 14535 * @param top The top coordinate of the rectangle to invalidate. 14536 * @param right The right coordinate of the rectangle to invalidate. 14537 * @param bottom The bottom coordinate of the rectangle to invalidate. 14538 * 14539 * @see #invalidate(int, int, int, int) 14540 * @see #invalidate(Rect) 14541 * @see #postInvalidateDelayed(long, int, int, int, int) 14542 */ 14543 public void postInvalidate(int left, int top, int right, int bottom) { 14544 postInvalidateDelayed(0, left, top, right, bottom); 14545 } 14546 14547 /** 14548 * <p>Cause an invalidate to happen on a subsequent cycle through the event 14549 * loop. Waits for the specified amount of time.</p> 14550 * 14551 * <p>This method can be invoked from outside of the UI thread 14552 * only when this View is attached to a window.</p> 14553 * 14554 * @param delayMilliseconds the duration in milliseconds to delay the 14555 * invalidation by 14556 * 14557 * @see #invalidate() 14558 * @see #postInvalidate() 14559 */ 14560 public void postInvalidateDelayed(long delayMilliseconds) { 14561 // We try only with the AttachInfo because there's no point in invalidating 14562 // if we are not attached to our window 14563 final AttachInfo attachInfo = mAttachInfo; 14564 if (attachInfo != null) { 14565 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 14566 } 14567 } 14568 14569 /** 14570 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14571 * through the event loop. Waits for the specified amount of time.</p> 14572 * 14573 * <p>This method can be invoked from outside of the UI thread 14574 * only when this View is attached to a window.</p> 14575 * 14576 * @param delayMilliseconds the duration in milliseconds to delay the 14577 * invalidation by 14578 * @param left The left coordinate of the rectangle to invalidate. 14579 * @param top The top coordinate of the rectangle to invalidate. 14580 * @param right The right coordinate of the rectangle to invalidate. 14581 * @param bottom The bottom coordinate of the rectangle to invalidate. 14582 * 14583 * @see #invalidate(int, int, int, int) 14584 * @see #invalidate(Rect) 14585 * @see #postInvalidate(int, int, int, int) 14586 */ 14587 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 14588 int right, int bottom) { 14589 14590 // We try only with the AttachInfo because there's no point in invalidating 14591 // if we are not attached to our window 14592 final AttachInfo attachInfo = mAttachInfo; 14593 if (attachInfo != null) { 14594 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14595 info.target = this; 14596 info.left = left; 14597 info.top = top; 14598 info.right = right; 14599 info.bottom = bottom; 14600 14601 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 14602 } 14603 } 14604 14605 /** 14606 * <p>Cause an invalidate to happen on the next animation time step, typically the 14607 * next display frame.</p> 14608 * 14609 * <p>This method can be invoked from outside of the UI thread 14610 * only when this View is attached to a window.</p> 14611 * 14612 * @see #invalidate() 14613 */ 14614 public void postInvalidateOnAnimation() { 14615 // We try only with the AttachInfo because there's no point in invalidating 14616 // if we are not attached to our window 14617 final AttachInfo attachInfo = mAttachInfo; 14618 if (attachInfo != null) { 14619 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 14620 } 14621 } 14622 14623 /** 14624 * <p>Cause an invalidate of the specified area to happen on the next animation 14625 * time step, typically the next display frame.</p> 14626 * 14627 * <p>This method can be invoked from outside of the UI thread 14628 * only when this View is attached to a window.</p> 14629 * 14630 * @param left The left coordinate of the rectangle to invalidate. 14631 * @param top The top coordinate of the rectangle to invalidate. 14632 * @param right The right coordinate of the rectangle to invalidate. 14633 * @param bottom The bottom coordinate of the rectangle to invalidate. 14634 * 14635 * @see #invalidate(int, int, int, int) 14636 * @see #invalidate(Rect) 14637 */ 14638 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 14639 // We try only with the AttachInfo because there's no point in invalidating 14640 // if we are not attached to our window 14641 final AttachInfo attachInfo = mAttachInfo; 14642 if (attachInfo != null) { 14643 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14644 info.target = this; 14645 info.left = left; 14646 info.top = top; 14647 info.right = right; 14648 info.bottom = bottom; 14649 14650 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 14651 } 14652 } 14653 14654 /** 14655 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 14656 * This event is sent at most once every 14657 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 14658 */ 14659 private void postSendViewScrolledAccessibilityEventCallback() { 14660 if (mSendViewScrolledAccessibilityEvent == null) { 14661 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 14662 } 14663 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 14664 mSendViewScrolledAccessibilityEvent.mIsPending = true; 14665 postDelayed(mSendViewScrolledAccessibilityEvent, 14666 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 14667 } 14668 } 14669 14670 /** 14671 * Called by a parent to request that a child update its values for mScrollX 14672 * and mScrollY if necessary. This will typically be done if the child is 14673 * animating a scroll using a {@link android.widget.Scroller Scroller} 14674 * object. 14675 */ 14676 public void computeScroll() { 14677 } 14678 14679 /** 14680 * <p>Indicate whether the horizontal edges are faded when the view is 14681 * scrolled horizontally.</p> 14682 * 14683 * @return true if the horizontal edges should are faded on scroll, false 14684 * otherwise 14685 * 14686 * @see #setHorizontalFadingEdgeEnabled(boolean) 14687 * 14688 * @attr ref android.R.styleable#View_requiresFadingEdge 14689 */ 14690 public boolean isHorizontalFadingEdgeEnabled() { 14691 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 14692 } 14693 14694 /** 14695 * <p>Define whether the horizontal edges should be faded when this view 14696 * is scrolled horizontally.</p> 14697 * 14698 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 14699 * be faded when the view is scrolled 14700 * horizontally 14701 * 14702 * @see #isHorizontalFadingEdgeEnabled() 14703 * 14704 * @attr ref android.R.styleable#View_requiresFadingEdge 14705 */ 14706 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 14707 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 14708 if (horizontalFadingEdgeEnabled) { 14709 initScrollCache(); 14710 } 14711 14712 mViewFlags ^= FADING_EDGE_HORIZONTAL; 14713 } 14714 } 14715 14716 /** 14717 * <p>Indicate whether the vertical edges are faded when the view is 14718 * scrolled horizontally.</p> 14719 * 14720 * @return true if the vertical edges should are faded on scroll, false 14721 * otherwise 14722 * 14723 * @see #setVerticalFadingEdgeEnabled(boolean) 14724 * 14725 * @attr ref android.R.styleable#View_requiresFadingEdge 14726 */ 14727 public boolean isVerticalFadingEdgeEnabled() { 14728 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 14729 } 14730 14731 /** 14732 * <p>Define whether the vertical edges should be faded when this view 14733 * is scrolled vertically.</p> 14734 * 14735 * @param verticalFadingEdgeEnabled true if the vertical edges should 14736 * be faded when the view is scrolled 14737 * vertically 14738 * 14739 * @see #isVerticalFadingEdgeEnabled() 14740 * 14741 * @attr ref android.R.styleable#View_requiresFadingEdge 14742 */ 14743 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 14744 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 14745 if (verticalFadingEdgeEnabled) { 14746 initScrollCache(); 14747 } 14748 14749 mViewFlags ^= FADING_EDGE_VERTICAL; 14750 } 14751 } 14752 14753 /** 14754 * Returns the strength, or intensity, of the top faded edge. The strength is 14755 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14756 * returns 0.0 or 1.0 but no value in between. 14757 * 14758 * Subclasses should override this method to provide a smoother fade transition 14759 * when scrolling occurs. 14760 * 14761 * @return the intensity of the top fade as a float between 0.0f and 1.0f 14762 */ 14763 protected float getTopFadingEdgeStrength() { 14764 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 14765 } 14766 14767 /** 14768 * Returns the strength, or intensity, of the bottom faded edge. The strength is 14769 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14770 * returns 0.0 or 1.0 but no value in between. 14771 * 14772 * Subclasses should override this method to provide a smoother fade transition 14773 * when scrolling occurs. 14774 * 14775 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 14776 */ 14777 protected float getBottomFadingEdgeStrength() { 14778 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 14779 computeVerticalScrollRange() ? 1.0f : 0.0f; 14780 } 14781 14782 /** 14783 * Returns the strength, or intensity, of the left faded edge. The strength is 14784 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14785 * returns 0.0 or 1.0 but no value in between. 14786 * 14787 * Subclasses should override this method to provide a smoother fade transition 14788 * when scrolling occurs. 14789 * 14790 * @return the intensity of the left fade as a float between 0.0f and 1.0f 14791 */ 14792 protected float getLeftFadingEdgeStrength() { 14793 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 14794 } 14795 14796 /** 14797 * Returns the strength, or intensity, of the right faded edge. The strength is 14798 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14799 * returns 0.0 or 1.0 but no value in between. 14800 * 14801 * Subclasses should override this method to provide a smoother fade transition 14802 * when scrolling occurs. 14803 * 14804 * @return the intensity of the right fade as a float between 0.0f and 1.0f 14805 */ 14806 protected float getRightFadingEdgeStrength() { 14807 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 14808 computeHorizontalScrollRange() ? 1.0f : 0.0f; 14809 } 14810 14811 /** 14812 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 14813 * scrollbar is not drawn by default.</p> 14814 * 14815 * @return true if the horizontal scrollbar should be painted, false 14816 * otherwise 14817 * 14818 * @see #setHorizontalScrollBarEnabled(boolean) 14819 */ 14820 public boolean isHorizontalScrollBarEnabled() { 14821 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 14822 } 14823 14824 /** 14825 * <p>Define whether the horizontal scrollbar should be drawn or not. The 14826 * scrollbar is not drawn by default.</p> 14827 * 14828 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 14829 * be painted 14830 * 14831 * @see #isHorizontalScrollBarEnabled() 14832 */ 14833 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 14834 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 14835 mViewFlags ^= SCROLLBARS_HORIZONTAL; 14836 computeOpaqueFlags(); 14837 resolvePadding(); 14838 } 14839 } 14840 14841 /** 14842 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 14843 * scrollbar is not drawn by default.</p> 14844 * 14845 * @return true if the vertical scrollbar should be painted, false 14846 * otherwise 14847 * 14848 * @see #setVerticalScrollBarEnabled(boolean) 14849 */ 14850 public boolean isVerticalScrollBarEnabled() { 14851 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 14852 } 14853 14854 /** 14855 * <p>Define whether the vertical scrollbar should be drawn or not. The 14856 * scrollbar is not drawn by default.</p> 14857 * 14858 * @param verticalScrollBarEnabled true if the vertical scrollbar should 14859 * be painted 14860 * 14861 * @see #isVerticalScrollBarEnabled() 14862 */ 14863 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 14864 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 14865 mViewFlags ^= SCROLLBARS_VERTICAL; 14866 computeOpaqueFlags(); 14867 resolvePadding(); 14868 } 14869 } 14870 14871 /** 14872 * @hide 14873 */ 14874 protected void recomputePadding() { 14875 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 14876 } 14877 14878 /** 14879 * Define whether scrollbars will fade when the view is not scrolling. 14880 * 14881 * @param fadeScrollbars whether to enable fading 14882 * 14883 * @attr ref android.R.styleable#View_fadeScrollbars 14884 */ 14885 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 14886 initScrollCache(); 14887 final ScrollabilityCache scrollabilityCache = mScrollCache; 14888 scrollabilityCache.fadeScrollBars = fadeScrollbars; 14889 if (fadeScrollbars) { 14890 scrollabilityCache.state = ScrollabilityCache.OFF; 14891 } else { 14892 scrollabilityCache.state = ScrollabilityCache.ON; 14893 } 14894 } 14895 14896 /** 14897 * 14898 * Returns true if scrollbars will fade when this view is not scrolling 14899 * 14900 * @return true if scrollbar fading is enabled 14901 * 14902 * @attr ref android.R.styleable#View_fadeScrollbars 14903 */ 14904 public boolean isScrollbarFadingEnabled() { 14905 return mScrollCache != null && mScrollCache.fadeScrollBars; 14906 } 14907 14908 /** 14909 * 14910 * Returns the delay before scrollbars fade. 14911 * 14912 * @return the delay before scrollbars fade 14913 * 14914 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 14915 */ 14916 public int getScrollBarDefaultDelayBeforeFade() { 14917 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 14918 mScrollCache.scrollBarDefaultDelayBeforeFade; 14919 } 14920 14921 /** 14922 * Define the delay before scrollbars fade. 14923 * 14924 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 14925 * 14926 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 14927 */ 14928 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 14929 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 14930 } 14931 14932 /** 14933 * 14934 * Returns the scrollbar fade duration. 14935 * 14936 * @return the scrollbar fade duration, in milliseconds 14937 * 14938 * @attr ref android.R.styleable#View_scrollbarFadeDuration 14939 */ 14940 public int getScrollBarFadeDuration() { 14941 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 14942 mScrollCache.scrollBarFadeDuration; 14943 } 14944 14945 /** 14946 * Define the scrollbar fade duration. 14947 * 14948 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 14949 * 14950 * @attr ref android.R.styleable#View_scrollbarFadeDuration 14951 */ 14952 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 14953 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 14954 } 14955 14956 /** 14957 * 14958 * Returns the scrollbar size. 14959 * 14960 * @return the scrollbar size 14961 * 14962 * @attr ref android.R.styleable#View_scrollbarSize 14963 */ 14964 public int getScrollBarSize() { 14965 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 14966 mScrollCache.scrollBarSize; 14967 } 14968 14969 /** 14970 * Define the scrollbar size. 14971 * 14972 * @param scrollBarSize - the scrollbar size 14973 * 14974 * @attr ref android.R.styleable#View_scrollbarSize 14975 */ 14976 public void setScrollBarSize(int scrollBarSize) { 14977 getScrollCache().scrollBarSize = scrollBarSize; 14978 } 14979 14980 /** 14981 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 14982 * inset. When inset, they add to the padding of the view. And the scrollbars 14983 * can be drawn inside the padding area or on the edge of the view. For example, 14984 * if a view has a background drawable and you want to draw the scrollbars 14985 * inside the padding specified by the drawable, you can use 14986 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 14987 * appear at the edge of the view, ignoring the padding, then you can use 14988 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 14989 * @param style the style of the scrollbars. Should be one of 14990 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 14991 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 14992 * @see #SCROLLBARS_INSIDE_OVERLAY 14993 * @see #SCROLLBARS_INSIDE_INSET 14994 * @see #SCROLLBARS_OUTSIDE_OVERLAY 14995 * @see #SCROLLBARS_OUTSIDE_INSET 14996 * 14997 * @attr ref android.R.styleable#View_scrollbarStyle 14998 */ 14999 public void setScrollBarStyle(@ScrollBarStyle int style) { 15000 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 15001 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 15002 computeOpaqueFlags(); 15003 resolvePadding(); 15004 } 15005 } 15006 15007 /** 15008 * <p>Returns the current scrollbar style.</p> 15009 * @return the current scrollbar style 15010 * @see #SCROLLBARS_INSIDE_OVERLAY 15011 * @see #SCROLLBARS_INSIDE_INSET 15012 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15013 * @see #SCROLLBARS_OUTSIDE_INSET 15014 * 15015 * @attr ref android.R.styleable#View_scrollbarStyle 15016 */ 15017 @ViewDebug.ExportedProperty(mapping = { 15018 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 15019 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 15020 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 15021 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 15022 }) 15023 @ScrollBarStyle 15024 public int getScrollBarStyle() { 15025 return mViewFlags & SCROLLBARS_STYLE_MASK; 15026 } 15027 15028 /** 15029 * <p>Compute the horizontal range that the horizontal scrollbar 15030 * represents.</p> 15031 * 15032 * <p>The range is expressed in arbitrary units that must be the same as the 15033 * units used by {@link #computeHorizontalScrollExtent()} and 15034 * {@link #computeHorizontalScrollOffset()}.</p> 15035 * 15036 * <p>The default range is the drawing width of this view.</p> 15037 * 15038 * @return the total horizontal range represented by the horizontal 15039 * scrollbar 15040 * 15041 * @see #computeHorizontalScrollExtent() 15042 * @see #computeHorizontalScrollOffset() 15043 * @see android.widget.ScrollBarDrawable 15044 */ 15045 protected int computeHorizontalScrollRange() { 15046 return getWidth(); 15047 } 15048 15049 /** 15050 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 15051 * within the horizontal range. This value is used to compute the position 15052 * of the thumb within the scrollbar's track.</p> 15053 * 15054 * <p>The range is expressed in arbitrary units that must be the same as the 15055 * units used by {@link #computeHorizontalScrollRange()} and 15056 * {@link #computeHorizontalScrollExtent()}.</p> 15057 * 15058 * <p>The default offset is the scroll offset of this view.</p> 15059 * 15060 * @return the horizontal offset of the scrollbar's thumb 15061 * 15062 * @see #computeHorizontalScrollRange() 15063 * @see #computeHorizontalScrollExtent() 15064 * @see android.widget.ScrollBarDrawable 15065 */ 15066 protected int computeHorizontalScrollOffset() { 15067 return mScrollX; 15068 } 15069 15070 /** 15071 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 15072 * within the horizontal range. This value is used to compute the length 15073 * of the thumb within the scrollbar's track.</p> 15074 * 15075 * <p>The range is expressed in arbitrary units that must be the same as the 15076 * units used by {@link #computeHorizontalScrollRange()} and 15077 * {@link #computeHorizontalScrollOffset()}.</p> 15078 * 15079 * <p>The default extent is the drawing width of this view.</p> 15080 * 15081 * @return the horizontal extent of the scrollbar's thumb 15082 * 15083 * @see #computeHorizontalScrollRange() 15084 * @see #computeHorizontalScrollOffset() 15085 * @see android.widget.ScrollBarDrawable 15086 */ 15087 protected int computeHorizontalScrollExtent() { 15088 return getWidth(); 15089 } 15090 15091 /** 15092 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 15093 * 15094 * <p>The range is expressed in arbitrary units that must be the same as the 15095 * units used by {@link #computeVerticalScrollExtent()} and 15096 * {@link #computeVerticalScrollOffset()}.</p> 15097 * 15098 * @return the total vertical range represented by the vertical scrollbar 15099 * 15100 * <p>The default range is the drawing height of this view.</p> 15101 * 15102 * @see #computeVerticalScrollExtent() 15103 * @see #computeVerticalScrollOffset() 15104 * @see android.widget.ScrollBarDrawable 15105 */ 15106 protected int computeVerticalScrollRange() { 15107 return getHeight(); 15108 } 15109 15110 /** 15111 * <p>Compute the vertical offset of the vertical scrollbar's thumb 15112 * within the horizontal range. This value is used to compute the position 15113 * of the thumb within the scrollbar's track.</p> 15114 * 15115 * <p>The range is expressed in arbitrary units that must be the same as the 15116 * units used by {@link #computeVerticalScrollRange()} and 15117 * {@link #computeVerticalScrollExtent()}.</p> 15118 * 15119 * <p>The default offset is the scroll offset of this view.</p> 15120 * 15121 * @return the vertical offset of the scrollbar's thumb 15122 * 15123 * @see #computeVerticalScrollRange() 15124 * @see #computeVerticalScrollExtent() 15125 * @see android.widget.ScrollBarDrawable 15126 */ 15127 protected int computeVerticalScrollOffset() { 15128 return mScrollY; 15129 } 15130 15131 /** 15132 * <p>Compute the vertical extent of the vertical scrollbar's thumb 15133 * within the vertical range. This value is used to compute the length 15134 * of the thumb within the scrollbar's track.</p> 15135 * 15136 * <p>The range is expressed in arbitrary units that must be the same as the 15137 * units used by {@link #computeVerticalScrollRange()} and 15138 * {@link #computeVerticalScrollOffset()}.</p> 15139 * 15140 * <p>The default extent is the drawing height of this view.</p> 15141 * 15142 * @return the vertical extent of the scrollbar's thumb 15143 * 15144 * @see #computeVerticalScrollRange() 15145 * @see #computeVerticalScrollOffset() 15146 * @see android.widget.ScrollBarDrawable 15147 */ 15148 protected int computeVerticalScrollExtent() { 15149 return getHeight(); 15150 } 15151 15152 /** 15153 * Check if this view can be scrolled horizontally in a certain direction. 15154 * 15155 * @param direction Negative to check scrolling left, positive to check scrolling right. 15156 * @return true if this view can be scrolled in the specified direction, false otherwise. 15157 */ 15158 public boolean canScrollHorizontally(int direction) { 15159 final int offset = computeHorizontalScrollOffset(); 15160 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 15161 if (range == 0) return false; 15162 if (direction < 0) { 15163 return offset > 0; 15164 } else { 15165 return offset < range - 1; 15166 } 15167 } 15168 15169 /** 15170 * Check if this view can be scrolled vertically in a certain direction. 15171 * 15172 * @param direction Negative to check scrolling up, positive to check scrolling down. 15173 * @return true if this view can be scrolled in the specified direction, false otherwise. 15174 */ 15175 public boolean canScrollVertically(int direction) { 15176 final int offset = computeVerticalScrollOffset(); 15177 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 15178 if (range == 0) return false; 15179 if (direction < 0) { 15180 return offset > 0; 15181 } else { 15182 return offset < range - 1; 15183 } 15184 } 15185 15186 void getScrollIndicatorBounds(@NonNull Rect out) { 15187 out.left = mScrollX; 15188 out.right = mScrollX + mRight - mLeft; 15189 out.top = mScrollY; 15190 out.bottom = mScrollY + mBottom - mTop; 15191 } 15192 15193 private void onDrawScrollIndicators(Canvas c) { 15194 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 15195 // No scroll indicators enabled. 15196 return; 15197 } 15198 15199 final Drawable dr = mScrollIndicatorDrawable; 15200 if (dr == null) { 15201 // Scroll indicators aren't supported here. 15202 return; 15203 } 15204 15205 final int h = dr.getIntrinsicHeight(); 15206 final int w = dr.getIntrinsicWidth(); 15207 final Rect rect = mAttachInfo.mTmpInvalRect; 15208 getScrollIndicatorBounds(rect); 15209 15210 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 15211 final boolean canScrollUp = canScrollVertically(-1); 15212 if (canScrollUp) { 15213 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 15214 dr.draw(c); 15215 } 15216 } 15217 15218 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 15219 final boolean canScrollDown = canScrollVertically(1); 15220 if (canScrollDown) { 15221 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 15222 dr.draw(c); 15223 } 15224 } 15225 15226 final int leftRtl; 15227 final int rightRtl; 15228 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15229 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 15230 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 15231 } else { 15232 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 15233 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 15234 } 15235 15236 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 15237 if ((mPrivateFlags3 & leftMask) != 0) { 15238 final boolean canScrollLeft = canScrollHorizontally(-1); 15239 if (canScrollLeft) { 15240 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 15241 dr.draw(c); 15242 } 15243 } 15244 15245 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 15246 if ((mPrivateFlags3 & rightMask) != 0) { 15247 final boolean canScrollRight = canScrollHorizontally(1); 15248 if (canScrollRight) { 15249 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 15250 dr.draw(c); 15251 } 15252 } 15253 } 15254 15255 private void getHorizontalScrollBarBounds(Rect bounds) { 15256 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 15257 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 15258 && !isVerticalScrollBarHidden(); 15259 final int size = getHorizontalScrollbarHeight(); 15260 final int verticalScrollBarGap = drawVerticalScrollBar ? 15261 getVerticalScrollbarWidth() : 0; 15262 final int width = mRight - mLeft; 15263 final int height = mBottom - mTop; 15264 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 15265 bounds.left = mScrollX + (mPaddingLeft & inside); 15266 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 15267 bounds.bottom = bounds.top + size; 15268 } 15269 15270 private void getVerticalScrollBarBounds(Rect bounds) { 15271 if (mRoundScrollbarRenderer == null) { 15272 getStraightVerticalScrollBarBounds(bounds); 15273 } else { 15274 getRoundVerticalScrollBarBounds(bounds); 15275 } 15276 } 15277 15278 private void getRoundVerticalScrollBarBounds(Rect bounds) { 15279 final int width = mRight - mLeft; 15280 final int height = mBottom - mTop; 15281 // Do not take padding into account as we always want the scrollbars 15282 // to hug the screen for round wearable devices. 15283 bounds.left = mScrollX; 15284 bounds.top = mScrollY; 15285 bounds.right = bounds.left + width; 15286 bounds.bottom = mScrollY + height; 15287 } 15288 15289 private void getStraightVerticalScrollBarBounds(Rect bounds) { 15290 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 15291 final int size = getVerticalScrollbarWidth(); 15292 int verticalScrollbarPosition = mVerticalScrollbarPosition; 15293 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 15294 verticalScrollbarPosition = isLayoutRtl() ? 15295 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 15296 } 15297 final int width = mRight - mLeft; 15298 final int height = mBottom - mTop; 15299 switch (verticalScrollbarPosition) { 15300 default: 15301 case SCROLLBAR_POSITION_RIGHT: 15302 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 15303 break; 15304 case SCROLLBAR_POSITION_LEFT: 15305 bounds.left = mScrollX + (mUserPaddingLeft & inside); 15306 break; 15307 } 15308 bounds.top = mScrollY + (mPaddingTop & inside); 15309 bounds.right = bounds.left + size; 15310 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 15311 } 15312 15313 /** 15314 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 15315 * scrollbars are painted only if they have been awakened first.</p> 15316 * 15317 * @param canvas the canvas on which to draw the scrollbars 15318 * 15319 * @see #awakenScrollBars(int) 15320 */ 15321 protected final void onDrawScrollBars(Canvas canvas) { 15322 // scrollbars are drawn only when the animation is running 15323 final ScrollabilityCache cache = mScrollCache; 15324 15325 if (cache != null) { 15326 15327 int state = cache.state; 15328 15329 if (state == ScrollabilityCache.OFF) { 15330 return; 15331 } 15332 15333 boolean invalidate = false; 15334 15335 if (state == ScrollabilityCache.FADING) { 15336 // We're fading -- get our fade interpolation 15337 if (cache.interpolatorValues == null) { 15338 cache.interpolatorValues = new float[1]; 15339 } 15340 15341 float[] values = cache.interpolatorValues; 15342 15343 // Stops the animation if we're done 15344 if (cache.scrollBarInterpolator.timeToValues(values) == 15345 Interpolator.Result.FREEZE_END) { 15346 cache.state = ScrollabilityCache.OFF; 15347 } else { 15348 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 15349 } 15350 15351 // This will make the scroll bars inval themselves after 15352 // drawing. We only want this when we're fading so that 15353 // we prevent excessive redraws 15354 invalidate = true; 15355 } else { 15356 // We're just on -- but we may have been fading before so 15357 // reset alpha 15358 cache.scrollBar.mutate().setAlpha(255); 15359 } 15360 15361 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 15362 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 15363 && !isVerticalScrollBarHidden(); 15364 15365 // Fork out the scroll bar drawing for round wearable devices. 15366 if (mRoundScrollbarRenderer != null) { 15367 if (drawVerticalScrollBar) { 15368 final Rect bounds = cache.mScrollBarBounds; 15369 getVerticalScrollBarBounds(bounds); 15370 mRoundScrollbarRenderer.drawRoundScrollbars( 15371 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 15372 if (invalidate) { 15373 invalidate(); 15374 } 15375 } 15376 // Do not draw horizontal scroll bars for round wearable devices. 15377 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 15378 final ScrollBarDrawable scrollBar = cache.scrollBar; 15379 15380 if (drawHorizontalScrollBar) { 15381 scrollBar.setParameters(computeHorizontalScrollRange(), 15382 computeHorizontalScrollOffset(), 15383 computeHorizontalScrollExtent(), false); 15384 final Rect bounds = cache.mScrollBarBounds; 15385 getHorizontalScrollBarBounds(bounds); 15386 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 15387 bounds.right, bounds.bottom); 15388 if (invalidate) { 15389 invalidate(bounds); 15390 } 15391 } 15392 15393 if (drawVerticalScrollBar) { 15394 scrollBar.setParameters(computeVerticalScrollRange(), 15395 computeVerticalScrollOffset(), 15396 computeVerticalScrollExtent(), true); 15397 final Rect bounds = cache.mScrollBarBounds; 15398 getVerticalScrollBarBounds(bounds); 15399 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 15400 bounds.right, bounds.bottom); 15401 if (invalidate) { 15402 invalidate(bounds); 15403 } 15404 } 15405 } 15406 } 15407 } 15408 15409 /** 15410 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 15411 * FastScroller is visible. 15412 * @return whether to temporarily hide the vertical scrollbar 15413 * @hide 15414 */ 15415 protected boolean isVerticalScrollBarHidden() { 15416 return false; 15417 } 15418 15419 /** 15420 * <p>Draw the horizontal scrollbar if 15421 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 15422 * 15423 * @param canvas the canvas on which to draw the scrollbar 15424 * @param scrollBar the scrollbar's drawable 15425 * 15426 * @see #isHorizontalScrollBarEnabled() 15427 * @see #computeHorizontalScrollRange() 15428 * @see #computeHorizontalScrollExtent() 15429 * @see #computeHorizontalScrollOffset() 15430 * @see android.widget.ScrollBarDrawable 15431 * @hide 15432 */ 15433 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 15434 int l, int t, int r, int b) { 15435 scrollBar.setBounds(l, t, r, b); 15436 scrollBar.draw(canvas); 15437 } 15438 15439 /** 15440 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 15441 * returns true.</p> 15442 * 15443 * @param canvas the canvas on which to draw the scrollbar 15444 * @param scrollBar the scrollbar's drawable 15445 * 15446 * @see #isVerticalScrollBarEnabled() 15447 * @see #computeVerticalScrollRange() 15448 * @see #computeVerticalScrollExtent() 15449 * @see #computeVerticalScrollOffset() 15450 * @see android.widget.ScrollBarDrawable 15451 * @hide 15452 */ 15453 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 15454 int l, int t, int r, int b) { 15455 scrollBar.setBounds(l, t, r, b); 15456 scrollBar.draw(canvas); 15457 } 15458 15459 /** 15460 * Implement this to do your drawing. 15461 * 15462 * @param canvas the canvas on which the background will be drawn 15463 */ 15464 protected void onDraw(Canvas canvas) { 15465 } 15466 15467 /* 15468 * Caller is responsible for calling requestLayout if necessary. 15469 * (This allows addViewInLayout to not request a new layout.) 15470 */ 15471 void assignParent(ViewParent parent) { 15472 if (mParent == null) { 15473 mParent = parent; 15474 } else if (parent == null) { 15475 mParent = null; 15476 } else { 15477 throw new RuntimeException("view " + this + " being added, but" 15478 + " it already has a parent"); 15479 } 15480 } 15481 15482 /** 15483 * This is called when the view is attached to a window. At this point it 15484 * has a Surface and will start drawing. Note that this function is 15485 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 15486 * however it may be called any time before the first onDraw -- including 15487 * before or after {@link #onMeasure(int, int)}. 15488 * 15489 * @see #onDetachedFromWindow() 15490 */ 15491 @CallSuper 15492 protected void onAttachedToWindow() { 15493 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 15494 mParent.requestTransparentRegion(this); 15495 } 15496 15497 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15498 15499 jumpDrawablesToCurrentState(); 15500 15501 resetSubtreeAccessibilityStateChanged(); 15502 15503 // rebuild, since Outline not maintained while View is detached 15504 rebuildOutline(); 15505 15506 if (isFocused()) { 15507 InputMethodManager imm = InputMethodManager.peekInstance(); 15508 if (imm != null) { 15509 imm.focusIn(this); 15510 } 15511 } 15512 } 15513 15514 /** 15515 * Resolve all RTL related properties. 15516 * 15517 * @return true if resolution of RTL properties has been done 15518 * 15519 * @hide 15520 */ 15521 public boolean resolveRtlPropertiesIfNeeded() { 15522 if (!needRtlPropertiesResolution()) return false; 15523 15524 // Order is important here: LayoutDirection MUST be resolved first 15525 if (!isLayoutDirectionResolved()) { 15526 resolveLayoutDirection(); 15527 resolveLayoutParams(); 15528 } 15529 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 15530 if (!isTextDirectionResolved()) { 15531 resolveTextDirection(); 15532 } 15533 if (!isTextAlignmentResolved()) { 15534 resolveTextAlignment(); 15535 } 15536 // Should resolve Drawables before Padding because we need the layout direction of the 15537 // Drawable to correctly resolve Padding. 15538 if (!areDrawablesResolved()) { 15539 resolveDrawables(); 15540 } 15541 if (!isPaddingResolved()) { 15542 resolvePadding(); 15543 } 15544 onRtlPropertiesChanged(getLayoutDirection()); 15545 return true; 15546 } 15547 15548 /** 15549 * Reset resolution of all RTL related properties. 15550 * 15551 * @hide 15552 */ 15553 public void resetRtlProperties() { 15554 resetResolvedLayoutDirection(); 15555 resetResolvedTextDirection(); 15556 resetResolvedTextAlignment(); 15557 resetResolvedPadding(); 15558 resetResolvedDrawables(); 15559 } 15560 15561 /** 15562 * @see #onScreenStateChanged(int) 15563 */ 15564 void dispatchScreenStateChanged(int screenState) { 15565 onScreenStateChanged(screenState); 15566 } 15567 15568 /** 15569 * This method is called whenever the state of the screen this view is 15570 * attached to changes. A state change will usually occurs when the screen 15571 * turns on or off (whether it happens automatically or the user does it 15572 * manually.) 15573 * 15574 * @param screenState The new state of the screen. Can be either 15575 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 15576 */ 15577 public void onScreenStateChanged(int screenState) { 15578 } 15579 15580 /** 15581 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 15582 */ 15583 private boolean hasRtlSupport() { 15584 return mContext.getApplicationInfo().hasRtlSupport(); 15585 } 15586 15587 /** 15588 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 15589 * RTL not supported) 15590 */ 15591 private boolean isRtlCompatibilityMode() { 15592 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 15593 return targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport(); 15594 } 15595 15596 /** 15597 * @return true if RTL properties need resolution. 15598 * 15599 */ 15600 private boolean needRtlPropertiesResolution() { 15601 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 15602 } 15603 15604 /** 15605 * Called when any RTL property (layout direction or text direction or text alignment) has 15606 * been changed. 15607 * 15608 * Subclasses need to override this method to take care of cached information that depends on the 15609 * resolved layout direction, or to inform child views that inherit their layout direction. 15610 * 15611 * The default implementation does nothing. 15612 * 15613 * @param layoutDirection the direction of the layout 15614 * 15615 * @see #LAYOUT_DIRECTION_LTR 15616 * @see #LAYOUT_DIRECTION_RTL 15617 */ 15618 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 15619 } 15620 15621 /** 15622 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 15623 * that the parent directionality can and will be resolved before its children. 15624 * 15625 * @return true if resolution has been done, false otherwise. 15626 * 15627 * @hide 15628 */ 15629 public boolean resolveLayoutDirection() { 15630 // Clear any previous layout direction resolution 15631 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15632 15633 if (hasRtlSupport()) { 15634 // Set resolved depending on layout direction 15635 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 15636 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 15637 case LAYOUT_DIRECTION_INHERIT: 15638 // We cannot resolve yet. LTR is by default and let the resolution happen again 15639 // later to get the correct resolved value 15640 if (!canResolveLayoutDirection()) return false; 15641 15642 // Parent has not yet resolved, LTR is still the default 15643 try { 15644 if (!mParent.isLayoutDirectionResolved()) return false; 15645 15646 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15647 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15648 } 15649 } catch (AbstractMethodError e) { 15650 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15651 " does not fully implement ViewParent", e); 15652 } 15653 break; 15654 case LAYOUT_DIRECTION_RTL: 15655 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15656 break; 15657 case LAYOUT_DIRECTION_LOCALE: 15658 if((LAYOUT_DIRECTION_RTL == 15659 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 15660 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15661 } 15662 break; 15663 default: 15664 // Nothing to do, LTR by default 15665 } 15666 } 15667 15668 // Set to resolved 15669 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 15670 return true; 15671 } 15672 15673 /** 15674 * Check if layout direction resolution can be done. 15675 * 15676 * @return true if layout direction resolution can be done otherwise return false. 15677 */ 15678 public boolean canResolveLayoutDirection() { 15679 switch (getRawLayoutDirection()) { 15680 case LAYOUT_DIRECTION_INHERIT: 15681 if (mParent != null) { 15682 try { 15683 return mParent.canResolveLayoutDirection(); 15684 } catch (AbstractMethodError e) { 15685 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15686 " does not fully implement ViewParent", e); 15687 } 15688 } 15689 return false; 15690 15691 default: 15692 return true; 15693 } 15694 } 15695 15696 /** 15697 * Reset the resolved layout direction. Layout direction will be resolved during a call to 15698 * {@link #onMeasure(int, int)}. 15699 * 15700 * @hide 15701 */ 15702 public void resetResolvedLayoutDirection() { 15703 // Reset the current resolved bits 15704 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15705 } 15706 15707 /** 15708 * @return true if the layout direction is inherited. 15709 * 15710 * @hide 15711 */ 15712 public boolean isLayoutDirectionInherited() { 15713 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 15714 } 15715 15716 /** 15717 * @return true if layout direction has been resolved. 15718 */ 15719 public boolean isLayoutDirectionResolved() { 15720 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 15721 } 15722 15723 /** 15724 * Return if padding has been resolved 15725 * 15726 * @hide 15727 */ 15728 boolean isPaddingResolved() { 15729 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 15730 } 15731 15732 /** 15733 * Resolves padding depending on layout direction, if applicable, and 15734 * recomputes internal padding values to adjust for scroll bars. 15735 * 15736 * @hide 15737 */ 15738 public void resolvePadding() { 15739 final int resolvedLayoutDirection = getLayoutDirection(); 15740 15741 if (!isRtlCompatibilityMode()) { 15742 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 15743 // If start / end padding are defined, they will be resolved (hence overriding) to 15744 // left / right or right / left depending on the resolved layout direction. 15745 // If start / end padding are not defined, use the left / right ones. 15746 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 15747 Rect padding = sThreadLocal.get(); 15748 if (padding == null) { 15749 padding = new Rect(); 15750 sThreadLocal.set(padding); 15751 } 15752 mBackground.getPadding(padding); 15753 if (!mLeftPaddingDefined) { 15754 mUserPaddingLeftInitial = padding.left; 15755 } 15756 if (!mRightPaddingDefined) { 15757 mUserPaddingRightInitial = padding.right; 15758 } 15759 } 15760 switch (resolvedLayoutDirection) { 15761 case LAYOUT_DIRECTION_RTL: 15762 if (mUserPaddingStart != UNDEFINED_PADDING) { 15763 mUserPaddingRight = mUserPaddingStart; 15764 } else { 15765 mUserPaddingRight = mUserPaddingRightInitial; 15766 } 15767 if (mUserPaddingEnd != UNDEFINED_PADDING) { 15768 mUserPaddingLeft = mUserPaddingEnd; 15769 } else { 15770 mUserPaddingLeft = mUserPaddingLeftInitial; 15771 } 15772 break; 15773 case LAYOUT_DIRECTION_LTR: 15774 default: 15775 if (mUserPaddingStart != UNDEFINED_PADDING) { 15776 mUserPaddingLeft = mUserPaddingStart; 15777 } else { 15778 mUserPaddingLeft = mUserPaddingLeftInitial; 15779 } 15780 if (mUserPaddingEnd != UNDEFINED_PADDING) { 15781 mUserPaddingRight = mUserPaddingEnd; 15782 } else { 15783 mUserPaddingRight = mUserPaddingRightInitial; 15784 } 15785 } 15786 15787 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 15788 } 15789 15790 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 15791 onRtlPropertiesChanged(resolvedLayoutDirection); 15792 15793 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 15794 } 15795 15796 /** 15797 * Reset the resolved layout direction. 15798 * 15799 * @hide 15800 */ 15801 public void resetResolvedPadding() { 15802 resetResolvedPaddingInternal(); 15803 } 15804 15805 /** 15806 * Used when we only want to reset *this* view's padding and not trigger overrides 15807 * in ViewGroup that reset children too. 15808 */ 15809 void resetResolvedPaddingInternal() { 15810 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 15811 } 15812 15813 /** 15814 * This is called when the view is detached from a window. At this point it 15815 * no longer has a surface for drawing. 15816 * 15817 * @see #onAttachedToWindow() 15818 */ 15819 @CallSuper 15820 protected void onDetachedFromWindow() { 15821 } 15822 15823 /** 15824 * This is a framework-internal mirror of onDetachedFromWindow() that's called 15825 * after onDetachedFromWindow(). 15826 * 15827 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 15828 * The super method should be called at the end of the overridden method to ensure 15829 * subclasses are destroyed first 15830 * 15831 * @hide 15832 */ 15833 @CallSuper 15834 protected void onDetachedFromWindowInternal() { 15835 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 15836 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15837 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 15838 15839 removeUnsetPressCallback(); 15840 removeLongPressCallback(); 15841 removePerformClickCallback(); 15842 removeSendViewScrolledAccessibilityEventCallback(); 15843 stopNestedScroll(); 15844 15845 // Anything that started animating right before detach should already 15846 // be in its final state when re-attached. 15847 jumpDrawablesToCurrentState(); 15848 15849 destroyDrawingCache(); 15850 15851 cleanupDraw(); 15852 mCurrentAnimation = null; 15853 15854 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 15855 hideTooltip(); 15856 } 15857 } 15858 15859 private void cleanupDraw() { 15860 resetDisplayList(); 15861 if (mAttachInfo != null) { 15862 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 15863 } 15864 } 15865 15866 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 15867 } 15868 15869 /** 15870 * @return The number of times this view has been attached to a window 15871 */ 15872 protected int getWindowAttachCount() { 15873 return mWindowAttachCount; 15874 } 15875 15876 /** 15877 * Retrieve a unique token identifying the window this view is attached to. 15878 * @return Return the window's token for use in 15879 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 15880 */ 15881 public IBinder getWindowToken() { 15882 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 15883 } 15884 15885 /** 15886 * Retrieve the {@link WindowId} for the window this view is 15887 * currently attached to. 15888 */ 15889 public WindowId getWindowId() { 15890 if (mAttachInfo == null) { 15891 return null; 15892 } 15893 if (mAttachInfo.mWindowId == null) { 15894 try { 15895 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 15896 mAttachInfo.mWindowToken); 15897 mAttachInfo.mWindowId = new WindowId( 15898 mAttachInfo.mIWindowId); 15899 } catch (RemoteException e) { 15900 } 15901 } 15902 return mAttachInfo.mWindowId; 15903 } 15904 15905 /** 15906 * Retrieve a unique token identifying the top-level "real" window of 15907 * the window that this view is attached to. That is, this is like 15908 * {@link #getWindowToken}, except if the window this view in is a panel 15909 * window (attached to another containing window), then the token of 15910 * the containing window is returned instead. 15911 * 15912 * @return Returns the associated window token, either 15913 * {@link #getWindowToken()} or the containing window's token. 15914 */ 15915 public IBinder getApplicationWindowToken() { 15916 AttachInfo ai = mAttachInfo; 15917 if (ai != null) { 15918 IBinder appWindowToken = ai.mPanelParentWindowToken; 15919 if (appWindowToken == null) { 15920 appWindowToken = ai.mWindowToken; 15921 } 15922 return appWindowToken; 15923 } 15924 return null; 15925 } 15926 15927 /** 15928 * Gets the logical display to which the view's window has been attached. 15929 * 15930 * @return The logical display, or null if the view is not currently attached to a window. 15931 */ 15932 public Display getDisplay() { 15933 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 15934 } 15935 15936 /** 15937 * Retrieve private session object this view hierarchy is using to 15938 * communicate with the window manager. 15939 * @return the session object to communicate with the window manager 15940 */ 15941 /*package*/ IWindowSession getWindowSession() { 15942 return mAttachInfo != null ? mAttachInfo.mSession : null; 15943 } 15944 15945 /** 15946 * Return the visibility value of the least visible component passed. 15947 */ 15948 int combineVisibility(int vis1, int vis2) { 15949 // This works because VISIBLE < INVISIBLE < GONE. 15950 return Math.max(vis1, vis2); 15951 } 15952 15953 /** 15954 * @param info the {@link android.view.View.AttachInfo} to associated with 15955 * this view 15956 */ 15957 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 15958 mAttachInfo = info; 15959 if (mOverlay != null) { 15960 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 15961 } 15962 mWindowAttachCount++; 15963 // We will need to evaluate the drawable state at least once. 15964 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 15965 if (mFloatingTreeObserver != null) { 15966 info.mTreeObserver.merge(mFloatingTreeObserver); 15967 mFloatingTreeObserver = null; 15968 } 15969 15970 registerPendingFrameMetricsObservers(); 15971 15972 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 15973 mAttachInfo.mScrollContainers.add(this); 15974 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 15975 } 15976 // Transfer all pending runnables. 15977 if (mRunQueue != null) { 15978 mRunQueue.executeActions(info.mHandler); 15979 mRunQueue = null; 15980 } 15981 performCollectViewAttributes(mAttachInfo, visibility); 15982 onAttachedToWindow(); 15983 15984 ListenerInfo li = mListenerInfo; 15985 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 15986 li != null ? li.mOnAttachStateChangeListeners : null; 15987 if (listeners != null && listeners.size() > 0) { 15988 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 15989 // perform the dispatching. The iterator is a safe guard against listeners that 15990 // could mutate the list by calling the various add/remove methods. This prevents 15991 // the array from being modified while we iterate it. 15992 for (OnAttachStateChangeListener listener : listeners) { 15993 listener.onViewAttachedToWindow(this); 15994 } 15995 } 15996 15997 int vis = info.mWindowVisibility; 15998 if (vis != GONE) { 15999 onWindowVisibilityChanged(vis); 16000 if (isShown()) { 16001 // Calling onVisibilityAggregated directly here since the subtree will also 16002 // receive dispatchAttachedToWindow and this same call 16003 onVisibilityAggregated(vis == VISIBLE); 16004 } 16005 } 16006 16007 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 16008 // As all views in the subtree will already receive dispatchAttachedToWindow 16009 // traversing the subtree again here is not desired. 16010 onVisibilityChanged(this, visibility); 16011 16012 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 16013 // If nobody has evaluated the drawable state yet, then do it now. 16014 refreshDrawableState(); 16015 } 16016 needGlobalAttributesUpdate(false); 16017 } 16018 16019 void dispatchDetachedFromWindow() { 16020 AttachInfo info = mAttachInfo; 16021 if (info != null) { 16022 int vis = info.mWindowVisibility; 16023 if (vis != GONE) { 16024 onWindowVisibilityChanged(GONE); 16025 if (isShown()) { 16026 // Invoking onVisibilityAggregated directly here since the subtree 16027 // will also receive detached from window 16028 onVisibilityAggregated(false); 16029 } 16030 } 16031 } 16032 16033 onDetachedFromWindow(); 16034 onDetachedFromWindowInternal(); 16035 16036 InputMethodManager imm = InputMethodManager.peekInstance(); 16037 if (imm != null) { 16038 imm.onViewDetachedFromWindow(this); 16039 } 16040 16041 ListenerInfo li = mListenerInfo; 16042 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 16043 li != null ? li.mOnAttachStateChangeListeners : null; 16044 if (listeners != null && listeners.size() > 0) { 16045 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 16046 // perform the dispatching. The iterator is a safe guard against listeners that 16047 // could mutate the list by calling the various add/remove methods. This prevents 16048 // the array from being modified while we iterate it. 16049 for (OnAttachStateChangeListener listener : listeners) { 16050 listener.onViewDetachedFromWindow(this); 16051 } 16052 } 16053 16054 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 16055 mAttachInfo.mScrollContainers.remove(this); 16056 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 16057 } 16058 16059 mAttachInfo = null; 16060 if (mOverlay != null) { 16061 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 16062 } 16063 } 16064 16065 /** 16066 * Cancel any deferred high-level input events that were previously posted to the event queue. 16067 * 16068 * <p>Many views post high-level events such as click handlers to the event queue 16069 * to run deferred in order to preserve a desired user experience - clearing visible 16070 * pressed states before executing, etc. This method will abort any events of this nature 16071 * that are currently in flight.</p> 16072 * 16073 * <p>Custom views that generate their own high-level deferred input events should override 16074 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 16075 * 16076 * <p>This will also cancel pending input events for any child views.</p> 16077 * 16078 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 16079 * This will not impact newer events posted after this call that may occur as a result of 16080 * lower-level input events still waiting in the queue. If you are trying to prevent 16081 * double-submitted events for the duration of some sort of asynchronous transaction 16082 * you should also take other steps to protect against unexpected double inputs e.g. calling 16083 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 16084 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 16085 */ 16086 public final void cancelPendingInputEvents() { 16087 dispatchCancelPendingInputEvents(); 16088 } 16089 16090 /** 16091 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 16092 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 16093 */ 16094 void dispatchCancelPendingInputEvents() { 16095 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 16096 onCancelPendingInputEvents(); 16097 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 16098 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 16099 " did not call through to super.onCancelPendingInputEvents()"); 16100 } 16101 } 16102 16103 /** 16104 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 16105 * a parent view. 16106 * 16107 * <p>This method is responsible for removing any pending high-level input events that were 16108 * posted to the event queue to run later. Custom view classes that post their own deferred 16109 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 16110 * {@link android.os.Handler} should override this method, call 16111 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 16112 * </p> 16113 */ 16114 public void onCancelPendingInputEvents() { 16115 removePerformClickCallback(); 16116 cancelLongPress(); 16117 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 16118 } 16119 16120 /** 16121 * Store this view hierarchy's frozen state into the given container. 16122 * 16123 * @param container The SparseArray in which to save the view's state. 16124 * 16125 * @see #restoreHierarchyState(android.util.SparseArray) 16126 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16127 * @see #onSaveInstanceState() 16128 */ 16129 public void saveHierarchyState(SparseArray<Parcelable> container) { 16130 dispatchSaveInstanceState(container); 16131 } 16132 16133 /** 16134 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 16135 * this view and its children. May be overridden to modify how freezing happens to a 16136 * view's children; for example, some views may want to not store state for their children. 16137 * 16138 * @param container The SparseArray in which to save the view's state. 16139 * 16140 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16141 * @see #saveHierarchyState(android.util.SparseArray) 16142 * @see #onSaveInstanceState() 16143 */ 16144 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 16145 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 16146 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 16147 Parcelable state = onSaveInstanceState(); 16148 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 16149 throw new IllegalStateException( 16150 "Derived class did not call super.onSaveInstanceState()"); 16151 } 16152 if (state != null) { 16153 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 16154 // + ": " + state); 16155 container.put(mID, state); 16156 } 16157 } 16158 } 16159 16160 /** 16161 * Hook allowing a view to generate a representation of its internal state 16162 * that can later be used to create a new instance with that same state. 16163 * This state should only contain information that is not persistent or can 16164 * not be reconstructed later. For example, you will never store your 16165 * current position on screen because that will be computed again when a 16166 * new instance of the view is placed in its view hierarchy. 16167 * <p> 16168 * Some examples of things you may store here: the current cursor position 16169 * in a text view (but usually not the text itself since that is stored in a 16170 * content provider or other persistent storage), the currently selected 16171 * item in a list view. 16172 * 16173 * @return Returns a Parcelable object containing the view's current dynamic 16174 * state, or null if there is nothing interesting to save. The 16175 * default implementation returns null. 16176 * @see #onRestoreInstanceState(android.os.Parcelable) 16177 * @see #saveHierarchyState(android.util.SparseArray) 16178 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16179 * @see #setSaveEnabled(boolean) 16180 */ 16181 @CallSuper 16182 protected Parcelable onSaveInstanceState() { 16183 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 16184 if (mStartActivityRequestWho != null) { 16185 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 16186 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 16187 return state; 16188 } 16189 return BaseSavedState.EMPTY_STATE; 16190 } 16191 16192 /** 16193 * Restore this view hierarchy's frozen state from the given container. 16194 * 16195 * @param container The SparseArray which holds previously frozen states. 16196 * 16197 * @see #saveHierarchyState(android.util.SparseArray) 16198 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16199 * @see #onRestoreInstanceState(android.os.Parcelable) 16200 */ 16201 public void restoreHierarchyState(SparseArray<Parcelable> container) { 16202 dispatchRestoreInstanceState(container); 16203 } 16204 16205 /** 16206 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 16207 * state for this view and its children. May be overridden to modify how restoring 16208 * happens to a view's children; for example, some views may want to not store state 16209 * for their children. 16210 * 16211 * @param container The SparseArray which holds previously saved state. 16212 * 16213 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16214 * @see #restoreHierarchyState(android.util.SparseArray) 16215 * @see #onRestoreInstanceState(android.os.Parcelable) 16216 */ 16217 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 16218 if (mID != NO_ID) { 16219 Parcelable state = container.get(mID); 16220 if (state != null) { 16221 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 16222 // + ": " + state); 16223 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 16224 onRestoreInstanceState(state); 16225 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 16226 throw new IllegalStateException( 16227 "Derived class did not call super.onRestoreInstanceState()"); 16228 } 16229 } 16230 } 16231 } 16232 16233 /** 16234 * Hook allowing a view to re-apply a representation of its internal state that had previously 16235 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 16236 * null state. 16237 * 16238 * @param state The frozen state that had previously been returned by 16239 * {@link #onSaveInstanceState}. 16240 * 16241 * @see #onSaveInstanceState() 16242 * @see #restoreHierarchyState(android.util.SparseArray) 16243 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16244 */ 16245 @CallSuper 16246 protected void onRestoreInstanceState(Parcelable state) { 16247 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 16248 if (state != null && !(state instanceof AbsSavedState)) { 16249 throw new IllegalArgumentException("Wrong state class, expecting View State but " 16250 + "received " + state.getClass().toString() + " instead. This usually happens " 16251 + "when two views of different type have the same id in the same hierarchy. " 16252 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 16253 + "other views do not use the same id."); 16254 } 16255 if (state != null && state instanceof BaseSavedState) { 16256 mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved; 16257 } 16258 } 16259 16260 /** 16261 * <p>Return the time at which the drawing of the view hierarchy started.</p> 16262 * 16263 * @return the drawing start time in milliseconds 16264 */ 16265 public long getDrawingTime() { 16266 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 16267 } 16268 16269 /** 16270 * <p>Enables or disables the duplication of the parent's state into this view. When 16271 * duplication is enabled, this view gets its drawable state from its parent rather 16272 * than from its own internal properties.</p> 16273 * 16274 * <p>Note: in the current implementation, setting this property to true after the 16275 * view was added to a ViewGroup might have no effect at all. This property should 16276 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 16277 * 16278 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 16279 * property is enabled, an exception will be thrown.</p> 16280 * 16281 * <p>Note: if the child view uses and updates additional states which are unknown to the 16282 * parent, these states should not be affected by this method.</p> 16283 * 16284 * @param enabled True to enable duplication of the parent's drawable state, false 16285 * to disable it. 16286 * 16287 * @see #getDrawableState() 16288 * @see #isDuplicateParentStateEnabled() 16289 */ 16290 public void setDuplicateParentStateEnabled(boolean enabled) { 16291 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 16292 } 16293 16294 /** 16295 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 16296 * 16297 * @return True if this view's drawable state is duplicated from the parent, 16298 * false otherwise 16299 * 16300 * @see #getDrawableState() 16301 * @see #setDuplicateParentStateEnabled(boolean) 16302 */ 16303 public boolean isDuplicateParentStateEnabled() { 16304 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 16305 } 16306 16307 /** 16308 * <p>Specifies the type of layer backing this view. The layer can be 16309 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16310 * {@link #LAYER_TYPE_HARDWARE}.</p> 16311 * 16312 * <p>A layer is associated with an optional {@link android.graphics.Paint} 16313 * instance that controls how the layer is composed on screen. The following 16314 * properties of the paint are taken into account when composing the layer:</p> 16315 * <ul> 16316 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 16317 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 16318 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 16319 * </ul> 16320 * 16321 * <p>If this view has an alpha value set to < 1.0 by calling 16322 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 16323 * by this view's alpha value.</p> 16324 * 16325 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 16326 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 16327 * for more information on when and how to use layers.</p> 16328 * 16329 * @param layerType The type of layer to use with this view, must be one of 16330 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16331 * {@link #LAYER_TYPE_HARDWARE} 16332 * @param paint The paint used to compose the layer. This argument is optional 16333 * and can be null. It is ignored when the layer type is 16334 * {@link #LAYER_TYPE_NONE} 16335 * 16336 * @see #getLayerType() 16337 * @see #LAYER_TYPE_NONE 16338 * @see #LAYER_TYPE_SOFTWARE 16339 * @see #LAYER_TYPE_HARDWARE 16340 * @see #setAlpha(float) 16341 * 16342 * @attr ref android.R.styleable#View_layerType 16343 */ 16344 public void setLayerType(int layerType, @Nullable Paint paint) { 16345 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 16346 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 16347 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 16348 } 16349 16350 boolean typeChanged = mRenderNode.setLayerType(layerType); 16351 16352 if (!typeChanged) { 16353 setLayerPaint(paint); 16354 return; 16355 } 16356 16357 if (layerType != LAYER_TYPE_SOFTWARE) { 16358 // Destroy any previous software drawing cache if present 16359 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 16360 // drawing cache created in View#draw when drawing to a SW canvas. 16361 destroyDrawingCache(); 16362 } 16363 16364 mLayerType = layerType; 16365 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 16366 mRenderNode.setLayerPaint(mLayerPaint); 16367 16368 // draw() behaves differently if we are on a layer, so we need to 16369 // invalidate() here 16370 invalidateParentCaches(); 16371 invalidate(true); 16372 } 16373 16374 /** 16375 * Updates the {@link Paint} object used with the current layer (used only if the current 16376 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 16377 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 16378 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 16379 * ensure that the view gets redrawn immediately. 16380 * 16381 * <p>A layer is associated with an optional {@link android.graphics.Paint} 16382 * instance that controls how the layer is composed on screen. The following 16383 * properties of the paint are taken into account when composing the layer:</p> 16384 * <ul> 16385 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 16386 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 16387 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 16388 * </ul> 16389 * 16390 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 16391 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 16392 * 16393 * @param paint The paint used to compose the layer. This argument is optional 16394 * and can be null. It is ignored when the layer type is 16395 * {@link #LAYER_TYPE_NONE} 16396 * 16397 * @see #setLayerType(int, android.graphics.Paint) 16398 */ 16399 public void setLayerPaint(@Nullable Paint paint) { 16400 int layerType = getLayerType(); 16401 if (layerType != LAYER_TYPE_NONE) { 16402 mLayerPaint = paint; 16403 if (layerType == LAYER_TYPE_HARDWARE) { 16404 if (mRenderNode.setLayerPaint(paint)) { 16405 invalidateViewProperty(false, false); 16406 } 16407 } else { 16408 invalidate(); 16409 } 16410 } 16411 } 16412 16413 /** 16414 * Indicates what type of layer is currently associated with this view. By default 16415 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 16416 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 16417 * for more information on the different types of layers. 16418 * 16419 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16420 * {@link #LAYER_TYPE_HARDWARE} 16421 * 16422 * @see #setLayerType(int, android.graphics.Paint) 16423 * @see #buildLayer() 16424 * @see #LAYER_TYPE_NONE 16425 * @see #LAYER_TYPE_SOFTWARE 16426 * @see #LAYER_TYPE_HARDWARE 16427 */ 16428 public int getLayerType() { 16429 return mLayerType; 16430 } 16431 16432 /** 16433 * Forces this view's layer to be created and this view to be rendered 16434 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 16435 * invoking this method will have no effect. 16436 * 16437 * This method can for instance be used to render a view into its layer before 16438 * starting an animation. If this view is complex, rendering into the layer 16439 * before starting the animation will avoid skipping frames. 16440 * 16441 * @throws IllegalStateException If this view is not attached to a window 16442 * 16443 * @see #setLayerType(int, android.graphics.Paint) 16444 */ 16445 public void buildLayer() { 16446 if (mLayerType == LAYER_TYPE_NONE) return; 16447 16448 final AttachInfo attachInfo = mAttachInfo; 16449 if (attachInfo == null) { 16450 throw new IllegalStateException("This view must be attached to a window first"); 16451 } 16452 16453 if (getWidth() == 0 || getHeight() == 0) { 16454 return; 16455 } 16456 16457 switch (mLayerType) { 16458 case LAYER_TYPE_HARDWARE: 16459 updateDisplayListIfDirty(); 16460 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 16461 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 16462 } 16463 break; 16464 case LAYER_TYPE_SOFTWARE: 16465 buildDrawingCache(true); 16466 break; 16467 } 16468 } 16469 16470 /** 16471 * Destroys all hardware rendering resources. This method is invoked 16472 * when the system needs to reclaim resources. Upon execution of this 16473 * method, you should free any OpenGL resources created by the view. 16474 * 16475 * Note: you <strong>must</strong> call 16476 * <code>super.destroyHardwareResources()</code> when overriding 16477 * this method. 16478 * 16479 * @hide 16480 */ 16481 @CallSuper 16482 protected void destroyHardwareResources() { 16483 // Although the Layer will be destroyed by RenderNode, we want to release 16484 // the staging display list, which is also a signal to RenderNode that it's 16485 // safe to free its copy of the display list as it knows that we will 16486 // push an updated DisplayList if we try to draw again 16487 resetDisplayList(); 16488 } 16489 16490 /** 16491 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 16492 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 16493 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 16494 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 16495 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 16496 * null.</p> 16497 * 16498 * <p>Enabling the drawing cache is similar to 16499 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 16500 * acceleration is turned off. When hardware acceleration is turned on, enabling the 16501 * drawing cache has no effect on rendering because the system uses a different mechanism 16502 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 16503 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 16504 * for information on how to enable software and hardware layers.</p> 16505 * 16506 * <p>This API can be used to manually generate 16507 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 16508 * {@link #getDrawingCache()}.</p> 16509 * 16510 * @param enabled true to enable the drawing cache, false otherwise 16511 * 16512 * @see #isDrawingCacheEnabled() 16513 * @see #getDrawingCache() 16514 * @see #buildDrawingCache() 16515 * @see #setLayerType(int, android.graphics.Paint) 16516 */ 16517 public void setDrawingCacheEnabled(boolean enabled) { 16518 mCachingFailed = false; 16519 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 16520 } 16521 16522 /** 16523 * <p>Indicates whether the drawing cache is enabled for this view.</p> 16524 * 16525 * @return true if the drawing cache is enabled 16526 * 16527 * @see #setDrawingCacheEnabled(boolean) 16528 * @see #getDrawingCache() 16529 */ 16530 @ViewDebug.ExportedProperty(category = "drawing") 16531 public boolean isDrawingCacheEnabled() { 16532 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 16533 } 16534 16535 /** 16536 * Debugging utility which recursively outputs the dirty state of a view and its 16537 * descendants. 16538 * 16539 * @hide 16540 */ 16541 @SuppressWarnings({"UnusedDeclaration"}) 16542 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 16543 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 16544 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 16545 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 16546 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 16547 if (clear) { 16548 mPrivateFlags &= clearMask; 16549 } 16550 if (this instanceof ViewGroup) { 16551 ViewGroup parent = (ViewGroup) this; 16552 final int count = parent.getChildCount(); 16553 for (int i = 0; i < count; i++) { 16554 final View child = parent.getChildAt(i); 16555 child.outputDirtyFlags(indent + " ", clear, clearMask); 16556 } 16557 } 16558 } 16559 16560 /** 16561 * This method is used by ViewGroup to cause its children to restore or recreate their 16562 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 16563 * to recreate its own display list, which would happen if it went through the normal 16564 * draw/dispatchDraw mechanisms. 16565 * 16566 * @hide 16567 */ 16568 protected void dispatchGetDisplayList() {} 16569 16570 /** 16571 * A view that is not attached or hardware accelerated cannot create a display list. 16572 * This method checks these conditions and returns the appropriate result. 16573 * 16574 * @return true if view has the ability to create a display list, false otherwise. 16575 * 16576 * @hide 16577 */ 16578 public boolean canHaveDisplayList() { 16579 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 16580 } 16581 16582 /** 16583 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 16584 * @hide 16585 */ 16586 @NonNull 16587 public RenderNode updateDisplayListIfDirty() { 16588 final RenderNode renderNode = mRenderNode; 16589 if (!canHaveDisplayList()) { 16590 // can't populate RenderNode, don't try 16591 return renderNode; 16592 } 16593 16594 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 16595 || !renderNode.isValid() 16596 || (mRecreateDisplayList)) { 16597 // Don't need to recreate the display list, just need to tell our 16598 // children to restore/recreate theirs 16599 if (renderNode.isValid() 16600 && !mRecreateDisplayList) { 16601 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16602 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16603 dispatchGetDisplayList(); 16604 16605 return renderNode; // no work needed 16606 } 16607 16608 // If we got here, we're recreating it. Mark it as such to ensure that 16609 // we copy in child display lists into ours in drawChild() 16610 mRecreateDisplayList = true; 16611 16612 int width = mRight - mLeft; 16613 int height = mBottom - mTop; 16614 int layerType = getLayerType(); 16615 16616 final DisplayListCanvas canvas = renderNode.start(width, height); 16617 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 16618 16619 try { 16620 if (layerType == LAYER_TYPE_SOFTWARE) { 16621 buildDrawingCache(true); 16622 Bitmap cache = getDrawingCache(true); 16623 if (cache != null) { 16624 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 16625 } 16626 } else { 16627 computeScroll(); 16628 16629 canvas.translate(-mScrollX, -mScrollY); 16630 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16631 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16632 16633 // Fast path for layouts with no backgrounds 16634 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16635 dispatchDraw(canvas); 16636 if (mOverlay != null && !mOverlay.isEmpty()) { 16637 mOverlay.getOverlayView().draw(canvas); 16638 } 16639 if (debugDraw()) { 16640 debugDrawFocus(canvas); 16641 } 16642 } else { 16643 draw(canvas); 16644 } 16645 } 16646 } finally { 16647 renderNode.end(canvas); 16648 setDisplayListProperties(renderNode); 16649 } 16650 } else { 16651 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16652 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16653 } 16654 return renderNode; 16655 } 16656 16657 private void resetDisplayList() { 16658 if (mRenderNode.isValid()) { 16659 mRenderNode.discardDisplayList(); 16660 } 16661 16662 if (mBackgroundRenderNode != null && mBackgroundRenderNode.isValid()) { 16663 mBackgroundRenderNode.discardDisplayList(); 16664 } 16665 } 16666 16667 /** 16668 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 16669 * 16670 * @return A non-scaled bitmap representing this view or null if cache is disabled. 16671 * 16672 * @see #getDrawingCache(boolean) 16673 */ 16674 public Bitmap getDrawingCache() { 16675 return getDrawingCache(false); 16676 } 16677 16678 /** 16679 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 16680 * is null when caching is disabled. If caching is enabled and the cache is not ready, 16681 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 16682 * draw from the cache when the cache is enabled. To benefit from the cache, you must 16683 * request the drawing cache by calling this method and draw it on screen if the 16684 * returned bitmap is not null.</p> 16685 * 16686 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16687 * this method will create a bitmap of the same size as this view. Because this bitmap 16688 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16689 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16690 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16691 * size than the view. This implies that your application must be able to handle this 16692 * size.</p> 16693 * 16694 * @param autoScale Indicates whether the generated bitmap should be scaled based on 16695 * the current density of the screen when the application is in compatibility 16696 * mode. 16697 * 16698 * @return A bitmap representing this view or null if cache is disabled. 16699 * 16700 * @see #setDrawingCacheEnabled(boolean) 16701 * @see #isDrawingCacheEnabled() 16702 * @see #buildDrawingCache(boolean) 16703 * @see #destroyDrawingCache() 16704 */ 16705 public Bitmap getDrawingCache(boolean autoScale) { 16706 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 16707 return null; 16708 } 16709 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 16710 buildDrawingCache(autoScale); 16711 } 16712 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 16713 } 16714 16715 /** 16716 * <p>Frees the resources used by the drawing cache. If you call 16717 * {@link #buildDrawingCache()} manually without calling 16718 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16719 * should cleanup the cache with this method afterwards.</p> 16720 * 16721 * @see #setDrawingCacheEnabled(boolean) 16722 * @see #buildDrawingCache() 16723 * @see #getDrawingCache() 16724 */ 16725 public void destroyDrawingCache() { 16726 if (mDrawingCache != null) { 16727 mDrawingCache.recycle(); 16728 mDrawingCache = null; 16729 } 16730 if (mUnscaledDrawingCache != null) { 16731 mUnscaledDrawingCache.recycle(); 16732 mUnscaledDrawingCache = null; 16733 } 16734 } 16735 16736 /** 16737 * Setting a solid background color for the drawing cache's bitmaps will improve 16738 * performance and memory usage. Note, though that this should only be used if this 16739 * view will always be drawn on top of a solid color. 16740 * 16741 * @param color The background color to use for the drawing cache's bitmap 16742 * 16743 * @see #setDrawingCacheEnabled(boolean) 16744 * @see #buildDrawingCache() 16745 * @see #getDrawingCache() 16746 */ 16747 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 16748 if (color != mDrawingCacheBackgroundColor) { 16749 mDrawingCacheBackgroundColor = color; 16750 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16751 } 16752 } 16753 16754 /** 16755 * @see #setDrawingCacheBackgroundColor(int) 16756 * 16757 * @return The background color to used for the drawing cache's bitmap 16758 */ 16759 @ColorInt 16760 public int getDrawingCacheBackgroundColor() { 16761 return mDrawingCacheBackgroundColor; 16762 } 16763 16764 /** 16765 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 16766 * 16767 * @see #buildDrawingCache(boolean) 16768 */ 16769 public void buildDrawingCache() { 16770 buildDrawingCache(false); 16771 } 16772 16773 /** 16774 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 16775 * 16776 * <p>If you call {@link #buildDrawingCache()} manually without calling 16777 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16778 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 16779 * 16780 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16781 * this method will create a bitmap of the same size as this view. Because this bitmap 16782 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16783 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16784 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16785 * size than the view. This implies that your application must be able to handle this 16786 * size.</p> 16787 * 16788 * <p>You should avoid calling this method when hardware acceleration is enabled. If 16789 * you do not need the drawing cache bitmap, calling this method will increase memory 16790 * usage and cause the view to be rendered in software once, thus negatively impacting 16791 * performance.</p> 16792 * 16793 * @see #getDrawingCache() 16794 * @see #destroyDrawingCache() 16795 */ 16796 public void buildDrawingCache(boolean autoScale) { 16797 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 16798 mDrawingCache == null : mUnscaledDrawingCache == null)) { 16799 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 16800 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 16801 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 16802 } 16803 try { 16804 buildDrawingCacheImpl(autoScale); 16805 } finally { 16806 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 16807 } 16808 } 16809 } 16810 16811 /** 16812 * private, internal implementation of buildDrawingCache, used to enable tracing 16813 */ 16814 private void buildDrawingCacheImpl(boolean autoScale) { 16815 mCachingFailed = false; 16816 16817 int width = mRight - mLeft; 16818 int height = mBottom - mTop; 16819 16820 final AttachInfo attachInfo = mAttachInfo; 16821 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 16822 16823 if (autoScale && scalingRequired) { 16824 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 16825 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 16826 } 16827 16828 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 16829 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 16830 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 16831 16832 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 16833 final long drawingCacheSize = 16834 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 16835 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 16836 if (width > 0 && height > 0) { 16837 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 16838 + " too large to fit into a software layer (or drawing cache), needs " 16839 + projectedBitmapSize + " bytes, only " 16840 + drawingCacheSize + " available"); 16841 } 16842 destroyDrawingCache(); 16843 mCachingFailed = true; 16844 return; 16845 } 16846 16847 boolean clear = true; 16848 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 16849 16850 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 16851 Bitmap.Config quality; 16852 if (!opaque) { 16853 // Never pick ARGB_4444 because it looks awful 16854 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 16855 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 16856 case DRAWING_CACHE_QUALITY_AUTO: 16857 case DRAWING_CACHE_QUALITY_LOW: 16858 case DRAWING_CACHE_QUALITY_HIGH: 16859 default: 16860 quality = Bitmap.Config.ARGB_8888; 16861 break; 16862 } 16863 } else { 16864 // Optimization for translucent windows 16865 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 16866 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 16867 } 16868 16869 // Try to cleanup memory 16870 if (bitmap != null) bitmap.recycle(); 16871 16872 try { 16873 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 16874 width, height, quality); 16875 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 16876 if (autoScale) { 16877 mDrawingCache = bitmap; 16878 } else { 16879 mUnscaledDrawingCache = bitmap; 16880 } 16881 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 16882 } catch (OutOfMemoryError e) { 16883 // If there is not enough memory to create the bitmap cache, just 16884 // ignore the issue as bitmap caches are not required to draw the 16885 // view hierarchy 16886 if (autoScale) { 16887 mDrawingCache = null; 16888 } else { 16889 mUnscaledDrawingCache = null; 16890 } 16891 mCachingFailed = true; 16892 return; 16893 } 16894 16895 clear = drawingCacheBackgroundColor != 0; 16896 } 16897 16898 Canvas canvas; 16899 if (attachInfo != null) { 16900 canvas = attachInfo.mCanvas; 16901 if (canvas == null) { 16902 canvas = new Canvas(); 16903 } 16904 canvas.setBitmap(bitmap); 16905 // Temporarily clobber the cached Canvas in case one of our children 16906 // is also using a drawing cache. Without this, the children would 16907 // steal the canvas by attaching their own bitmap to it and bad, bad 16908 // thing would happen (invisible views, corrupted drawings, etc.) 16909 attachInfo.mCanvas = null; 16910 } else { 16911 // This case should hopefully never or seldom happen 16912 canvas = new Canvas(bitmap); 16913 } 16914 16915 if (clear) { 16916 bitmap.eraseColor(drawingCacheBackgroundColor); 16917 } 16918 16919 computeScroll(); 16920 final int restoreCount = canvas.save(); 16921 16922 if (autoScale && scalingRequired) { 16923 final float scale = attachInfo.mApplicationScale; 16924 canvas.scale(scale, scale); 16925 } 16926 16927 canvas.translate(-mScrollX, -mScrollY); 16928 16929 mPrivateFlags |= PFLAG_DRAWN; 16930 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 16931 mLayerType != LAYER_TYPE_NONE) { 16932 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 16933 } 16934 16935 // Fast path for layouts with no backgrounds 16936 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16937 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16938 dispatchDraw(canvas); 16939 if (mOverlay != null && !mOverlay.isEmpty()) { 16940 mOverlay.getOverlayView().draw(canvas); 16941 } 16942 } else { 16943 draw(canvas); 16944 } 16945 16946 canvas.restoreToCount(restoreCount); 16947 canvas.setBitmap(null); 16948 16949 if (attachInfo != null) { 16950 // Restore the cached Canvas for our siblings 16951 attachInfo.mCanvas = canvas; 16952 } 16953 } 16954 16955 /** 16956 * Create a snapshot of the view into a bitmap. We should probably make 16957 * some form of this public, but should think about the API. 16958 * 16959 * @hide 16960 */ 16961 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 16962 int width = mRight - mLeft; 16963 int height = mBottom - mTop; 16964 16965 final AttachInfo attachInfo = mAttachInfo; 16966 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 16967 width = (int) ((width * scale) + 0.5f); 16968 height = (int) ((height * scale) + 0.5f); 16969 16970 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 16971 width > 0 ? width : 1, height > 0 ? height : 1, quality); 16972 if (bitmap == null) { 16973 throw new OutOfMemoryError(); 16974 } 16975 16976 Resources resources = getResources(); 16977 if (resources != null) { 16978 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 16979 } 16980 16981 Canvas canvas; 16982 if (attachInfo != null) { 16983 canvas = attachInfo.mCanvas; 16984 if (canvas == null) { 16985 canvas = new Canvas(); 16986 } 16987 canvas.setBitmap(bitmap); 16988 // Temporarily clobber the cached Canvas in case one of our children 16989 // is also using a drawing cache. Without this, the children would 16990 // steal the canvas by attaching their own bitmap to it and bad, bad 16991 // things would happen (invisible views, corrupted drawings, etc.) 16992 attachInfo.mCanvas = null; 16993 } else { 16994 // This case should hopefully never or seldom happen 16995 canvas = new Canvas(bitmap); 16996 } 16997 16998 if ((backgroundColor & 0xff000000) != 0) { 16999 bitmap.eraseColor(backgroundColor); 17000 } 17001 17002 computeScroll(); 17003 final int restoreCount = canvas.save(); 17004 canvas.scale(scale, scale); 17005 canvas.translate(-mScrollX, -mScrollY); 17006 17007 // Temporarily remove the dirty mask 17008 int flags = mPrivateFlags; 17009 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17010 17011 // Fast path for layouts with no backgrounds 17012 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17013 dispatchDraw(canvas); 17014 if (mOverlay != null && !mOverlay.isEmpty()) { 17015 mOverlay.getOverlayView().draw(canvas); 17016 } 17017 } else { 17018 draw(canvas); 17019 } 17020 17021 mPrivateFlags = flags; 17022 17023 canvas.restoreToCount(restoreCount); 17024 canvas.setBitmap(null); 17025 17026 if (attachInfo != null) { 17027 // Restore the cached Canvas for our siblings 17028 attachInfo.mCanvas = canvas; 17029 } 17030 17031 return bitmap; 17032 } 17033 17034 /** 17035 * Indicates whether this View is currently in edit mode. A View is usually 17036 * in edit mode when displayed within a developer tool. For instance, if 17037 * this View is being drawn by a visual user interface builder, this method 17038 * should return true. 17039 * 17040 * Subclasses should check the return value of this method to provide 17041 * different behaviors if their normal behavior might interfere with the 17042 * host environment. For instance: the class spawns a thread in its 17043 * constructor, the drawing code relies on device-specific features, etc. 17044 * 17045 * This method is usually checked in the drawing code of custom widgets. 17046 * 17047 * @return True if this View is in edit mode, false otherwise. 17048 */ 17049 public boolean isInEditMode() { 17050 return false; 17051 } 17052 17053 /** 17054 * If the View draws content inside its padding and enables fading edges, 17055 * it needs to support padding offsets. Padding offsets are added to the 17056 * fading edges to extend the length of the fade so that it covers pixels 17057 * drawn inside the padding. 17058 * 17059 * Subclasses of this class should override this method if they need 17060 * to draw content inside the padding. 17061 * 17062 * @return True if padding offset must be applied, false otherwise. 17063 * 17064 * @see #getLeftPaddingOffset() 17065 * @see #getRightPaddingOffset() 17066 * @see #getTopPaddingOffset() 17067 * @see #getBottomPaddingOffset() 17068 * 17069 * @since CURRENT 17070 */ 17071 protected boolean isPaddingOffsetRequired() { 17072 return false; 17073 } 17074 17075 /** 17076 * Amount by which to extend the left fading region. Called only when 17077 * {@link #isPaddingOffsetRequired()} returns true. 17078 * 17079 * @return The left padding offset in pixels. 17080 * 17081 * @see #isPaddingOffsetRequired() 17082 * 17083 * @since CURRENT 17084 */ 17085 protected int getLeftPaddingOffset() { 17086 return 0; 17087 } 17088 17089 /** 17090 * Amount by which to extend the right fading region. Called only when 17091 * {@link #isPaddingOffsetRequired()} returns true. 17092 * 17093 * @return The right padding offset in pixels. 17094 * 17095 * @see #isPaddingOffsetRequired() 17096 * 17097 * @since CURRENT 17098 */ 17099 protected int getRightPaddingOffset() { 17100 return 0; 17101 } 17102 17103 /** 17104 * Amount by which to extend the top fading region. Called only when 17105 * {@link #isPaddingOffsetRequired()} returns true. 17106 * 17107 * @return The top padding offset in pixels. 17108 * 17109 * @see #isPaddingOffsetRequired() 17110 * 17111 * @since CURRENT 17112 */ 17113 protected int getTopPaddingOffset() { 17114 return 0; 17115 } 17116 17117 /** 17118 * Amount by which to extend the bottom fading region. Called only when 17119 * {@link #isPaddingOffsetRequired()} returns true. 17120 * 17121 * @return The bottom padding offset in pixels. 17122 * 17123 * @see #isPaddingOffsetRequired() 17124 * 17125 * @since CURRENT 17126 */ 17127 protected int getBottomPaddingOffset() { 17128 return 0; 17129 } 17130 17131 /** 17132 * @hide 17133 * @param offsetRequired 17134 */ 17135 protected int getFadeTop(boolean offsetRequired) { 17136 int top = mPaddingTop; 17137 if (offsetRequired) top += getTopPaddingOffset(); 17138 return top; 17139 } 17140 17141 /** 17142 * @hide 17143 * @param offsetRequired 17144 */ 17145 protected int getFadeHeight(boolean offsetRequired) { 17146 int padding = mPaddingTop; 17147 if (offsetRequired) padding += getTopPaddingOffset(); 17148 return mBottom - mTop - mPaddingBottom - padding; 17149 } 17150 17151 /** 17152 * <p>Indicates whether this view is attached to a hardware accelerated 17153 * window or not.</p> 17154 * 17155 * <p>Even if this method returns true, it does not mean that every call 17156 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 17157 * accelerated {@link android.graphics.Canvas}. For instance, if this view 17158 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 17159 * window is hardware accelerated, 17160 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 17161 * return false, and this method will return true.</p> 17162 * 17163 * @return True if the view is attached to a window and the window is 17164 * hardware accelerated; false in any other case. 17165 */ 17166 @ViewDebug.ExportedProperty(category = "drawing") 17167 public boolean isHardwareAccelerated() { 17168 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 17169 } 17170 17171 /** 17172 * Sets a rectangular area on this view to which the view will be clipped 17173 * when it is drawn. Setting the value to null will remove the clip bounds 17174 * and the view will draw normally, using its full bounds. 17175 * 17176 * @param clipBounds The rectangular area, in the local coordinates of 17177 * this view, to which future drawing operations will be clipped. 17178 */ 17179 public void setClipBounds(Rect clipBounds) { 17180 if (clipBounds == mClipBounds 17181 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 17182 return; 17183 } 17184 if (clipBounds != null) { 17185 if (mClipBounds == null) { 17186 mClipBounds = new Rect(clipBounds); 17187 } else { 17188 mClipBounds.set(clipBounds); 17189 } 17190 } else { 17191 mClipBounds = null; 17192 } 17193 mRenderNode.setClipBounds(mClipBounds); 17194 invalidateViewProperty(false, false); 17195 } 17196 17197 /** 17198 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 17199 * 17200 * @return A copy of the current clip bounds if clip bounds are set, 17201 * otherwise null. 17202 */ 17203 public Rect getClipBounds() { 17204 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 17205 } 17206 17207 17208 /** 17209 * Populates an output rectangle with the clip bounds of the view, 17210 * returning {@code true} if successful or {@code false} if the view's 17211 * clip bounds are {@code null}. 17212 * 17213 * @param outRect rectangle in which to place the clip bounds of the view 17214 * @return {@code true} if successful or {@code false} if the view's 17215 * clip bounds are {@code null} 17216 */ 17217 public boolean getClipBounds(Rect outRect) { 17218 if (mClipBounds != null) { 17219 outRect.set(mClipBounds); 17220 return true; 17221 } 17222 return false; 17223 } 17224 17225 /** 17226 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 17227 * case of an active Animation being run on the view. 17228 */ 17229 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 17230 Animation a, boolean scalingRequired) { 17231 Transformation invalidationTransform; 17232 final int flags = parent.mGroupFlags; 17233 final boolean initialized = a.isInitialized(); 17234 if (!initialized) { 17235 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 17236 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 17237 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 17238 onAnimationStart(); 17239 } 17240 17241 final Transformation t = parent.getChildTransformation(); 17242 boolean more = a.getTransformation(drawingTime, t, 1f); 17243 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 17244 if (parent.mInvalidationTransformation == null) { 17245 parent.mInvalidationTransformation = new Transformation(); 17246 } 17247 invalidationTransform = parent.mInvalidationTransformation; 17248 a.getTransformation(drawingTime, invalidationTransform, 1f); 17249 } else { 17250 invalidationTransform = t; 17251 } 17252 17253 if (more) { 17254 if (!a.willChangeBounds()) { 17255 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 17256 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 17257 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 17258 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 17259 // The child need to draw an animation, potentially offscreen, so 17260 // make sure we do not cancel invalidate requests 17261 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17262 parent.invalidate(mLeft, mTop, mRight, mBottom); 17263 } 17264 } else { 17265 if (parent.mInvalidateRegion == null) { 17266 parent.mInvalidateRegion = new RectF(); 17267 } 17268 final RectF region = parent.mInvalidateRegion; 17269 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 17270 invalidationTransform); 17271 17272 // The child need to draw an animation, potentially offscreen, so 17273 // make sure we do not cancel invalidate requests 17274 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17275 17276 final int left = mLeft + (int) region.left; 17277 final int top = mTop + (int) region.top; 17278 parent.invalidate(left, top, left + (int) (region.width() + .5f), 17279 top + (int) (region.height() + .5f)); 17280 } 17281 } 17282 return more; 17283 } 17284 17285 /** 17286 * This method is called by getDisplayList() when a display list is recorded for a View. 17287 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 17288 */ 17289 void setDisplayListProperties(RenderNode renderNode) { 17290 if (renderNode != null) { 17291 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 17292 renderNode.setClipToBounds(mParent instanceof ViewGroup 17293 && ((ViewGroup) mParent).getClipChildren()); 17294 17295 float alpha = 1; 17296 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 17297 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17298 ViewGroup parentVG = (ViewGroup) mParent; 17299 final Transformation t = parentVG.getChildTransformation(); 17300 if (parentVG.getChildStaticTransformation(this, t)) { 17301 final int transformType = t.getTransformationType(); 17302 if (transformType != Transformation.TYPE_IDENTITY) { 17303 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 17304 alpha = t.getAlpha(); 17305 } 17306 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 17307 renderNode.setStaticMatrix(t.getMatrix()); 17308 } 17309 } 17310 } 17311 } 17312 if (mTransformationInfo != null) { 17313 alpha *= getFinalAlpha(); 17314 if (alpha < 1) { 17315 final int multipliedAlpha = (int) (255 * alpha); 17316 if (onSetAlpha(multipliedAlpha)) { 17317 alpha = 1; 17318 } 17319 } 17320 renderNode.setAlpha(alpha); 17321 } else if (alpha < 1) { 17322 renderNode.setAlpha(alpha); 17323 } 17324 } 17325 } 17326 17327 /** 17328 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 17329 * 17330 * This is where the View specializes rendering behavior based on layer type, 17331 * and hardware acceleration. 17332 */ 17333 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 17334 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 17335 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 17336 * 17337 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 17338 * HW accelerated, it can't handle drawing RenderNodes. 17339 */ 17340 boolean drawingWithRenderNode = mAttachInfo != null 17341 && mAttachInfo.mHardwareAccelerated 17342 && hardwareAcceleratedCanvas; 17343 17344 boolean more = false; 17345 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 17346 final int parentFlags = parent.mGroupFlags; 17347 17348 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 17349 parent.getChildTransformation().clear(); 17350 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17351 } 17352 17353 Transformation transformToApply = null; 17354 boolean concatMatrix = false; 17355 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 17356 final Animation a = getAnimation(); 17357 if (a != null) { 17358 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 17359 concatMatrix = a.willChangeTransformationMatrix(); 17360 if (concatMatrix) { 17361 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17362 } 17363 transformToApply = parent.getChildTransformation(); 17364 } else { 17365 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 17366 // No longer animating: clear out old animation matrix 17367 mRenderNode.setAnimationMatrix(null); 17368 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17369 } 17370 if (!drawingWithRenderNode 17371 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17372 final Transformation t = parent.getChildTransformation(); 17373 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 17374 if (hasTransform) { 17375 final int transformType = t.getTransformationType(); 17376 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 17377 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 17378 } 17379 } 17380 } 17381 17382 concatMatrix |= !childHasIdentityMatrix; 17383 17384 // Sets the flag as early as possible to allow draw() implementations 17385 // to call invalidate() successfully when doing animations 17386 mPrivateFlags |= PFLAG_DRAWN; 17387 17388 if (!concatMatrix && 17389 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 17390 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 17391 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 17392 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 17393 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 17394 return more; 17395 } 17396 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 17397 17398 if (hardwareAcceleratedCanvas) { 17399 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 17400 // retain the flag's value temporarily in the mRecreateDisplayList flag 17401 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 17402 mPrivateFlags &= ~PFLAG_INVALIDATED; 17403 } 17404 17405 RenderNode renderNode = null; 17406 Bitmap cache = null; 17407 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 17408 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 17409 if (layerType != LAYER_TYPE_NONE) { 17410 // If not drawing with RenderNode, treat HW layers as SW 17411 layerType = LAYER_TYPE_SOFTWARE; 17412 buildDrawingCache(true); 17413 } 17414 cache = getDrawingCache(true); 17415 } 17416 17417 if (drawingWithRenderNode) { 17418 // Delay getting the display list until animation-driven alpha values are 17419 // set up and possibly passed on to the view 17420 renderNode = updateDisplayListIfDirty(); 17421 if (!renderNode.isValid()) { 17422 // Uncommon, but possible. If a view is removed from the hierarchy during the call 17423 // to getDisplayList(), the display list will be marked invalid and we should not 17424 // try to use it again. 17425 renderNode = null; 17426 drawingWithRenderNode = false; 17427 } 17428 } 17429 17430 int sx = 0; 17431 int sy = 0; 17432 if (!drawingWithRenderNode) { 17433 computeScroll(); 17434 sx = mScrollX; 17435 sy = mScrollY; 17436 } 17437 17438 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 17439 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 17440 17441 int restoreTo = -1; 17442 if (!drawingWithRenderNode || transformToApply != null) { 17443 restoreTo = canvas.save(); 17444 } 17445 if (offsetForScroll) { 17446 canvas.translate(mLeft - sx, mTop - sy); 17447 } else { 17448 if (!drawingWithRenderNode) { 17449 canvas.translate(mLeft, mTop); 17450 } 17451 if (scalingRequired) { 17452 if (drawingWithRenderNode) { 17453 // TODO: Might not need this if we put everything inside the DL 17454 restoreTo = canvas.save(); 17455 } 17456 // mAttachInfo cannot be null, otherwise scalingRequired == false 17457 final float scale = 1.0f / mAttachInfo.mApplicationScale; 17458 canvas.scale(scale, scale); 17459 } 17460 } 17461 17462 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 17463 if (transformToApply != null 17464 || alpha < 1 17465 || !hasIdentityMatrix() 17466 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17467 if (transformToApply != null || !childHasIdentityMatrix) { 17468 int transX = 0; 17469 int transY = 0; 17470 17471 if (offsetForScroll) { 17472 transX = -sx; 17473 transY = -sy; 17474 } 17475 17476 if (transformToApply != null) { 17477 if (concatMatrix) { 17478 if (drawingWithRenderNode) { 17479 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 17480 } else { 17481 // Undo the scroll translation, apply the transformation matrix, 17482 // then redo the scroll translate to get the correct result. 17483 canvas.translate(-transX, -transY); 17484 canvas.concat(transformToApply.getMatrix()); 17485 canvas.translate(transX, transY); 17486 } 17487 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17488 } 17489 17490 float transformAlpha = transformToApply.getAlpha(); 17491 if (transformAlpha < 1) { 17492 alpha *= transformAlpha; 17493 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17494 } 17495 } 17496 17497 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 17498 canvas.translate(-transX, -transY); 17499 canvas.concat(getMatrix()); 17500 canvas.translate(transX, transY); 17501 } 17502 } 17503 17504 // Deal with alpha if it is or used to be <1 17505 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17506 if (alpha < 1) { 17507 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17508 } else { 17509 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17510 } 17511 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17512 if (!drawingWithDrawingCache) { 17513 final int multipliedAlpha = (int) (255 * alpha); 17514 if (!onSetAlpha(multipliedAlpha)) { 17515 if (drawingWithRenderNode) { 17516 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 17517 } else if (layerType == LAYER_TYPE_NONE) { 17518 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 17519 multipliedAlpha); 17520 } 17521 } else { 17522 // Alpha is handled by the child directly, clobber the layer's alpha 17523 mPrivateFlags |= PFLAG_ALPHA_SET; 17524 } 17525 } 17526 } 17527 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17528 onSetAlpha(255); 17529 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17530 } 17531 17532 if (!drawingWithRenderNode) { 17533 // apply clips directly, since RenderNode won't do it for this draw 17534 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 17535 if (offsetForScroll) { 17536 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 17537 } else { 17538 if (!scalingRequired || cache == null) { 17539 canvas.clipRect(0, 0, getWidth(), getHeight()); 17540 } else { 17541 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 17542 } 17543 } 17544 } 17545 17546 if (mClipBounds != null) { 17547 // clip bounds ignore scroll 17548 canvas.clipRect(mClipBounds); 17549 } 17550 } 17551 17552 if (!drawingWithDrawingCache) { 17553 if (drawingWithRenderNode) { 17554 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17555 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 17556 } else { 17557 // Fast path for layouts with no backgrounds 17558 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17559 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17560 dispatchDraw(canvas); 17561 } else { 17562 draw(canvas); 17563 } 17564 } 17565 } else if (cache != null) { 17566 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17567 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 17568 // no layer paint, use temporary paint to draw bitmap 17569 Paint cachePaint = parent.mCachePaint; 17570 if (cachePaint == null) { 17571 cachePaint = new Paint(); 17572 cachePaint.setDither(false); 17573 parent.mCachePaint = cachePaint; 17574 } 17575 cachePaint.setAlpha((int) (alpha * 255)); 17576 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 17577 } else { 17578 // use layer paint to draw the bitmap, merging the two alphas, but also restore 17579 int layerPaintAlpha = mLayerPaint.getAlpha(); 17580 if (alpha < 1) { 17581 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 17582 } 17583 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 17584 if (alpha < 1) { 17585 mLayerPaint.setAlpha(layerPaintAlpha); 17586 } 17587 } 17588 } 17589 17590 if (restoreTo >= 0) { 17591 canvas.restoreToCount(restoreTo); 17592 } 17593 17594 if (a != null && !more) { 17595 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 17596 onSetAlpha(255); 17597 } 17598 parent.finishAnimatingView(this, a); 17599 } 17600 17601 if (more && hardwareAcceleratedCanvas) { 17602 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17603 // alpha animations should cause the child to recreate its display list 17604 invalidate(true); 17605 } 17606 } 17607 17608 mRecreateDisplayList = false; 17609 17610 return more; 17611 } 17612 17613 static Paint getDebugPaint() { 17614 if (sDebugPaint == null) { 17615 sDebugPaint = new Paint(); 17616 sDebugPaint.setAntiAlias(false); 17617 } 17618 return sDebugPaint; 17619 } 17620 17621 final int dipsToPixels(int dips) { 17622 float scale = getContext().getResources().getDisplayMetrics().density; 17623 return (int) (dips * scale + 0.5f); 17624 } 17625 17626 final private void debugDrawFocus(Canvas canvas) { 17627 if (isFocused()) { 17628 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 17629 final int l = mScrollX; 17630 final int r = l + mRight - mLeft; 17631 final int t = mScrollY; 17632 final int b = t + mBottom - mTop; 17633 17634 final Paint paint = getDebugPaint(); 17635 paint.setColor(DEBUG_CORNERS_COLOR); 17636 17637 // Draw squares in corners. 17638 paint.setStyle(Paint.Style.FILL); 17639 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 17640 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 17641 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 17642 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 17643 17644 // Draw big X across the view. 17645 paint.setStyle(Paint.Style.STROKE); 17646 canvas.drawLine(l, t, r, b, paint); 17647 canvas.drawLine(l, b, r, t, paint); 17648 } 17649 } 17650 17651 /** 17652 * Manually render this view (and all of its children) to the given Canvas. 17653 * The view must have already done a full layout before this function is 17654 * called. When implementing a view, implement 17655 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 17656 * If you do need to override this method, call the superclass version. 17657 * 17658 * @param canvas The Canvas to which the View is rendered. 17659 */ 17660 @CallSuper 17661 public void draw(Canvas canvas) { 17662 final int privateFlags = mPrivateFlags; 17663 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 17664 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 17665 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 17666 17667 /* 17668 * Draw traversal performs several drawing steps which must be executed 17669 * in the appropriate order: 17670 * 17671 * 1. Draw the background 17672 * 2. If necessary, save the canvas' layers to prepare for fading 17673 * 3. Draw view's content 17674 * 4. Draw children 17675 * 5. If necessary, draw the fading edges and restore layers 17676 * 6. Draw decorations (scrollbars for instance) 17677 */ 17678 17679 // Step 1, draw the background, if needed 17680 int saveCount; 17681 17682 if (!dirtyOpaque) { 17683 drawBackground(canvas); 17684 } 17685 17686 // skip step 2 & 5 if possible (common case) 17687 final int viewFlags = mViewFlags; 17688 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 17689 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 17690 if (!verticalEdges && !horizontalEdges) { 17691 // Step 3, draw the content 17692 if (!dirtyOpaque) onDraw(canvas); 17693 17694 // Step 4, draw the children 17695 dispatchDraw(canvas); 17696 17697 // Overlay is part of the content and draws beneath Foreground 17698 if (mOverlay != null && !mOverlay.isEmpty()) { 17699 mOverlay.getOverlayView().dispatchDraw(canvas); 17700 } 17701 17702 // Step 6, draw decorations (foreground, scrollbars) 17703 onDrawForeground(canvas); 17704 17705 if (debugDraw()) { 17706 debugDrawFocus(canvas); 17707 } 17708 17709 // we're done... 17710 return; 17711 } 17712 17713 /* 17714 * Here we do the full fledged routine... 17715 * (this is an uncommon case where speed matters less, 17716 * this is why we repeat some of the tests that have been 17717 * done above) 17718 */ 17719 17720 boolean drawTop = false; 17721 boolean drawBottom = false; 17722 boolean drawLeft = false; 17723 boolean drawRight = false; 17724 17725 float topFadeStrength = 0.0f; 17726 float bottomFadeStrength = 0.0f; 17727 float leftFadeStrength = 0.0f; 17728 float rightFadeStrength = 0.0f; 17729 17730 // Step 2, save the canvas' layers 17731 int paddingLeft = mPaddingLeft; 17732 17733 final boolean offsetRequired = isPaddingOffsetRequired(); 17734 if (offsetRequired) { 17735 paddingLeft += getLeftPaddingOffset(); 17736 } 17737 17738 int left = mScrollX + paddingLeft; 17739 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 17740 int top = mScrollY + getFadeTop(offsetRequired); 17741 int bottom = top + getFadeHeight(offsetRequired); 17742 17743 if (offsetRequired) { 17744 right += getRightPaddingOffset(); 17745 bottom += getBottomPaddingOffset(); 17746 } 17747 17748 final ScrollabilityCache scrollabilityCache = mScrollCache; 17749 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 17750 int length = (int) fadeHeight; 17751 17752 // clip the fade length if top and bottom fades overlap 17753 // overlapping fades produce odd-looking artifacts 17754 if (verticalEdges && (top + length > bottom - length)) { 17755 length = (bottom - top) / 2; 17756 } 17757 17758 // also clip horizontal fades if necessary 17759 if (horizontalEdges && (left + length > right - length)) { 17760 length = (right - left) / 2; 17761 } 17762 17763 if (verticalEdges) { 17764 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 17765 drawTop = topFadeStrength * fadeHeight > 1.0f; 17766 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 17767 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 17768 } 17769 17770 if (horizontalEdges) { 17771 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 17772 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 17773 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 17774 drawRight = rightFadeStrength * fadeHeight > 1.0f; 17775 } 17776 17777 saveCount = canvas.getSaveCount(); 17778 17779 int solidColor = getSolidColor(); 17780 if (solidColor == 0) { 17781 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 17782 17783 if (drawTop) { 17784 canvas.saveLayer(left, top, right, top + length, null, flags); 17785 } 17786 17787 if (drawBottom) { 17788 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 17789 } 17790 17791 if (drawLeft) { 17792 canvas.saveLayer(left, top, left + length, bottom, null, flags); 17793 } 17794 17795 if (drawRight) { 17796 canvas.saveLayer(right - length, top, right, bottom, null, flags); 17797 } 17798 } else { 17799 scrollabilityCache.setFadeColor(solidColor); 17800 } 17801 17802 // Step 3, draw the content 17803 if (!dirtyOpaque) onDraw(canvas); 17804 17805 // Step 4, draw the children 17806 dispatchDraw(canvas); 17807 17808 // Step 5, draw the fade effect and restore layers 17809 final Paint p = scrollabilityCache.paint; 17810 final Matrix matrix = scrollabilityCache.matrix; 17811 final Shader fade = scrollabilityCache.shader; 17812 17813 if (drawTop) { 17814 matrix.setScale(1, fadeHeight * topFadeStrength); 17815 matrix.postTranslate(left, top); 17816 fade.setLocalMatrix(matrix); 17817 p.setShader(fade); 17818 canvas.drawRect(left, top, right, top + length, p); 17819 } 17820 17821 if (drawBottom) { 17822 matrix.setScale(1, fadeHeight * bottomFadeStrength); 17823 matrix.postRotate(180); 17824 matrix.postTranslate(left, bottom); 17825 fade.setLocalMatrix(matrix); 17826 p.setShader(fade); 17827 canvas.drawRect(left, bottom - length, right, bottom, p); 17828 } 17829 17830 if (drawLeft) { 17831 matrix.setScale(1, fadeHeight * leftFadeStrength); 17832 matrix.postRotate(-90); 17833 matrix.postTranslate(left, top); 17834 fade.setLocalMatrix(matrix); 17835 p.setShader(fade); 17836 canvas.drawRect(left, top, left + length, bottom, p); 17837 } 17838 17839 if (drawRight) { 17840 matrix.setScale(1, fadeHeight * rightFadeStrength); 17841 matrix.postRotate(90); 17842 matrix.postTranslate(right, top); 17843 fade.setLocalMatrix(matrix); 17844 p.setShader(fade); 17845 canvas.drawRect(right - length, top, right, bottom, p); 17846 } 17847 17848 canvas.restoreToCount(saveCount); 17849 17850 // Overlay is part of the content and draws beneath Foreground 17851 if (mOverlay != null && !mOverlay.isEmpty()) { 17852 mOverlay.getOverlayView().dispatchDraw(canvas); 17853 } 17854 17855 // Step 6, draw decorations (foreground, scrollbars) 17856 onDrawForeground(canvas); 17857 17858 if (debugDraw()) { 17859 debugDrawFocus(canvas); 17860 } 17861 } 17862 17863 /** 17864 * Draws the background onto the specified canvas. 17865 * 17866 * @param canvas Canvas on which to draw the background 17867 */ 17868 private void drawBackground(Canvas canvas) { 17869 final Drawable background = mBackground; 17870 if (background == null) { 17871 return; 17872 } 17873 17874 setBackgroundBounds(); 17875 17876 // Attempt to use a display list if requested. 17877 if (canvas.isHardwareAccelerated() && mAttachInfo != null 17878 && mAttachInfo.mThreadedRenderer != null) { 17879 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 17880 17881 final RenderNode renderNode = mBackgroundRenderNode; 17882 if (renderNode != null && renderNode.isValid()) { 17883 setBackgroundRenderNodeProperties(renderNode); 17884 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 17885 return; 17886 } 17887 } 17888 17889 final int scrollX = mScrollX; 17890 final int scrollY = mScrollY; 17891 if ((scrollX | scrollY) == 0) { 17892 background.draw(canvas); 17893 } else { 17894 canvas.translate(scrollX, scrollY); 17895 background.draw(canvas); 17896 canvas.translate(-scrollX, -scrollY); 17897 } 17898 } 17899 17900 /** 17901 * Sets the correct background bounds and rebuilds the outline, if needed. 17902 * <p/> 17903 * This is called by LayoutLib. 17904 */ 17905 void setBackgroundBounds() { 17906 if (mBackgroundSizeChanged && mBackground != null) { 17907 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 17908 mBackgroundSizeChanged = false; 17909 rebuildOutline(); 17910 } 17911 } 17912 17913 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 17914 renderNode.setTranslationX(mScrollX); 17915 renderNode.setTranslationY(mScrollY); 17916 } 17917 17918 /** 17919 * Creates a new display list or updates the existing display list for the 17920 * specified Drawable. 17921 * 17922 * @param drawable Drawable for which to create a display list 17923 * @param renderNode Existing RenderNode, or {@code null} 17924 * @return A valid display list for the specified drawable 17925 */ 17926 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 17927 if (renderNode == null) { 17928 renderNode = RenderNode.create(drawable.getClass().getName(), this); 17929 } 17930 17931 final Rect bounds = drawable.getBounds(); 17932 final int width = bounds.width(); 17933 final int height = bounds.height(); 17934 final DisplayListCanvas canvas = renderNode.start(width, height); 17935 17936 // Reverse left/top translation done by drawable canvas, which will 17937 // instead be applied by rendernode's LTRB bounds below. This way, the 17938 // drawable's bounds match with its rendernode bounds and its content 17939 // will lie within those bounds in the rendernode tree. 17940 canvas.translate(-bounds.left, -bounds.top); 17941 17942 try { 17943 drawable.draw(canvas); 17944 } finally { 17945 renderNode.end(canvas); 17946 } 17947 17948 // Set up drawable properties that are view-independent. 17949 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 17950 renderNode.setProjectBackwards(drawable.isProjected()); 17951 renderNode.setProjectionReceiver(true); 17952 renderNode.setClipToBounds(false); 17953 return renderNode; 17954 } 17955 17956 /** 17957 * Returns the overlay for this view, creating it if it does not yet exist. 17958 * Adding drawables to the overlay will cause them to be displayed whenever 17959 * the view itself is redrawn. Objects in the overlay should be actively 17960 * managed: remove them when they should not be displayed anymore. The 17961 * overlay will always have the same size as its host view. 17962 * 17963 * <p>Note: Overlays do not currently work correctly with {@link 17964 * SurfaceView} or {@link TextureView}; contents in overlays for these 17965 * types of views may not display correctly.</p> 17966 * 17967 * @return The ViewOverlay object for this view. 17968 * @see ViewOverlay 17969 */ 17970 public ViewOverlay getOverlay() { 17971 if (mOverlay == null) { 17972 mOverlay = new ViewOverlay(mContext, this); 17973 } 17974 return mOverlay; 17975 } 17976 17977 /** 17978 * Override this if your view is known to always be drawn on top of a solid color background, 17979 * and needs to draw fading edges. Returning a non-zero color enables the view system to 17980 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 17981 * should be set to 0xFF. 17982 * 17983 * @see #setVerticalFadingEdgeEnabled(boolean) 17984 * @see #setHorizontalFadingEdgeEnabled(boolean) 17985 * 17986 * @return The known solid color background for this view, or 0 if the color may vary 17987 */ 17988 @ViewDebug.ExportedProperty(category = "drawing") 17989 @ColorInt 17990 public int getSolidColor() { 17991 return 0; 17992 } 17993 17994 /** 17995 * Build a human readable string representation of the specified view flags. 17996 * 17997 * @param flags the view flags to convert to a string 17998 * @return a String representing the supplied flags 17999 */ 18000 private static String printFlags(int flags) { 18001 String output = ""; 18002 int numFlags = 0; 18003 if ((flags & FOCUSABLE_MASK) == FOCUSABLE) { 18004 output += "TAKES_FOCUS"; 18005 numFlags++; 18006 } 18007 18008 switch (flags & VISIBILITY_MASK) { 18009 case INVISIBLE: 18010 if (numFlags > 0) { 18011 output += " "; 18012 } 18013 output += "INVISIBLE"; 18014 // USELESS HERE numFlags++; 18015 break; 18016 case GONE: 18017 if (numFlags > 0) { 18018 output += " "; 18019 } 18020 output += "GONE"; 18021 // USELESS HERE numFlags++; 18022 break; 18023 default: 18024 break; 18025 } 18026 return output; 18027 } 18028 18029 /** 18030 * Build a human readable string representation of the specified private 18031 * view flags. 18032 * 18033 * @param privateFlags the private view flags to convert to a string 18034 * @return a String representing the supplied flags 18035 */ 18036 private static String printPrivateFlags(int privateFlags) { 18037 String output = ""; 18038 int numFlags = 0; 18039 18040 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 18041 output += "WANTS_FOCUS"; 18042 numFlags++; 18043 } 18044 18045 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 18046 if (numFlags > 0) { 18047 output += " "; 18048 } 18049 output += "FOCUSED"; 18050 numFlags++; 18051 } 18052 18053 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 18054 if (numFlags > 0) { 18055 output += " "; 18056 } 18057 output += "SELECTED"; 18058 numFlags++; 18059 } 18060 18061 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 18062 if (numFlags > 0) { 18063 output += " "; 18064 } 18065 output += "IS_ROOT_NAMESPACE"; 18066 numFlags++; 18067 } 18068 18069 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 18070 if (numFlags > 0) { 18071 output += " "; 18072 } 18073 output += "HAS_BOUNDS"; 18074 numFlags++; 18075 } 18076 18077 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 18078 if (numFlags > 0) { 18079 output += " "; 18080 } 18081 output += "DRAWN"; 18082 // USELESS HERE numFlags++; 18083 } 18084 return output; 18085 } 18086 18087 /** 18088 * <p>Indicates whether or not this view's layout will be requested during 18089 * the next hierarchy layout pass.</p> 18090 * 18091 * @return true if the layout will be forced during next layout pass 18092 */ 18093 public boolean isLayoutRequested() { 18094 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 18095 } 18096 18097 /** 18098 * Return true if o is a ViewGroup that is laying out using optical bounds. 18099 * @hide 18100 */ 18101 public static boolean isLayoutModeOptical(Object o) { 18102 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 18103 } 18104 18105 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 18106 Insets parentInsets = mParent instanceof View ? 18107 ((View) mParent).getOpticalInsets() : Insets.NONE; 18108 Insets childInsets = getOpticalInsets(); 18109 return setFrame( 18110 left + parentInsets.left - childInsets.left, 18111 top + parentInsets.top - childInsets.top, 18112 right + parentInsets.left + childInsets.right, 18113 bottom + parentInsets.top + childInsets.bottom); 18114 } 18115 18116 /** 18117 * Assign a size and position to a view and all of its 18118 * descendants 18119 * 18120 * <p>This is the second phase of the layout mechanism. 18121 * (The first is measuring). In this phase, each parent calls 18122 * layout on all of its children to position them. 18123 * This is typically done using the child measurements 18124 * that were stored in the measure pass().</p> 18125 * 18126 * <p>Derived classes should not override this method. 18127 * Derived classes with children should override 18128 * onLayout. In that method, they should 18129 * call layout on each of their children.</p> 18130 * 18131 * @param l Left position, relative to parent 18132 * @param t Top position, relative to parent 18133 * @param r Right position, relative to parent 18134 * @param b Bottom position, relative to parent 18135 */ 18136 @SuppressWarnings({"unchecked"}) 18137 public void layout(int l, int t, int r, int b) { 18138 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 18139 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 18140 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 18141 } 18142 18143 int oldL = mLeft; 18144 int oldT = mTop; 18145 int oldB = mBottom; 18146 int oldR = mRight; 18147 18148 boolean changed = isLayoutModeOptical(mParent) ? 18149 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 18150 18151 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 18152 onLayout(changed, l, t, r, b); 18153 18154 if (shouldDrawRoundScrollbar()) { 18155 if(mRoundScrollbarRenderer == null) { 18156 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 18157 } 18158 } else { 18159 mRoundScrollbarRenderer = null; 18160 } 18161 18162 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 18163 18164 ListenerInfo li = mListenerInfo; 18165 if (li != null && li.mOnLayoutChangeListeners != null) { 18166 ArrayList<OnLayoutChangeListener> listenersCopy = 18167 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 18168 int numListeners = listenersCopy.size(); 18169 for (int i = 0; i < numListeners; ++i) { 18170 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 18171 } 18172 } 18173 } 18174 18175 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 18176 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 18177 } 18178 18179 /** 18180 * Called from layout when this view should 18181 * assign a size and position to each of its children. 18182 * 18183 * Derived classes with children should override 18184 * this method and call layout on each of 18185 * their children. 18186 * @param changed This is a new size or position for this view 18187 * @param left Left position, relative to parent 18188 * @param top Top position, relative to parent 18189 * @param right Right position, relative to parent 18190 * @param bottom Bottom position, relative to parent 18191 */ 18192 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 18193 } 18194 18195 /** 18196 * Assign a size and position to this view. 18197 * 18198 * This is called from layout. 18199 * 18200 * @param left Left position, relative to parent 18201 * @param top Top position, relative to parent 18202 * @param right Right position, relative to parent 18203 * @param bottom Bottom position, relative to parent 18204 * @return true if the new size and position are different than the 18205 * previous ones 18206 * {@hide} 18207 */ 18208 protected boolean setFrame(int left, int top, int right, int bottom) { 18209 boolean changed = false; 18210 18211 if (DBG) { 18212 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 18213 + right + "," + bottom + ")"); 18214 } 18215 18216 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 18217 changed = true; 18218 18219 // Remember our drawn bit 18220 int drawn = mPrivateFlags & PFLAG_DRAWN; 18221 18222 int oldWidth = mRight - mLeft; 18223 int oldHeight = mBottom - mTop; 18224 int newWidth = right - left; 18225 int newHeight = bottom - top; 18226 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 18227 18228 // Invalidate our old position 18229 invalidate(sizeChanged); 18230 18231 mLeft = left; 18232 mTop = top; 18233 mRight = right; 18234 mBottom = bottom; 18235 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 18236 18237 mPrivateFlags |= PFLAG_HAS_BOUNDS; 18238 18239 18240 if (sizeChanged) { 18241 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 18242 } 18243 18244 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 18245 // If we are visible, force the DRAWN bit to on so that 18246 // this invalidate will go through (at least to our parent). 18247 // This is because someone may have invalidated this view 18248 // before this call to setFrame came in, thereby clearing 18249 // the DRAWN bit. 18250 mPrivateFlags |= PFLAG_DRAWN; 18251 invalidate(sizeChanged); 18252 // parent display list may need to be recreated based on a change in the bounds 18253 // of any child 18254 invalidateParentCaches(); 18255 } 18256 18257 // Reset drawn bit to original value (invalidate turns it off) 18258 mPrivateFlags |= drawn; 18259 18260 mBackgroundSizeChanged = true; 18261 if (mForegroundInfo != null) { 18262 mForegroundInfo.mBoundsChanged = true; 18263 } 18264 18265 notifySubtreeAccessibilityStateChangedIfNeeded(); 18266 } 18267 return changed; 18268 } 18269 18270 /** 18271 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 18272 * @hide 18273 */ 18274 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 18275 setFrame(left, top, right, bottom); 18276 } 18277 18278 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 18279 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 18280 if (mOverlay != null) { 18281 mOverlay.getOverlayView().setRight(newWidth); 18282 mOverlay.getOverlayView().setBottom(newHeight); 18283 } 18284 rebuildOutline(); 18285 } 18286 18287 /** 18288 * Finalize inflating a view from XML. This is called as the last phase 18289 * of inflation, after all child views have been added. 18290 * 18291 * <p>Even if the subclass overrides onFinishInflate, they should always be 18292 * sure to call the super method, so that we get called. 18293 */ 18294 @CallSuper 18295 protected void onFinishInflate() { 18296 } 18297 18298 /** 18299 * Returns the resources associated with this view. 18300 * 18301 * @return Resources object. 18302 */ 18303 public Resources getResources() { 18304 return mResources; 18305 } 18306 18307 /** 18308 * Invalidates the specified Drawable. 18309 * 18310 * @param drawable the drawable to invalidate 18311 */ 18312 @Override 18313 public void invalidateDrawable(@NonNull Drawable drawable) { 18314 if (verifyDrawable(drawable)) { 18315 final Rect dirty = drawable.getDirtyBounds(); 18316 final int scrollX = mScrollX; 18317 final int scrollY = mScrollY; 18318 18319 invalidate(dirty.left + scrollX, dirty.top + scrollY, 18320 dirty.right + scrollX, dirty.bottom + scrollY); 18321 rebuildOutline(); 18322 } 18323 } 18324 18325 /** 18326 * Schedules an action on a drawable to occur at a specified time. 18327 * 18328 * @param who the recipient of the action 18329 * @param what the action to run on the drawable 18330 * @param when the time at which the action must occur. Uses the 18331 * {@link SystemClock#uptimeMillis} timebase. 18332 */ 18333 @Override 18334 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 18335 if (verifyDrawable(who) && what != null) { 18336 final long delay = when - SystemClock.uptimeMillis(); 18337 if (mAttachInfo != null) { 18338 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 18339 Choreographer.CALLBACK_ANIMATION, what, who, 18340 Choreographer.subtractFrameDelay(delay)); 18341 } else { 18342 // Postpone the runnable until we know 18343 // on which thread it needs to run. 18344 getRunQueue().postDelayed(what, delay); 18345 } 18346 } 18347 } 18348 18349 /** 18350 * Cancels a scheduled action on a drawable. 18351 * 18352 * @param who the recipient of the action 18353 * @param what the action to cancel 18354 */ 18355 @Override 18356 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 18357 if (verifyDrawable(who) && what != null) { 18358 if (mAttachInfo != null) { 18359 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18360 Choreographer.CALLBACK_ANIMATION, what, who); 18361 } 18362 getRunQueue().removeCallbacks(what); 18363 } 18364 } 18365 18366 /** 18367 * Unschedule any events associated with the given Drawable. This can be 18368 * used when selecting a new Drawable into a view, so that the previous 18369 * one is completely unscheduled. 18370 * 18371 * @param who The Drawable to unschedule. 18372 * 18373 * @see #drawableStateChanged 18374 */ 18375 public void unscheduleDrawable(Drawable who) { 18376 if (mAttachInfo != null && who != null) { 18377 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18378 Choreographer.CALLBACK_ANIMATION, null, who); 18379 } 18380 } 18381 18382 /** 18383 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 18384 * that the View directionality can and will be resolved before its Drawables. 18385 * 18386 * Will call {@link View#onResolveDrawables} when resolution is done. 18387 * 18388 * @hide 18389 */ 18390 protected void resolveDrawables() { 18391 // Drawables resolution may need to happen before resolving the layout direction (which is 18392 // done only during the measure() call). 18393 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 18394 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 18395 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 18396 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 18397 // direction to be resolved as its resolved value will be the same as its raw value. 18398 if (!isLayoutDirectionResolved() && 18399 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 18400 return; 18401 } 18402 18403 final int layoutDirection = isLayoutDirectionResolved() ? 18404 getLayoutDirection() : getRawLayoutDirection(); 18405 18406 if (mBackground != null) { 18407 mBackground.setLayoutDirection(layoutDirection); 18408 } 18409 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18410 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 18411 } 18412 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 18413 onResolveDrawables(layoutDirection); 18414 } 18415 18416 boolean areDrawablesResolved() { 18417 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 18418 } 18419 18420 /** 18421 * Called when layout direction has been resolved. 18422 * 18423 * The default implementation does nothing. 18424 * 18425 * @param layoutDirection The resolved layout direction. 18426 * 18427 * @see #LAYOUT_DIRECTION_LTR 18428 * @see #LAYOUT_DIRECTION_RTL 18429 * 18430 * @hide 18431 */ 18432 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 18433 } 18434 18435 /** 18436 * @hide 18437 */ 18438 protected void resetResolvedDrawables() { 18439 resetResolvedDrawablesInternal(); 18440 } 18441 18442 void resetResolvedDrawablesInternal() { 18443 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 18444 } 18445 18446 /** 18447 * If your view subclass is displaying its own Drawable objects, it should 18448 * override this function and return true for any Drawable it is 18449 * displaying. This allows animations for those drawables to be 18450 * scheduled. 18451 * 18452 * <p>Be sure to call through to the super class when overriding this 18453 * function. 18454 * 18455 * @param who The Drawable to verify. Return true if it is one you are 18456 * displaying, else return the result of calling through to the 18457 * super class. 18458 * 18459 * @return boolean If true than the Drawable is being displayed in the 18460 * view; else false and it is not allowed to animate. 18461 * 18462 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 18463 * @see #drawableStateChanged() 18464 */ 18465 @CallSuper 18466 protected boolean verifyDrawable(@NonNull Drawable who) { 18467 // Avoid verifying the scroll bar drawable so that we don't end up in 18468 // an invalidation loop. This effectively prevents the scroll bar 18469 // drawable from triggering invalidations and scheduling runnables. 18470 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); 18471 } 18472 18473 /** 18474 * This function is called whenever the state of the view changes in such 18475 * a way that it impacts the state of drawables being shown. 18476 * <p> 18477 * If the View has a StateListAnimator, it will also be called to run necessary state 18478 * change animations. 18479 * <p> 18480 * Be sure to call through to the superclass when overriding this function. 18481 * 18482 * @see Drawable#setState(int[]) 18483 */ 18484 @CallSuper 18485 protected void drawableStateChanged() { 18486 final int[] state = getDrawableState(); 18487 boolean changed = false; 18488 18489 final Drawable bg = mBackground; 18490 if (bg != null && bg.isStateful()) { 18491 changed |= bg.setState(state); 18492 } 18493 18494 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 18495 if (fg != null && fg.isStateful()) { 18496 changed |= fg.setState(state); 18497 } 18498 18499 if (mScrollCache != null) { 18500 final Drawable scrollBar = mScrollCache.scrollBar; 18501 if (scrollBar != null && scrollBar.isStateful()) { 18502 changed |= scrollBar.setState(state) 18503 && mScrollCache.state != ScrollabilityCache.OFF; 18504 } 18505 } 18506 18507 if (mStateListAnimator != null) { 18508 mStateListAnimator.setState(state); 18509 } 18510 18511 if (changed) { 18512 invalidate(); 18513 } 18514 } 18515 18516 /** 18517 * This function is called whenever the view hotspot changes and needs to 18518 * be propagated to drawables or child views managed by the view. 18519 * <p> 18520 * Dispatching to child views is handled by 18521 * {@link #dispatchDrawableHotspotChanged(float, float)}. 18522 * <p> 18523 * Be sure to call through to the superclass when overriding this function. 18524 * 18525 * @param x hotspot x coordinate 18526 * @param y hotspot y coordinate 18527 */ 18528 @CallSuper 18529 public void drawableHotspotChanged(float x, float y) { 18530 if (mBackground != null) { 18531 mBackground.setHotspot(x, y); 18532 } 18533 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18534 mForegroundInfo.mDrawable.setHotspot(x, y); 18535 } 18536 18537 dispatchDrawableHotspotChanged(x, y); 18538 } 18539 18540 /** 18541 * Dispatches drawableHotspotChanged to all of this View's children. 18542 * 18543 * @param x hotspot x coordinate 18544 * @param y hotspot y coordinate 18545 * @see #drawableHotspotChanged(float, float) 18546 */ 18547 public void dispatchDrawableHotspotChanged(float x, float y) { 18548 } 18549 18550 /** 18551 * Call this to force a view to update its drawable state. This will cause 18552 * drawableStateChanged to be called on this view. Views that are interested 18553 * in the new state should call getDrawableState. 18554 * 18555 * @see #drawableStateChanged 18556 * @see #getDrawableState 18557 */ 18558 public void refreshDrawableState() { 18559 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 18560 drawableStateChanged(); 18561 18562 ViewParent parent = mParent; 18563 if (parent != null) { 18564 parent.childDrawableStateChanged(this); 18565 } 18566 } 18567 18568 /** 18569 * Return an array of resource IDs of the drawable states representing the 18570 * current state of the view. 18571 * 18572 * @return The current drawable state 18573 * 18574 * @see Drawable#setState(int[]) 18575 * @see #drawableStateChanged() 18576 * @see #onCreateDrawableState(int) 18577 */ 18578 public final int[] getDrawableState() { 18579 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 18580 return mDrawableState; 18581 } else { 18582 mDrawableState = onCreateDrawableState(0); 18583 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 18584 return mDrawableState; 18585 } 18586 } 18587 18588 /** 18589 * Generate the new {@link android.graphics.drawable.Drawable} state for 18590 * this view. This is called by the view 18591 * system when the cached Drawable state is determined to be invalid. To 18592 * retrieve the current state, you should use {@link #getDrawableState}. 18593 * 18594 * @param extraSpace if non-zero, this is the number of extra entries you 18595 * would like in the returned array in which you can place your own 18596 * states. 18597 * 18598 * @return Returns an array holding the current {@link Drawable} state of 18599 * the view. 18600 * 18601 * @see #mergeDrawableStates(int[], int[]) 18602 */ 18603 protected int[] onCreateDrawableState(int extraSpace) { 18604 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 18605 mParent instanceof View) { 18606 return ((View) mParent).onCreateDrawableState(extraSpace); 18607 } 18608 18609 int[] drawableState; 18610 18611 int privateFlags = mPrivateFlags; 18612 18613 int viewStateIndex = 0; 18614 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 18615 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 18616 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 18617 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 18618 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 18619 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 18620 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 18621 ThreadedRenderer.isAvailable()) { 18622 // This is set if HW acceleration is requested, even if the current 18623 // process doesn't allow it. This is just to allow app preview 18624 // windows to better match their app. 18625 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 18626 } 18627 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 18628 18629 final int privateFlags2 = mPrivateFlags2; 18630 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 18631 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 18632 } 18633 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 18634 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 18635 } 18636 18637 drawableState = StateSet.get(viewStateIndex); 18638 18639 //noinspection ConstantIfStatement 18640 if (false) { 18641 Log.i("View", "drawableStateIndex=" + viewStateIndex); 18642 Log.i("View", toString() 18643 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 18644 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 18645 + " fo=" + hasFocus() 18646 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 18647 + " wf=" + hasWindowFocus() 18648 + ": " + Arrays.toString(drawableState)); 18649 } 18650 18651 if (extraSpace == 0) { 18652 return drawableState; 18653 } 18654 18655 final int[] fullState; 18656 if (drawableState != null) { 18657 fullState = new int[drawableState.length + extraSpace]; 18658 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 18659 } else { 18660 fullState = new int[extraSpace]; 18661 } 18662 18663 return fullState; 18664 } 18665 18666 /** 18667 * Merge your own state values in <var>additionalState</var> into the base 18668 * state values <var>baseState</var> that were returned by 18669 * {@link #onCreateDrawableState(int)}. 18670 * 18671 * @param baseState The base state values returned by 18672 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 18673 * own additional state values. 18674 * 18675 * @param additionalState The additional state values you would like 18676 * added to <var>baseState</var>; this array is not modified. 18677 * 18678 * @return As a convenience, the <var>baseState</var> array you originally 18679 * passed into the function is returned. 18680 * 18681 * @see #onCreateDrawableState(int) 18682 */ 18683 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 18684 final int N = baseState.length; 18685 int i = N - 1; 18686 while (i >= 0 && baseState[i] == 0) { 18687 i--; 18688 } 18689 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 18690 return baseState; 18691 } 18692 18693 /** 18694 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 18695 * on all Drawable objects associated with this view. 18696 * <p> 18697 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 18698 * attached to this view. 18699 */ 18700 @CallSuper 18701 public void jumpDrawablesToCurrentState() { 18702 if (mBackground != null) { 18703 mBackground.jumpToCurrentState(); 18704 } 18705 if (mStateListAnimator != null) { 18706 mStateListAnimator.jumpToCurrentState(); 18707 } 18708 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18709 mForegroundInfo.mDrawable.jumpToCurrentState(); 18710 } 18711 } 18712 18713 /** 18714 * Sets the background color for this view. 18715 * @param color the color of the background 18716 */ 18717 @RemotableViewMethod 18718 public void setBackgroundColor(@ColorInt int color) { 18719 if (mBackground instanceof ColorDrawable) { 18720 ((ColorDrawable) mBackground.mutate()).setColor(color); 18721 computeOpaqueFlags(); 18722 mBackgroundResource = 0; 18723 } else { 18724 setBackground(new ColorDrawable(color)); 18725 } 18726 } 18727 18728 /** 18729 * Set the background to a given resource. The resource should refer to 18730 * a Drawable object or 0 to remove the background. 18731 * @param resid The identifier of the resource. 18732 * 18733 * @attr ref android.R.styleable#View_background 18734 */ 18735 @RemotableViewMethod 18736 public void setBackgroundResource(@DrawableRes int resid) { 18737 if (resid != 0 && resid == mBackgroundResource) { 18738 return; 18739 } 18740 18741 Drawable d = null; 18742 if (resid != 0) { 18743 d = mContext.getDrawable(resid); 18744 } 18745 setBackground(d); 18746 18747 mBackgroundResource = resid; 18748 } 18749 18750 /** 18751 * Set the background to a given Drawable, or remove the background. If the 18752 * background has padding, this View's padding is set to the background's 18753 * padding. However, when a background is removed, this View's padding isn't 18754 * touched. If setting the padding is desired, please use 18755 * {@link #setPadding(int, int, int, int)}. 18756 * 18757 * @param background The Drawable to use as the background, or null to remove the 18758 * background 18759 */ 18760 public void setBackground(Drawable background) { 18761 //noinspection deprecation 18762 setBackgroundDrawable(background); 18763 } 18764 18765 /** 18766 * @deprecated use {@link #setBackground(Drawable)} instead 18767 */ 18768 @Deprecated 18769 public void setBackgroundDrawable(Drawable background) { 18770 computeOpaqueFlags(); 18771 18772 if (background == mBackground) { 18773 return; 18774 } 18775 18776 boolean requestLayout = false; 18777 18778 mBackgroundResource = 0; 18779 18780 /* 18781 * Regardless of whether we're setting a new background or not, we want 18782 * to clear the previous drawable. setVisible first while we still have the callback set. 18783 */ 18784 if (mBackground != null) { 18785 if (isAttachedToWindow()) { 18786 mBackground.setVisible(false, false); 18787 } 18788 mBackground.setCallback(null); 18789 unscheduleDrawable(mBackground); 18790 } 18791 18792 if (background != null) { 18793 Rect padding = sThreadLocal.get(); 18794 if (padding == null) { 18795 padding = new Rect(); 18796 sThreadLocal.set(padding); 18797 } 18798 resetResolvedDrawablesInternal(); 18799 background.setLayoutDirection(getLayoutDirection()); 18800 if (background.getPadding(padding)) { 18801 resetResolvedPaddingInternal(); 18802 switch (background.getLayoutDirection()) { 18803 case LAYOUT_DIRECTION_RTL: 18804 mUserPaddingLeftInitial = padding.right; 18805 mUserPaddingRightInitial = padding.left; 18806 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 18807 break; 18808 case LAYOUT_DIRECTION_LTR: 18809 default: 18810 mUserPaddingLeftInitial = padding.left; 18811 mUserPaddingRightInitial = padding.right; 18812 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 18813 } 18814 mLeftPaddingDefined = false; 18815 mRightPaddingDefined = false; 18816 } 18817 18818 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 18819 // if it has a different minimum size, we should layout again 18820 if (mBackground == null 18821 || mBackground.getMinimumHeight() != background.getMinimumHeight() 18822 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 18823 requestLayout = true; 18824 } 18825 18826 // Set mBackground before we set this as the callback and start making other 18827 // background drawable state change calls. In particular, the setVisible call below 18828 // can result in drawables attempting to start animations or otherwise invalidate, 18829 // which requires the view set as the callback (us) to recognize the drawable as 18830 // belonging to it as per verifyDrawable. 18831 mBackground = background; 18832 if (background.isStateful()) { 18833 background.setState(getDrawableState()); 18834 } 18835 if (isAttachedToWindow()) { 18836 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 18837 } 18838 18839 applyBackgroundTint(); 18840 18841 // Set callback last, since the view may still be initializing. 18842 background.setCallback(this); 18843 18844 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 18845 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 18846 requestLayout = true; 18847 } 18848 } else { 18849 /* Remove the background */ 18850 mBackground = null; 18851 if ((mViewFlags & WILL_NOT_DRAW) != 0 18852 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 18853 mPrivateFlags |= PFLAG_SKIP_DRAW; 18854 } 18855 18856 /* 18857 * When the background is set, we try to apply its padding to this 18858 * View. When the background is removed, we don't touch this View's 18859 * padding. This is noted in the Javadocs. Hence, we don't need to 18860 * requestLayout(), the invalidate() below is sufficient. 18861 */ 18862 18863 // The old background's minimum size could have affected this 18864 // View's layout, so let's requestLayout 18865 requestLayout = true; 18866 } 18867 18868 computeOpaqueFlags(); 18869 18870 if (requestLayout) { 18871 requestLayout(); 18872 } 18873 18874 mBackgroundSizeChanged = true; 18875 invalidate(true); 18876 invalidateOutline(); 18877 } 18878 18879 /** 18880 * Gets the background drawable 18881 * 18882 * @return The drawable used as the background for this view, if any. 18883 * 18884 * @see #setBackground(Drawable) 18885 * 18886 * @attr ref android.R.styleable#View_background 18887 */ 18888 public Drawable getBackground() { 18889 return mBackground; 18890 } 18891 18892 /** 18893 * Applies a tint to the background drawable. Does not modify the current tint 18894 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 18895 * <p> 18896 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 18897 * mutate the drawable and apply the specified tint and tint mode using 18898 * {@link Drawable#setTintList(ColorStateList)}. 18899 * 18900 * @param tint the tint to apply, may be {@code null} to clear tint 18901 * 18902 * @attr ref android.R.styleable#View_backgroundTint 18903 * @see #getBackgroundTintList() 18904 * @see Drawable#setTintList(ColorStateList) 18905 */ 18906 public void setBackgroundTintList(@Nullable ColorStateList tint) { 18907 if (mBackgroundTint == null) { 18908 mBackgroundTint = new TintInfo(); 18909 } 18910 mBackgroundTint.mTintList = tint; 18911 mBackgroundTint.mHasTintList = true; 18912 18913 applyBackgroundTint(); 18914 } 18915 18916 /** 18917 * Return the tint applied to the background drawable, if specified. 18918 * 18919 * @return the tint applied to the background drawable 18920 * @attr ref android.R.styleable#View_backgroundTint 18921 * @see #setBackgroundTintList(ColorStateList) 18922 */ 18923 @Nullable 18924 public ColorStateList getBackgroundTintList() { 18925 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 18926 } 18927 18928 /** 18929 * Specifies the blending mode used to apply the tint specified by 18930 * {@link #setBackgroundTintList(ColorStateList)}} to the background 18931 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 18932 * 18933 * @param tintMode the blending mode used to apply the tint, may be 18934 * {@code null} to clear tint 18935 * @attr ref android.R.styleable#View_backgroundTintMode 18936 * @see #getBackgroundTintMode() 18937 * @see Drawable#setTintMode(PorterDuff.Mode) 18938 */ 18939 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 18940 if (mBackgroundTint == null) { 18941 mBackgroundTint = new TintInfo(); 18942 } 18943 mBackgroundTint.mTintMode = tintMode; 18944 mBackgroundTint.mHasTintMode = true; 18945 18946 applyBackgroundTint(); 18947 } 18948 18949 /** 18950 * Return the blending mode used to apply the tint to the background 18951 * drawable, if specified. 18952 * 18953 * @return the blending mode used to apply the tint to the background 18954 * drawable 18955 * @attr ref android.R.styleable#View_backgroundTintMode 18956 * @see #setBackgroundTintMode(PorterDuff.Mode) 18957 */ 18958 @Nullable 18959 public PorterDuff.Mode getBackgroundTintMode() { 18960 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 18961 } 18962 18963 private void applyBackgroundTint() { 18964 if (mBackground != null && mBackgroundTint != null) { 18965 final TintInfo tintInfo = mBackgroundTint; 18966 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 18967 mBackground = mBackground.mutate(); 18968 18969 if (tintInfo.mHasTintList) { 18970 mBackground.setTintList(tintInfo.mTintList); 18971 } 18972 18973 if (tintInfo.mHasTintMode) { 18974 mBackground.setTintMode(tintInfo.mTintMode); 18975 } 18976 18977 // The drawable (or one of its children) may not have been 18978 // stateful before applying the tint, so let's try again. 18979 if (mBackground.isStateful()) { 18980 mBackground.setState(getDrawableState()); 18981 } 18982 } 18983 } 18984 } 18985 18986 /** 18987 * Returns the drawable used as the foreground of this View. The 18988 * foreground drawable, if non-null, is always drawn on top of the view's content. 18989 * 18990 * @return a Drawable or null if no foreground was set 18991 * 18992 * @see #onDrawForeground(Canvas) 18993 */ 18994 public Drawable getForeground() { 18995 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 18996 } 18997 18998 /** 18999 * Supply a Drawable that is to be rendered on top of all of the content in the view. 19000 * 19001 * @param foreground the Drawable to be drawn on top of the children 19002 * 19003 * @attr ref android.R.styleable#View_foreground 19004 */ 19005 public void setForeground(Drawable foreground) { 19006 if (mForegroundInfo == null) { 19007 if (foreground == null) { 19008 // Nothing to do. 19009 return; 19010 } 19011 mForegroundInfo = new ForegroundInfo(); 19012 } 19013 19014 if (foreground == mForegroundInfo.mDrawable) { 19015 // Nothing to do 19016 return; 19017 } 19018 19019 if (mForegroundInfo.mDrawable != null) { 19020 if (isAttachedToWindow()) { 19021 mForegroundInfo.mDrawable.setVisible(false, false); 19022 } 19023 mForegroundInfo.mDrawable.setCallback(null); 19024 unscheduleDrawable(mForegroundInfo.mDrawable); 19025 } 19026 19027 mForegroundInfo.mDrawable = foreground; 19028 mForegroundInfo.mBoundsChanged = true; 19029 if (foreground != null) { 19030 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19031 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19032 } 19033 foreground.setLayoutDirection(getLayoutDirection()); 19034 if (foreground.isStateful()) { 19035 foreground.setState(getDrawableState()); 19036 } 19037 applyForegroundTint(); 19038 if (isAttachedToWindow()) { 19039 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 19040 } 19041 // Set callback last, since the view may still be initializing. 19042 foreground.setCallback(this); 19043 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) { 19044 mPrivateFlags |= PFLAG_SKIP_DRAW; 19045 } 19046 requestLayout(); 19047 invalidate(); 19048 } 19049 19050 /** 19051 * Magic bit used to support features of framework-internal window decor implementation details. 19052 * This used to live exclusively in FrameLayout. 19053 * 19054 * @return true if the foreground should draw inside the padding region or false 19055 * if it should draw inset by the view's padding 19056 * @hide internal use only; only used by FrameLayout and internal screen layouts. 19057 */ 19058 public boolean isForegroundInsidePadding() { 19059 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 19060 } 19061 19062 /** 19063 * Describes how the foreground is positioned. 19064 * 19065 * @return foreground gravity. 19066 * 19067 * @see #setForegroundGravity(int) 19068 * 19069 * @attr ref android.R.styleable#View_foregroundGravity 19070 */ 19071 public int getForegroundGravity() { 19072 return mForegroundInfo != null ? mForegroundInfo.mGravity 19073 : Gravity.START | Gravity.TOP; 19074 } 19075 19076 /** 19077 * Describes how the foreground is positioned. Defaults to START and TOP. 19078 * 19079 * @param gravity see {@link android.view.Gravity} 19080 * 19081 * @see #getForegroundGravity() 19082 * 19083 * @attr ref android.R.styleable#View_foregroundGravity 19084 */ 19085 public void setForegroundGravity(int gravity) { 19086 if (mForegroundInfo == null) { 19087 mForegroundInfo = new ForegroundInfo(); 19088 } 19089 19090 if (mForegroundInfo.mGravity != gravity) { 19091 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 19092 gravity |= Gravity.START; 19093 } 19094 19095 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 19096 gravity |= Gravity.TOP; 19097 } 19098 19099 mForegroundInfo.mGravity = gravity; 19100 requestLayout(); 19101 } 19102 } 19103 19104 /** 19105 * Applies a tint to the foreground drawable. Does not modify the current tint 19106 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19107 * <p> 19108 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 19109 * mutate the drawable and apply the specified tint and tint mode using 19110 * {@link Drawable#setTintList(ColorStateList)}. 19111 * 19112 * @param tint the tint to apply, may be {@code null} to clear tint 19113 * 19114 * @attr ref android.R.styleable#View_foregroundTint 19115 * @see #getForegroundTintList() 19116 * @see Drawable#setTintList(ColorStateList) 19117 */ 19118 public void setForegroundTintList(@Nullable ColorStateList tint) { 19119 if (mForegroundInfo == null) { 19120 mForegroundInfo = new ForegroundInfo(); 19121 } 19122 if (mForegroundInfo.mTintInfo == null) { 19123 mForegroundInfo.mTintInfo = new TintInfo(); 19124 } 19125 mForegroundInfo.mTintInfo.mTintList = tint; 19126 mForegroundInfo.mTintInfo.mHasTintList = true; 19127 19128 applyForegroundTint(); 19129 } 19130 19131 /** 19132 * Return the tint applied to the foreground drawable, if specified. 19133 * 19134 * @return the tint applied to the foreground drawable 19135 * @attr ref android.R.styleable#View_foregroundTint 19136 * @see #setForegroundTintList(ColorStateList) 19137 */ 19138 @Nullable 19139 public ColorStateList getForegroundTintList() { 19140 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19141 ? mForegroundInfo.mTintInfo.mTintList : null; 19142 } 19143 19144 /** 19145 * Specifies the blending mode used to apply the tint specified by 19146 * {@link #setForegroundTintList(ColorStateList)}} to the background 19147 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19148 * 19149 * @param tintMode the blending mode used to apply the tint, may be 19150 * {@code null} to clear tint 19151 * @attr ref android.R.styleable#View_foregroundTintMode 19152 * @see #getForegroundTintMode() 19153 * @see Drawable#setTintMode(PorterDuff.Mode) 19154 */ 19155 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19156 if (mForegroundInfo == null) { 19157 mForegroundInfo = new ForegroundInfo(); 19158 } 19159 if (mForegroundInfo.mTintInfo == null) { 19160 mForegroundInfo.mTintInfo = new TintInfo(); 19161 } 19162 mForegroundInfo.mTintInfo.mTintMode = tintMode; 19163 mForegroundInfo.mTintInfo.mHasTintMode = true; 19164 19165 applyForegroundTint(); 19166 } 19167 19168 /** 19169 * Return the blending mode used to apply the tint to the foreground 19170 * drawable, if specified. 19171 * 19172 * @return the blending mode used to apply the tint to the foreground 19173 * drawable 19174 * @attr ref android.R.styleable#View_foregroundTintMode 19175 * @see #setForegroundTintMode(PorterDuff.Mode) 19176 */ 19177 @Nullable 19178 public PorterDuff.Mode getForegroundTintMode() { 19179 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19180 ? mForegroundInfo.mTintInfo.mTintMode : null; 19181 } 19182 19183 private void applyForegroundTint() { 19184 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 19185 && mForegroundInfo.mTintInfo != null) { 19186 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 19187 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19188 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 19189 19190 if (tintInfo.mHasTintList) { 19191 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 19192 } 19193 19194 if (tintInfo.mHasTintMode) { 19195 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 19196 } 19197 19198 // The drawable (or one of its children) may not have been 19199 // stateful before applying the tint, so let's try again. 19200 if (mForegroundInfo.mDrawable.isStateful()) { 19201 mForegroundInfo.mDrawable.setState(getDrawableState()); 19202 } 19203 } 19204 } 19205 } 19206 19207 /** 19208 * Draw any foreground content for this view. 19209 * 19210 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 19211 * drawable or other view-specific decorations. The foreground is drawn on top of the 19212 * primary view content.</p> 19213 * 19214 * @param canvas canvas to draw into 19215 */ 19216 public void onDrawForeground(Canvas canvas) { 19217 onDrawScrollIndicators(canvas); 19218 onDrawScrollBars(canvas); 19219 19220 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19221 if (foreground != null) { 19222 if (mForegroundInfo.mBoundsChanged) { 19223 mForegroundInfo.mBoundsChanged = false; 19224 final Rect selfBounds = mForegroundInfo.mSelfBounds; 19225 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 19226 19227 if (mForegroundInfo.mInsidePadding) { 19228 selfBounds.set(0, 0, getWidth(), getHeight()); 19229 } else { 19230 selfBounds.set(getPaddingLeft(), getPaddingTop(), 19231 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 19232 } 19233 19234 final int ld = getLayoutDirection(); 19235 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 19236 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 19237 foreground.setBounds(overlayBounds); 19238 } 19239 19240 foreground.draw(canvas); 19241 } 19242 } 19243 19244 /** 19245 * Sets the padding. The view may add on the space required to display 19246 * the scrollbars, depending on the style and visibility of the scrollbars. 19247 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 19248 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 19249 * from the values set in this call. 19250 * 19251 * @attr ref android.R.styleable#View_padding 19252 * @attr ref android.R.styleable#View_paddingBottom 19253 * @attr ref android.R.styleable#View_paddingLeft 19254 * @attr ref android.R.styleable#View_paddingRight 19255 * @attr ref android.R.styleable#View_paddingTop 19256 * @param left the left padding in pixels 19257 * @param top the top padding in pixels 19258 * @param right the right padding in pixels 19259 * @param bottom the bottom padding in pixels 19260 */ 19261 public void setPadding(int left, int top, int right, int bottom) { 19262 resetResolvedPaddingInternal(); 19263 19264 mUserPaddingStart = UNDEFINED_PADDING; 19265 mUserPaddingEnd = UNDEFINED_PADDING; 19266 19267 mUserPaddingLeftInitial = left; 19268 mUserPaddingRightInitial = right; 19269 19270 mLeftPaddingDefined = true; 19271 mRightPaddingDefined = true; 19272 19273 internalSetPadding(left, top, right, bottom); 19274 } 19275 19276 /** 19277 * @hide 19278 */ 19279 protected void internalSetPadding(int left, int top, int right, int bottom) { 19280 mUserPaddingLeft = left; 19281 mUserPaddingRight = right; 19282 mUserPaddingBottom = bottom; 19283 19284 final int viewFlags = mViewFlags; 19285 boolean changed = false; 19286 19287 // Common case is there are no scroll bars. 19288 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 19289 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 19290 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 19291 ? 0 : getVerticalScrollbarWidth(); 19292 switch (mVerticalScrollbarPosition) { 19293 case SCROLLBAR_POSITION_DEFAULT: 19294 if (isLayoutRtl()) { 19295 left += offset; 19296 } else { 19297 right += offset; 19298 } 19299 break; 19300 case SCROLLBAR_POSITION_RIGHT: 19301 right += offset; 19302 break; 19303 case SCROLLBAR_POSITION_LEFT: 19304 left += offset; 19305 break; 19306 } 19307 } 19308 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 19309 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 19310 ? 0 : getHorizontalScrollbarHeight(); 19311 } 19312 } 19313 19314 if (mPaddingLeft != left) { 19315 changed = true; 19316 mPaddingLeft = left; 19317 } 19318 if (mPaddingTop != top) { 19319 changed = true; 19320 mPaddingTop = top; 19321 } 19322 if (mPaddingRight != right) { 19323 changed = true; 19324 mPaddingRight = right; 19325 } 19326 if (mPaddingBottom != bottom) { 19327 changed = true; 19328 mPaddingBottom = bottom; 19329 } 19330 19331 if (changed) { 19332 requestLayout(); 19333 invalidateOutline(); 19334 } 19335 } 19336 19337 /** 19338 * Sets the relative padding. The view may add on the space required to display 19339 * the scrollbars, depending on the style and visibility of the scrollbars. 19340 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 19341 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 19342 * from the values set in this call. 19343 * 19344 * @attr ref android.R.styleable#View_padding 19345 * @attr ref android.R.styleable#View_paddingBottom 19346 * @attr ref android.R.styleable#View_paddingStart 19347 * @attr ref android.R.styleable#View_paddingEnd 19348 * @attr ref android.R.styleable#View_paddingTop 19349 * @param start the start padding in pixels 19350 * @param top the top padding in pixels 19351 * @param end the end padding in pixels 19352 * @param bottom the bottom padding in pixels 19353 */ 19354 public void setPaddingRelative(int start, int top, int end, int bottom) { 19355 resetResolvedPaddingInternal(); 19356 19357 mUserPaddingStart = start; 19358 mUserPaddingEnd = end; 19359 mLeftPaddingDefined = true; 19360 mRightPaddingDefined = true; 19361 19362 switch(getLayoutDirection()) { 19363 case LAYOUT_DIRECTION_RTL: 19364 mUserPaddingLeftInitial = end; 19365 mUserPaddingRightInitial = start; 19366 internalSetPadding(end, top, start, bottom); 19367 break; 19368 case LAYOUT_DIRECTION_LTR: 19369 default: 19370 mUserPaddingLeftInitial = start; 19371 mUserPaddingRightInitial = end; 19372 internalSetPadding(start, top, end, bottom); 19373 } 19374 } 19375 19376 /** 19377 * Returns the top padding of this view. 19378 * 19379 * @return the top padding in pixels 19380 */ 19381 public int getPaddingTop() { 19382 return mPaddingTop; 19383 } 19384 19385 /** 19386 * Returns the bottom padding of this view. If there are inset and enabled 19387 * scrollbars, this value may include the space required to display the 19388 * scrollbars as well. 19389 * 19390 * @return the bottom padding in pixels 19391 */ 19392 public int getPaddingBottom() { 19393 return mPaddingBottom; 19394 } 19395 19396 /** 19397 * Returns the left padding of this view. If there are inset and enabled 19398 * scrollbars, this value may include the space required to display the 19399 * scrollbars as well. 19400 * 19401 * @return the left padding in pixels 19402 */ 19403 public int getPaddingLeft() { 19404 if (!isPaddingResolved()) { 19405 resolvePadding(); 19406 } 19407 return mPaddingLeft; 19408 } 19409 19410 /** 19411 * Returns the start padding of this view depending on its resolved layout direction. 19412 * If there are inset and enabled scrollbars, this value may include the space 19413 * required to display the scrollbars as well. 19414 * 19415 * @return the start padding in pixels 19416 */ 19417 public int getPaddingStart() { 19418 if (!isPaddingResolved()) { 19419 resolvePadding(); 19420 } 19421 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19422 mPaddingRight : mPaddingLeft; 19423 } 19424 19425 /** 19426 * Returns the right padding of this view. If there are inset and enabled 19427 * scrollbars, this value may include the space required to display the 19428 * scrollbars as well. 19429 * 19430 * @return the right padding in pixels 19431 */ 19432 public int getPaddingRight() { 19433 if (!isPaddingResolved()) { 19434 resolvePadding(); 19435 } 19436 return mPaddingRight; 19437 } 19438 19439 /** 19440 * Returns the end padding of this view depending on its resolved layout direction. 19441 * If there are inset and enabled scrollbars, this value may include the space 19442 * required to display the scrollbars as well. 19443 * 19444 * @return the end padding in pixels 19445 */ 19446 public int getPaddingEnd() { 19447 if (!isPaddingResolved()) { 19448 resolvePadding(); 19449 } 19450 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19451 mPaddingLeft : mPaddingRight; 19452 } 19453 19454 /** 19455 * Return if the padding has been set through relative values 19456 * {@link #setPaddingRelative(int, int, int, int)} or through 19457 * @attr ref android.R.styleable#View_paddingStart or 19458 * @attr ref android.R.styleable#View_paddingEnd 19459 * 19460 * @return true if the padding is relative or false if it is not. 19461 */ 19462 public boolean isPaddingRelative() { 19463 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 19464 } 19465 19466 Insets computeOpticalInsets() { 19467 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 19468 } 19469 19470 /** 19471 * @hide 19472 */ 19473 public void resetPaddingToInitialValues() { 19474 if (isRtlCompatibilityMode()) { 19475 mPaddingLeft = mUserPaddingLeftInitial; 19476 mPaddingRight = mUserPaddingRightInitial; 19477 return; 19478 } 19479 if (isLayoutRtl()) { 19480 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 19481 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 19482 } else { 19483 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 19484 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 19485 } 19486 } 19487 19488 /** 19489 * @hide 19490 */ 19491 public Insets getOpticalInsets() { 19492 if (mLayoutInsets == null) { 19493 mLayoutInsets = computeOpticalInsets(); 19494 } 19495 return mLayoutInsets; 19496 } 19497 19498 /** 19499 * Set this view's optical insets. 19500 * 19501 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 19502 * property. Views that compute their own optical insets should call it as part of measurement. 19503 * This method does not request layout. If you are setting optical insets outside of 19504 * measure/layout itself you will want to call requestLayout() yourself. 19505 * </p> 19506 * @hide 19507 */ 19508 public void setOpticalInsets(Insets insets) { 19509 mLayoutInsets = insets; 19510 } 19511 19512 /** 19513 * Changes the selection state of this view. A view can be selected or not. 19514 * Note that selection is not the same as focus. Views are typically 19515 * selected in the context of an AdapterView like ListView or GridView; 19516 * the selected view is the view that is highlighted. 19517 * 19518 * @param selected true if the view must be selected, false otherwise 19519 */ 19520 public void setSelected(boolean selected) { 19521 //noinspection DoubleNegation 19522 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 19523 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 19524 if (!selected) resetPressedState(); 19525 invalidate(true); 19526 refreshDrawableState(); 19527 dispatchSetSelected(selected); 19528 if (selected) { 19529 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 19530 } else { 19531 notifyViewAccessibilityStateChangedIfNeeded( 19532 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 19533 } 19534 } 19535 } 19536 19537 /** 19538 * Dispatch setSelected to all of this View's children. 19539 * 19540 * @see #setSelected(boolean) 19541 * 19542 * @param selected The new selected state 19543 */ 19544 protected void dispatchSetSelected(boolean selected) { 19545 } 19546 19547 /** 19548 * Indicates the selection state of this view. 19549 * 19550 * @return true if the view is selected, false otherwise 19551 */ 19552 @ViewDebug.ExportedProperty 19553 public boolean isSelected() { 19554 return (mPrivateFlags & PFLAG_SELECTED) != 0; 19555 } 19556 19557 /** 19558 * Changes the activated state of this view. A view can be activated or not. 19559 * Note that activation is not the same as selection. Selection is 19560 * a transient property, representing the view (hierarchy) the user is 19561 * currently interacting with. Activation is a longer-term state that the 19562 * user can move views in and out of. For example, in a list view with 19563 * single or multiple selection enabled, the views in the current selection 19564 * set are activated. (Um, yeah, we are deeply sorry about the terminology 19565 * here.) The activated state is propagated down to children of the view it 19566 * is set on. 19567 * 19568 * @param activated true if the view must be activated, false otherwise 19569 */ 19570 public void setActivated(boolean activated) { 19571 //noinspection DoubleNegation 19572 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 19573 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 19574 invalidate(true); 19575 refreshDrawableState(); 19576 dispatchSetActivated(activated); 19577 } 19578 } 19579 19580 /** 19581 * Dispatch setActivated to all of this View's children. 19582 * 19583 * @see #setActivated(boolean) 19584 * 19585 * @param activated The new activated state 19586 */ 19587 protected void dispatchSetActivated(boolean activated) { 19588 } 19589 19590 /** 19591 * Indicates the activation state of this view. 19592 * 19593 * @return true if the view is activated, false otherwise 19594 */ 19595 @ViewDebug.ExportedProperty 19596 public boolean isActivated() { 19597 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 19598 } 19599 19600 /** 19601 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 19602 * observer can be used to get notifications when global events, like 19603 * layout, happen. 19604 * 19605 * The returned ViewTreeObserver observer is not guaranteed to remain 19606 * valid for the lifetime of this View. If the caller of this method keeps 19607 * a long-lived reference to ViewTreeObserver, it should always check for 19608 * the return value of {@link ViewTreeObserver#isAlive()}. 19609 * 19610 * @return The ViewTreeObserver for this view's hierarchy. 19611 */ 19612 public ViewTreeObserver getViewTreeObserver() { 19613 if (mAttachInfo != null) { 19614 return mAttachInfo.mTreeObserver; 19615 } 19616 if (mFloatingTreeObserver == null) { 19617 mFloatingTreeObserver = new ViewTreeObserver(mContext); 19618 } 19619 return mFloatingTreeObserver; 19620 } 19621 19622 /** 19623 * <p>Finds the topmost view in the current view hierarchy.</p> 19624 * 19625 * @return the topmost view containing this view 19626 */ 19627 public View getRootView() { 19628 if (mAttachInfo != null) { 19629 final View v = mAttachInfo.mRootView; 19630 if (v != null) { 19631 return v; 19632 } 19633 } 19634 19635 View parent = this; 19636 19637 while (parent.mParent != null && parent.mParent instanceof View) { 19638 parent = (View) parent.mParent; 19639 } 19640 19641 return parent; 19642 } 19643 19644 /** 19645 * Transforms a motion event from view-local coordinates to on-screen 19646 * coordinates. 19647 * 19648 * @param ev the view-local motion event 19649 * @return false if the transformation could not be applied 19650 * @hide 19651 */ 19652 public boolean toGlobalMotionEvent(MotionEvent ev) { 19653 final AttachInfo info = mAttachInfo; 19654 if (info == null) { 19655 return false; 19656 } 19657 19658 final Matrix m = info.mTmpMatrix; 19659 m.set(Matrix.IDENTITY_MATRIX); 19660 transformMatrixToGlobal(m); 19661 ev.transform(m); 19662 return true; 19663 } 19664 19665 /** 19666 * Transforms a motion event from on-screen coordinates to view-local 19667 * coordinates. 19668 * 19669 * @param ev the on-screen motion event 19670 * @return false if the transformation could not be applied 19671 * @hide 19672 */ 19673 public boolean toLocalMotionEvent(MotionEvent ev) { 19674 final AttachInfo info = mAttachInfo; 19675 if (info == null) { 19676 return false; 19677 } 19678 19679 final Matrix m = info.mTmpMatrix; 19680 m.set(Matrix.IDENTITY_MATRIX); 19681 transformMatrixToLocal(m); 19682 ev.transform(m); 19683 return true; 19684 } 19685 19686 /** 19687 * Modifies the input matrix such that it maps view-local coordinates to 19688 * on-screen coordinates. 19689 * 19690 * @param m input matrix to modify 19691 * @hide 19692 */ 19693 public void transformMatrixToGlobal(Matrix m) { 19694 final ViewParent parent = mParent; 19695 if (parent instanceof View) { 19696 final View vp = (View) parent; 19697 vp.transformMatrixToGlobal(m); 19698 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 19699 } else if (parent instanceof ViewRootImpl) { 19700 final ViewRootImpl vr = (ViewRootImpl) parent; 19701 vr.transformMatrixToGlobal(m); 19702 m.preTranslate(0, -vr.mCurScrollY); 19703 } 19704 19705 m.preTranslate(mLeft, mTop); 19706 19707 if (!hasIdentityMatrix()) { 19708 m.preConcat(getMatrix()); 19709 } 19710 } 19711 19712 /** 19713 * Modifies the input matrix such that it maps on-screen coordinates to 19714 * view-local coordinates. 19715 * 19716 * @param m input matrix to modify 19717 * @hide 19718 */ 19719 public void transformMatrixToLocal(Matrix m) { 19720 final ViewParent parent = mParent; 19721 if (parent instanceof View) { 19722 final View vp = (View) parent; 19723 vp.transformMatrixToLocal(m); 19724 m.postTranslate(vp.mScrollX, vp.mScrollY); 19725 } else if (parent instanceof ViewRootImpl) { 19726 final ViewRootImpl vr = (ViewRootImpl) parent; 19727 vr.transformMatrixToLocal(m); 19728 m.postTranslate(0, vr.mCurScrollY); 19729 } 19730 19731 m.postTranslate(-mLeft, -mTop); 19732 19733 if (!hasIdentityMatrix()) { 19734 m.postConcat(getInverseMatrix()); 19735 } 19736 } 19737 19738 /** 19739 * @hide 19740 */ 19741 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 19742 @ViewDebug.IntToString(from = 0, to = "x"), 19743 @ViewDebug.IntToString(from = 1, to = "y") 19744 }) 19745 public int[] getLocationOnScreen() { 19746 int[] location = new int[2]; 19747 getLocationOnScreen(location); 19748 return location; 19749 } 19750 19751 /** 19752 * <p>Computes the coordinates of this view on the screen. The argument 19753 * must be an array of two integers. After the method returns, the array 19754 * contains the x and y location in that order.</p> 19755 * 19756 * @param outLocation an array of two integers in which to hold the coordinates 19757 */ 19758 public void getLocationOnScreen(@Size(2) int[] outLocation) { 19759 getLocationInWindow(outLocation); 19760 19761 final AttachInfo info = mAttachInfo; 19762 if (info != null) { 19763 outLocation[0] += info.mWindowLeft; 19764 outLocation[1] += info.mWindowTop; 19765 } 19766 } 19767 19768 /** 19769 * <p>Computes the coordinates of this view in its window. The argument 19770 * must be an array of two integers. After the method returns, the array 19771 * contains the x and y location in that order.</p> 19772 * 19773 * @param outLocation an array of two integers in which to hold the coordinates 19774 */ 19775 public void getLocationInWindow(@Size(2) int[] outLocation) { 19776 if (outLocation == null || outLocation.length < 2) { 19777 throw new IllegalArgumentException("outLocation must be an array of two integers"); 19778 } 19779 19780 outLocation[0] = 0; 19781 outLocation[1] = 0; 19782 19783 transformFromViewToWindowSpace(outLocation); 19784 } 19785 19786 /** @hide */ 19787 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 19788 if (inOutLocation == null || inOutLocation.length < 2) { 19789 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 19790 } 19791 19792 if (mAttachInfo == null) { 19793 // When the view is not attached to a window, this method does not make sense 19794 inOutLocation[0] = inOutLocation[1] = 0; 19795 return; 19796 } 19797 19798 float position[] = mAttachInfo.mTmpTransformLocation; 19799 position[0] = inOutLocation[0]; 19800 position[1] = inOutLocation[1]; 19801 19802 if (!hasIdentityMatrix()) { 19803 getMatrix().mapPoints(position); 19804 } 19805 19806 position[0] += mLeft; 19807 position[1] += mTop; 19808 19809 ViewParent viewParent = mParent; 19810 while (viewParent instanceof View) { 19811 final View view = (View) viewParent; 19812 19813 position[0] -= view.mScrollX; 19814 position[1] -= view.mScrollY; 19815 19816 if (!view.hasIdentityMatrix()) { 19817 view.getMatrix().mapPoints(position); 19818 } 19819 19820 position[0] += view.mLeft; 19821 position[1] += view.mTop; 19822 19823 viewParent = view.mParent; 19824 } 19825 19826 if (viewParent instanceof ViewRootImpl) { 19827 // *cough* 19828 final ViewRootImpl vr = (ViewRootImpl) viewParent; 19829 position[1] -= vr.mCurScrollY; 19830 } 19831 19832 inOutLocation[0] = Math.round(position[0]); 19833 inOutLocation[1] = Math.round(position[1]); 19834 } 19835 19836 /** 19837 * {@hide} 19838 * @param id the id of the view to be found 19839 * @return the view of the specified id, null if cannot be found 19840 */ 19841 protected View findViewTraversal(@IdRes int id) { 19842 if (id == mID) { 19843 return this; 19844 } 19845 return null; 19846 } 19847 19848 /** 19849 * {@hide} 19850 * @param tag the tag of the view to be found 19851 * @return the view of specified tag, null if cannot be found 19852 */ 19853 protected View findViewWithTagTraversal(Object tag) { 19854 if (tag != null && tag.equals(mTag)) { 19855 return this; 19856 } 19857 return null; 19858 } 19859 19860 /** 19861 * {@hide} 19862 * @param predicate The predicate to evaluate. 19863 * @param childToSkip If not null, ignores this child during the recursive traversal. 19864 * @return The first view that matches the predicate or null. 19865 */ 19866 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 19867 if (predicate.apply(this)) { 19868 return this; 19869 } 19870 return null; 19871 } 19872 19873 /** 19874 * Look for a child view with the given id. If this view has the given 19875 * id, return this view. 19876 * 19877 * @param id The id to search for. 19878 * @return The view that has the given id in the hierarchy or null 19879 */ 19880 @Nullable 19881 public final View findViewById(@IdRes int id) { 19882 if (id < 0) { 19883 return null; 19884 } 19885 return findViewTraversal(id); 19886 } 19887 19888 /** 19889 * Finds a view by its unuque and stable accessibility id. 19890 * 19891 * @param accessibilityId The searched accessibility id. 19892 * @return The found view. 19893 */ 19894 final View findViewByAccessibilityId(int accessibilityId) { 19895 if (accessibilityId < 0) { 19896 return null; 19897 } 19898 View view = findViewByAccessibilityIdTraversal(accessibilityId); 19899 if (view != null) { 19900 return view.includeForAccessibility() ? view : null; 19901 } 19902 return null; 19903 } 19904 19905 /** 19906 * Performs the traversal to find a view by its unuque and stable accessibility id. 19907 * 19908 * <strong>Note:</strong>This method does not stop at the root namespace 19909 * boundary since the user can touch the screen at an arbitrary location 19910 * potentially crossing the root namespace bounday which will send an 19911 * accessibility event to accessibility services and they should be able 19912 * to obtain the event source. Also accessibility ids are guaranteed to be 19913 * unique in the window. 19914 * 19915 * @param accessibilityId The accessibility id. 19916 * @return The found view. 19917 * 19918 * @hide 19919 */ 19920 public View findViewByAccessibilityIdTraversal(int accessibilityId) { 19921 if (getAccessibilityViewId() == accessibilityId) { 19922 return this; 19923 } 19924 return null; 19925 } 19926 19927 /** 19928 * Look for a child view with the given tag. If this view has the given 19929 * tag, return this view. 19930 * 19931 * @param tag The tag to search for, using "tag.equals(getTag())". 19932 * @return The View that has the given tag in the hierarchy or null 19933 */ 19934 public final View findViewWithTag(Object tag) { 19935 if (tag == null) { 19936 return null; 19937 } 19938 return findViewWithTagTraversal(tag); 19939 } 19940 19941 /** 19942 * {@hide} 19943 * Look for a child view that matches the specified predicate. 19944 * If this view matches the predicate, return this view. 19945 * 19946 * @param predicate The predicate to evaluate. 19947 * @return The first view that matches the predicate or null. 19948 */ 19949 public final View findViewByPredicate(Predicate<View> predicate) { 19950 return findViewByPredicateTraversal(predicate, null); 19951 } 19952 19953 /** 19954 * {@hide} 19955 * Look for a child view that matches the specified predicate, 19956 * starting with the specified view and its descendents and then 19957 * recusively searching the ancestors and siblings of that view 19958 * until this view is reached. 19959 * 19960 * This method is useful in cases where the predicate does not match 19961 * a single unique view (perhaps multiple views use the same id) 19962 * and we are trying to find the view that is "closest" in scope to the 19963 * starting view. 19964 * 19965 * @param start The view to start from. 19966 * @param predicate The predicate to evaluate. 19967 * @return The first view that matches the predicate or null. 19968 */ 19969 public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) { 19970 View childToSkip = null; 19971 for (;;) { 19972 View view = start.findViewByPredicateTraversal(predicate, childToSkip); 19973 if (view != null || start == this) { 19974 return view; 19975 } 19976 19977 ViewParent parent = start.getParent(); 19978 if (parent == null || !(parent instanceof View)) { 19979 return null; 19980 } 19981 19982 childToSkip = start; 19983 start = (View) parent; 19984 } 19985 } 19986 19987 /** 19988 * Sets the identifier for this view. The identifier does not have to be 19989 * unique in this view's hierarchy. The identifier should be a positive 19990 * number. 19991 * 19992 * @see #NO_ID 19993 * @see #getId() 19994 * @see #findViewById(int) 19995 * 19996 * @param id a number used to identify the view 19997 * 19998 * @attr ref android.R.styleable#View_id 19999 */ 20000 public void setId(@IdRes int id) { 20001 mID = id; 20002 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 20003 mID = generateViewId(); 20004 } 20005 } 20006 20007 /** 20008 * {@hide} 20009 * 20010 * @param isRoot true if the view belongs to the root namespace, false 20011 * otherwise 20012 */ 20013 public void setIsRootNamespace(boolean isRoot) { 20014 if (isRoot) { 20015 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 20016 } else { 20017 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 20018 } 20019 } 20020 20021 /** 20022 * {@hide} 20023 * 20024 * @return true if the view belongs to the root namespace, false otherwise 20025 */ 20026 public boolean isRootNamespace() { 20027 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 20028 } 20029 20030 /** 20031 * Returns this view's identifier. 20032 * 20033 * @return a positive integer used to identify the view or {@link #NO_ID} 20034 * if the view has no ID 20035 * 20036 * @see #setId(int) 20037 * @see #findViewById(int) 20038 * @attr ref android.R.styleable#View_id 20039 */ 20040 @IdRes 20041 @ViewDebug.CapturedViewProperty 20042 public int getId() { 20043 return mID; 20044 } 20045 20046 /** 20047 * Returns this view's tag. 20048 * 20049 * @return the Object stored in this view as a tag, or {@code null} if not 20050 * set 20051 * 20052 * @see #setTag(Object) 20053 * @see #getTag(int) 20054 */ 20055 @ViewDebug.ExportedProperty 20056 public Object getTag() { 20057 return mTag; 20058 } 20059 20060 /** 20061 * Sets the tag associated with this view. A tag can be used to mark 20062 * a view in its hierarchy and does not have to be unique within the 20063 * hierarchy. Tags can also be used to store data within a view without 20064 * resorting to another data structure. 20065 * 20066 * @param tag an Object to tag the view with 20067 * 20068 * @see #getTag() 20069 * @see #setTag(int, Object) 20070 */ 20071 public void setTag(final Object tag) { 20072 mTag = tag; 20073 } 20074 20075 /** 20076 * Returns the tag associated with this view and the specified key. 20077 * 20078 * @param key The key identifying the tag 20079 * 20080 * @return the Object stored in this view as a tag, or {@code null} if not 20081 * set 20082 * 20083 * @see #setTag(int, Object) 20084 * @see #getTag() 20085 */ 20086 public Object getTag(int key) { 20087 if (mKeyedTags != null) return mKeyedTags.get(key); 20088 return null; 20089 } 20090 20091 /** 20092 * Sets a tag associated with this view and a key. A tag can be used 20093 * to mark a view in its hierarchy and does not have to be unique within 20094 * the hierarchy. Tags can also be used to store data within a view 20095 * without resorting to another data structure. 20096 * 20097 * The specified key should be an id declared in the resources of the 20098 * application to ensure it is unique (see the <a 20099 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 20100 * Keys identified as belonging to 20101 * the Android framework or not associated with any package will cause 20102 * an {@link IllegalArgumentException} to be thrown. 20103 * 20104 * @param key The key identifying the tag 20105 * @param tag An Object to tag the view with 20106 * 20107 * @throws IllegalArgumentException If they specified key is not valid 20108 * 20109 * @see #setTag(Object) 20110 * @see #getTag(int) 20111 */ 20112 public void setTag(int key, final Object tag) { 20113 // If the package id is 0x00 or 0x01, it's either an undefined package 20114 // or a framework id 20115 if ((key >>> 24) < 2) { 20116 throw new IllegalArgumentException("The key must be an application-specific " 20117 + "resource id."); 20118 } 20119 20120 setKeyedTag(key, tag); 20121 } 20122 20123 /** 20124 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 20125 * framework id. 20126 * 20127 * @hide 20128 */ 20129 public void setTagInternal(int key, Object tag) { 20130 if ((key >>> 24) != 0x1) { 20131 throw new IllegalArgumentException("The key must be a framework-specific " 20132 + "resource id."); 20133 } 20134 20135 setKeyedTag(key, tag); 20136 } 20137 20138 private void setKeyedTag(int key, Object tag) { 20139 if (mKeyedTags == null) { 20140 mKeyedTags = new SparseArray<Object>(2); 20141 } 20142 20143 mKeyedTags.put(key, tag); 20144 } 20145 20146 /** 20147 * Prints information about this view in the log output, with the tag 20148 * {@link #VIEW_LOG_TAG}. 20149 * 20150 * @hide 20151 */ 20152 public void debug() { 20153 debug(0); 20154 } 20155 20156 /** 20157 * Prints information about this view in the log output, with the tag 20158 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 20159 * indentation defined by the <code>depth</code>. 20160 * 20161 * @param depth the indentation level 20162 * 20163 * @hide 20164 */ 20165 protected void debug(int depth) { 20166 String output = debugIndent(depth - 1); 20167 20168 output += "+ " + this; 20169 int id = getId(); 20170 if (id != -1) { 20171 output += " (id=" + id + ")"; 20172 } 20173 Object tag = getTag(); 20174 if (tag != null) { 20175 output += " (tag=" + tag + ")"; 20176 } 20177 Log.d(VIEW_LOG_TAG, output); 20178 20179 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 20180 output = debugIndent(depth) + " FOCUSED"; 20181 Log.d(VIEW_LOG_TAG, output); 20182 } 20183 20184 output = debugIndent(depth); 20185 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 20186 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 20187 + "} "; 20188 Log.d(VIEW_LOG_TAG, output); 20189 20190 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 20191 || mPaddingBottom != 0) { 20192 output = debugIndent(depth); 20193 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 20194 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 20195 Log.d(VIEW_LOG_TAG, output); 20196 } 20197 20198 output = debugIndent(depth); 20199 output += "mMeasureWidth=" + mMeasuredWidth + 20200 " mMeasureHeight=" + mMeasuredHeight; 20201 Log.d(VIEW_LOG_TAG, output); 20202 20203 output = debugIndent(depth); 20204 if (mLayoutParams == null) { 20205 output += "BAD! no layout params"; 20206 } else { 20207 output = mLayoutParams.debug(output); 20208 } 20209 Log.d(VIEW_LOG_TAG, output); 20210 20211 output = debugIndent(depth); 20212 output += "flags={"; 20213 output += View.printFlags(mViewFlags); 20214 output += "}"; 20215 Log.d(VIEW_LOG_TAG, output); 20216 20217 output = debugIndent(depth); 20218 output += "privateFlags={"; 20219 output += View.printPrivateFlags(mPrivateFlags); 20220 output += "}"; 20221 Log.d(VIEW_LOG_TAG, output); 20222 } 20223 20224 /** 20225 * Creates a string of whitespaces used for indentation. 20226 * 20227 * @param depth the indentation level 20228 * @return a String containing (depth * 2 + 3) * 2 white spaces 20229 * 20230 * @hide 20231 */ 20232 protected static String debugIndent(int depth) { 20233 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 20234 for (int i = 0; i < (depth * 2) + 3; i++) { 20235 spaces.append(' ').append(' '); 20236 } 20237 return spaces.toString(); 20238 } 20239 20240 /** 20241 * <p>Return the offset of the widget's text baseline from the widget's top 20242 * boundary. If this widget does not support baseline alignment, this 20243 * method returns -1. </p> 20244 * 20245 * @return the offset of the baseline within the widget's bounds or -1 20246 * if baseline alignment is not supported 20247 */ 20248 @ViewDebug.ExportedProperty(category = "layout") 20249 public int getBaseline() { 20250 return -1; 20251 } 20252 20253 /** 20254 * Returns whether the view hierarchy is currently undergoing a layout pass. This 20255 * information is useful to avoid situations such as calling {@link #requestLayout()} during 20256 * a layout pass. 20257 * 20258 * @return whether the view hierarchy is currently undergoing a layout pass 20259 */ 20260 public boolean isInLayout() { 20261 ViewRootImpl viewRoot = getViewRootImpl(); 20262 return (viewRoot != null && viewRoot.isInLayout()); 20263 } 20264 20265 /** 20266 * Call this when something has changed which has invalidated the 20267 * layout of this view. This will schedule a layout pass of the view 20268 * tree. This should not be called while the view hierarchy is currently in a layout 20269 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 20270 * end of the current layout pass (and then layout will run again) or after the current 20271 * frame is drawn and the next layout occurs. 20272 * 20273 * <p>Subclasses which override this method should call the superclass method to 20274 * handle possible request-during-layout errors correctly.</p> 20275 */ 20276 @CallSuper 20277 public void requestLayout() { 20278 if (mMeasureCache != null) mMeasureCache.clear(); 20279 20280 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 20281 // Only trigger request-during-layout logic if this is the view requesting it, 20282 // not the views in its parent hierarchy 20283 ViewRootImpl viewRoot = getViewRootImpl(); 20284 if (viewRoot != null && viewRoot.isInLayout()) { 20285 if (!viewRoot.requestLayoutDuringLayout(this)) { 20286 return; 20287 } 20288 } 20289 mAttachInfo.mViewRequestingLayout = this; 20290 } 20291 20292 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20293 mPrivateFlags |= PFLAG_INVALIDATED; 20294 20295 if (mParent != null && !mParent.isLayoutRequested()) { 20296 mParent.requestLayout(); 20297 } 20298 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 20299 mAttachInfo.mViewRequestingLayout = null; 20300 } 20301 } 20302 20303 /** 20304 * Forces this view to be laid out during the next layout pass. 20305 * This method does not call requestLayout() or forceLayout() 20306 * on the parent. 20307 */ 20308 public void forceLayout() { 20309 if (mMeasureCache != null) mMeasureCache.clear(); 20310 20311 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20312 mPrivateFlags |= PFLAG_INVALIDATED; 20313 } 20314 20315 /** 20316 * <p> 20317 * This is called to find out how big a view should be. The parent 20318 * supplies constraint information in the width and height parameters. 20319 * </p> 20320 * 20321 * <p> 20322 * The actual measurement work of a view is performed in 20323 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 20324 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 20325 * </p> 20326 * 20327 * 20328 * @param widthMeasureSpec Horizontal space requirements as imposed by the 20329 * parent 20330 * @param heightMeasureSpec Vertical space requirements as imposed by the 20331 * parent 20332 * 20333 * @see #onMeasure(int, int) 20334 */ 20335 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 20336 boolean optical = isLayoutModeOptical(this); 20337 if (optical != isLayoutModeOptical(mParent)) { 20338 Insets insets = getOpticalInsets(); 20339 int oWidth = insets.left + insets.right; 20340 int oHeight = insets.top + insets.bottom; 20341 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 20342 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 20343 } 20344 20345 // Suppress sign extension for the low bytes 20346 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 20347 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 20348 20349 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 20350 20351 // Optimize layout by avoiding an extra EXACTLY pass when the view is 20352 // already measured as the correct size. In API 23 and below, this 20353 // extra pass is required to make LinearLayout re-distribute weight. 20354 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 20355 || heightMeasureSpec != mOldHeightMeasureSpec; 20356 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 20357 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 20358 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 20359 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 20360 final boolean needsLayout = specChanged 20361 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 20362 20363 if (forceLayout || needsLayout) { 20364 // first clears the measured dimension flag 20365 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 20366 20367 resolveRtlPropertiesIfNeeded(); 20368 20369 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 20370 if (cacheIndex < 0 || sIgnoreMeasureCache) { 20371 // measure ourselves, this should set the measured dimension flag back 20372 onMeasure(widthMeasureSpec, heightMeasureSpec); 20373 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20374 } else { 20375 long value = mMeasureCache.valueAt(cacheIndex); 20376 // Casting a long to int drops the high 32 bits, no mask needed 20377 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 20378 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20379 } 20380 20381 // flag not set, setMeasuredDimension() was not invoked, we raise 20382 // an exception to warn the developer 20383 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 20384 throw new IllegalStateException("View with id " + getId() + ": " 20385 + getClass().getName() + "#onMeasure() did not set the" 20386 + " measured dimension by calling" 20387 + " setMeasuredDimension()"); 20388 } 20389 20390 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 20391 } 20392 20393 mOldWidthMeasureSpec = widthMeasureSpec; 20394 mOldHeightMeasureSpec = heightMeasureSpec; 20395 20396 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 20397 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 20398 } 20399 20400 /** 20401 * <p> 20402 * Measure the view and its content to determine the measured width and the 20403 * measured height. This method is invoked by {@link #measure(int, int)} and 20404 * should be overridden by subclasses to provide accurate and efficient 20405 * measurement of their contents. 20406 * </p> 20407 * 20408 * <p> 20409 * <strong>CONTRACT:</strong> When overriding this method, you 20410 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 20411 * measured width and height of this view. Failure to do so will trigger an 20412 * <code>IllegalStateException</code>, thrown by 20413 * {@link #measure(int, int)}. Calling the superclass' 20414 * {@link #onMeasure(int, int)} is a valid use. 20415 * </p> 20416 * 20417 * <p> 20418 * The base class implementation of measure defaults to the background size, 20419 * unless a larger size is allowed by the MeasureSpec. Subclasses should 20420 * override {@link #onMeasure(int, int)} to provide better measurements of 20421 * their content. 20422 * </p> 20423 * 20424 * <p> 20425 * If this method is overridden, it is the subclass's responsibility to make 20426 * sure the measured height and width are at least the view's minimum height 20427 * and width ({@link #getSuggestedMinimumHeight()} and 20428 * {@link #getSuggestedMinimumWidth()}). 20429 * </p> 20430 * 20431 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 20432 * The requirements are encoded with 20433 * {@link android.view.View.MeasureSpec}. 20434 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 20435 * The requirements are encoded with 20436 * {@link android.view.View.MeasureSpec}. 20437 * 20438 * @see #getMeasuredWidth() 20439 * @see #getMeasuredHeight() 20440 * @see #setMeasuredDimension(int, int) 20441 * @see #getSuggestedMinimumHeight() 20442 * @see #getSuggestedMinimumWidth() 20443 * @see android.view.View.MeasureSpec#getMode(int) 20444 * @see android.view.View.MeasureSpec#getSize(int) 20445 */ 20446 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 20447 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 20448 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 20449 } 20450 20451 /** 20452 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 20453 * measured width and measured height. Failing to do so will trigger an 20454 * exception at measurement time.</p> 20455 * 20456 * @param measuredWidth The measured width of this view. May be a complex 20457 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20458 * {@link #MEASURED_STATE_TOO_SMALL}. 20459 * @param measuredHeight The measured height of this view. May be a complex 20460 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20461 * {@link #MEASURED_STATE_TOO_SMALL}. 20462 */ 20463 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 20464 boolean optical = isLayoutModeOptical(this); 20465 if (optical != isLayoutModeOptical(mParent)) { 20466 Insets insets = getOpticalInsets(); 20467 int opticalWidth = insets.left + insets.right; 20468 int opticalHeight = insets.top + insets.bottom; 20469 20470 measuredWidth += optical ? opticalWidth : -opticalWidth; 20471 measuredHeight += optical ? opticalHeight : -opticalHeight; 20472 } 20473 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 20474 } 20475 20476 /** 20477 * Sets the measured dimension without extra processing for things like optical bounds. 20478 * Useful for reapplying consistent values that have already been cooked with adjustments 20479 * for optical bounds, etc. such as those from the measurement cache. 20480 * 20481 * @param measuredWidth The measured width of this view. May be a complex 20482 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20483 * {@link #MEASURED_STATE_TOO_SMALL}. 20484 * @param measuredHeight The measured height of this view. May be a complex 20485 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20486 * {@link #MEASURED_STATE_TOO_SMALL}. 20487 */ 20488 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 20489 mMeasuredWidth = measuredWidth; 20490 mMeasuredHeight = measuredHeight; 20491 20492 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 20493 } 20494 20495 /** 20496 * Merge two states as returned by {@link #getMeasuredState()}. 20497 * @param curState The current state as returned from a view or the result 20498 * of combining multiple views. 20499 * @param newState The new view state to combine. 20500 * @return Returns a new integer reflecting the combination of the two 20501 * states. 20502 */ 20503 public static int combineMeasuredStates(int curState, int newState) { 20504 return curState | newState; 20505 } 20506 20507 /** 20508 * Version of {@link #resolveSizeAndState(int, int, int)} 20509 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 20510 */ 20511 public static int resolveSize(int size, int measureSpec) { 20512 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 20513 } 20514 20515 /** 20516 * Utility to reconcile a desired size and state, with constraints imposed 20517 * by a MeasureSpec. Will take the desired size, unless a different size 20518 * is imposed by the constraints. The returned value is a compound integer, 20519 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 20520 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 20521 * resulting size is smaller than the size the view wants to be. 20522 * 20523 * @param size How big the view wants to be. 20524 * @param measureSpec Constraints imposed by the parent. 20525 * @param childMeasuredState Size information bit mask for the view's 20526 * children. 20527 * @return Size information bit mask as defined by 20528 * {@link #MEASURED_SIZE_MASK} and 20529 * {@link #MEASURED_STATE_TOO_SMALL}. 20530 */ 20531 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 20532 final int specMode = MeasureSpec.getMode(measureSpec); 20533 final int specSize = MeasureSpec.getSize(measureSpec); 20534 final int result; 20535 switch (specMode) { 20536 case MeasureSpec.AT_MOST: 20537 if (specSize < size) { 20538 result = specSize | MEASURED_STATE_TOO_SMALL; 20539 } else { 20540 result = size; 20541 } 20542 break; 20543 case MeasureSpec.EXACTLY: 20544 result = specSize; 20545 break; 20546 case MeasureSpec.UNSPECIFIED: 20547 default: 20548 result = size; 20549 } 20550 return result | (childMeasuredState & MEASURED_STATE_MASK); 20551 } 20552 20553 /** 20554 * Utility to return a default size. Uses the supplied size if the 20555 * MeasureSpec imposed no constraints. Will get larger if allowed 20556 * by the MeasureSpec. 20557 * 20558 * @param size Default size for this view 20559 * @param measureSpec Constraints imposed by the parent 20560 * @return The size this view should be. 20561 */ 20562 public static int getDefaultSize(int size, int measureSpec) { 20563 int result = size; 20564 int specMode = MeasureSpec.getMode(measureSpec); 20565 int specSize = MeasureSpec.getSize(measureSpec); 20566 20567 switch (specMode) { 20568 case MeasureSpec.UNSPECIFIED: 20569 result = size; 20570 break; 20571 case MeasureSpec.AT_MOST: 20572 case MeasureSpec.EXACTLY: 20573 result = specSize; 20574 break; 20575 } 20576 return result; 20577 } 20578 20579 /** 20580 * Returns the suggested minimum height that the view should use. This 20581 * returns the maximum of the view's minimum height 20582 * and the background's minimum height 20583 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 20584 * <p> 20585 * When being used in {@link #onMeasure(int, int)}, the caller should still 20586 * ensure the returned height is within the requirements of the parent. 20587 * 20588 * @return The suggested minimum height of the view. 20589 */ 20590 protected int getSuggestedMinimumHeight() { 20591 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 20592 20593 } 20594 20595 /** 20596 * Returns the suggested minimum width that the view should use. This 20597 * returns the maximum of the view's minimum width 20598 * and the background's minimum width 20599 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 20600 * <p> 20601 * When being used in {@link #onMeasure(int, int)}, the caller should still 20602 * ensure the returned width is within the requirements of the parent. 20603 * 20604 * @return The suggested minimum width of the view. 20605 */ 20606 protected int getSuggestedMinimumWidth() { 20607 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 20608 } 20609 20610 /** 20611 * Returns the minimum height of the view. 20612 * 20613 * @return the minimum height the view will try to be, in pixels 20614 * 20615 * @see #setMinimumHeight(int) 20616 * 20617 * @attr ref android.R.styleable#View_minHeight 20618 */ 20619 public int getMinimumHeight() { 20620 return mMinHeight; 20621 } 20622 20623 /** 20624 * Sets the minimum height of the view. It is not guaranteed the view will 20625 * be able to achieve this minimum height (for example, if its parent layout 20626 * constrains it with less available height). 20627 * 20628 * @param minHeight The minimum height the view will try to be, in pixels 20629 * 20630 * @see #getMinimumHeight() 20631 * 20632 * @attr ref android.R.styleable#View_minHeight 20633 */ 20634 @RemotableViewMethod 20635 public void setMinimumHeight(int minHeight) { 20636 mMinHeight = minHeight; 20637 requestLayout(); 20638 } 20639 20640 /** 20641 * Returns the minimum width of the view. 20642 * 20643 * @return the minimum width the view will try to be, in pixels 20644 * 20645 * @see #setMinimumWidth(int) 20646 * 20647 * @attr ref android.R.styleable#View_minWidth 20648 */ 20649 public int getMinimumWidth() { 20650 return mMinWidth; 20651 } 20652 20653 /** 20654 * Sets the minimum width of the view. It is not guaranteed the view will 20655 * be able to achieve this minimum width (for example, if its parent layout 20656 * constrains it with less available width). 20657 * 20658 * @param minWidth The minimum width the view will try to be, in pixels 20659 * 20660 * @see #getMinimumWidth() 20661 * 20662 * @attr ref android.R.styleable#View_minWidth 20663 */ 20664 public void setMinimumWidth(int minWidth) { 20665 mMinWidth = minWidth; 20666 requestLayout(); 20667 20668 } 20669 20670 /** 20671 * Get the animation currently associated with this view. 20672 * 20673 * @return The animation that is currently playing or 20674 * scheduled to play for this view. 20675 */ 20676 public Animation getAnimation() { 20677 return mCurrentAnimation; 20678 } 20679 20680 /** 20681 * Start the specified animation now. 20682 * 20683 * @param animation the animation to start now 20684 */ 20685 public void startAnimation(Animation animation) { 20686 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 20687 setAnimation(animation); 20688 invalidateParentCaches(); 20689 invalidate(true); 20690 } 20691 20692 /** 20693 * Cancels any animations for this view. 20694 */ 20695 public void clearAnimation() { 20696 if (mCurrentAnimation != null) { 20697 mCurrentAnimation.detach(); 20698 } 20699 mCurrentAnimation = null; 20700 invalidateParentIfNeeded(); 20701 } 20702 20703 /** 20704 * Sets the next animation to play for this view. 20705 * If you want the animation to play immediately, use 20706 * {@link #startAnimation(android.view.animation.Animation)} instead. 20707 * This method provides allows fine-grained 20708 * control over the start time and invalidation, but you 20709 * must make sure that 1) the animation has a start time set, and 20710 * 2) the view's parent (which controls animations on its children) 20711 * will be invalidated when the animation is supposed to 20712 * start. 20713 * 20714 * @param animation The next animation, or null. 20715 */ 20716 public void setAnimation(Animation animation) { 20717 mCurrentAnimation = animation; 20718 20719 if (animation != null) { 20720 // If the screen is off assume the animation start time is now instead of 20721 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 20722 // would cause the animation to start when the screen turns back on 20723 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 20724 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 20725 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 20726 } 20727 animation.reset(); 20728 } 20729 } 20730 20731 /** 20732 * Invoked by a parent ViewGroup to notify the start of the animation 20733 * currently associated with this view. If you override this method, 20734 * always call super.onAnimationStart(); 20735 * 20736 * @see #setAnimation(android.view.animation.Animation) 20737 * @see #getAnimation() 20738 */ 20739 @CallSuper 20740 protected void onAnimationStart() { 20741 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 20742 } 20743 20744 /** 20745 * Invoked by a parent ViewGroup to notify the end of the animation 20746 * currently associated with this view. If you override this method, 20747 * always call super.onAnimationEnd(); 20748 * 20749 * @see #setAnimation(android.view.animation.Animation) 20750 * @see #getAnimation() 20751 */ 20752 @CallSuper 20753 protected void onAnimationEnd() { 20754 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 20755 } 20756 20757 /** 20758 * Invoked if there is a Transform that involves alpha. Subclass that can 20759 * draw themselves with the specified alpha should return true, and then 20760 * respect that alpha when their onDraw() is called. If this returns false 20761 * then the view may be redirected to draw into an offscreen buffer to 20762 * fulfill the request, which will look fine, but may be slower than if the 20763 * subclass handles it internally. The default implementation returns false. 20764 * 20765 * @param alpha The alpha (0..255) to apply to the view's drawing 20766 * @return true if the view can draw with the specified alpha. 20767 */ 20768 protected boolean onSetAlpha(int alpha) { 20769 return false; 20770 } 20771 20772 /** 20773 * This is used by the RootView to perform an optimization when 20774 * the view hierarchy contains one or several SurfaceView. 20775 * SurfaceView is always considered transparent, but its children are not, 20776 * therefore all View objects remove themselves from the global transparent 20777 * region (passed as a parameter to this function). 20778 * 20779 * @param region The transparent region for this ViewAncestor (window). 20780 * 20781 * @return Returns true if the effective visibility of the view at this 20782 * point is opaque, regardless of the transparent region; returns false 20783 * if it is possible for underlying windows to be seen behind the view. 20784 * 20785 * {@hide} 20786 */ 20787 public boolean gatherTransparentRegion(Region region) { 20788 final AttachInfo attachInfo = mAttachInfo; 20789 if (region != null && attachInfo != null) { 20790 final int pflags = mPrivateFlags; 20791 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 20792 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 20793 // remove it from the transparent region. 20794 final int[] location = attachInfo.mTransparentLocation; 20795 getLocationInWindow(location); 20796 // When a view has Z value, then it will be better to leave some area below the view 20797 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 20798 // the bottom part needs more offset than the left, top and right parts due to the 20799 // spot light effects. 20800 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 20801 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 20802 location[0] + mRight - mLeft + shadowOffset, 20803 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 20804 } else { 20805 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 20806 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 20807 // the background drawable's non-transparent parts from this transparent region. 20808 applyDrawableToTransparentRegion(mBackground, region); 20809 } 20810 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20811 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 20812 // Similarly, we remove the foreground drawable's non-transparent parts. 20813 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 20814 } 20815 } 20816 } 20817 return true; 20818 } 20819 20820 /** 20821 * Play a sound effect for this view. 20822 * 20823 * <p>The framework will play sound effects for some built in actions, such as 20824 * clicking, but you may wish to play these effects in your widget, 20825 * for instance, for internal navigation. 20826 * 20827 * <p>The sound effect will only be played if sound effects are enabled by the user, and 20828 * {@link #isSoundEffectsEnabled()} is true. 20829 * 20830 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 20831 */ 20832 public void playSoundEffect(int soundConstant) { 20833 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 20834 return; 20835 } 20836 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 20837 } 20838 20839 /** 20840 * BZZZTT!!1! 20841 * 20842 * <p>Provide haptic feedback to the user for this view. 20843 * 20844 * <p>The framework will provide haptic feedback for some built in actions, 20845 * such as long presses, but you may wish to provide feedback for your 20846 * own widget. 20847 * 20848 * <p>The feedback will only be performed if 20849 * {@link #isHapticFeedbackEnabled()} is true. 20850 * 20851 * @param feedbackConstant One of the constants defined in 20852 * {@link HapticFeedbackConstants} 20853 */ 20854 public boolean performHapticFeedback(int feedbackConstant) { 20855 return performHapticFeedback(feedbackConstant, 0); 20856 } 20857 20858 /** 20859 * BZZZTT!!1! 20860 * 20861 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 20862 * 20863 * @param feedbackConstant One of the constants defined in 20864 * {@link HapticFeedbackConstants} 20865 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 20866 */ 20867 public boolean performHapticFeedback(int feedbackConstant, int flags) { 20868 if (mAttachInfo == null) { 20869 return false; 20870 } 20871 //noinspection SimplifiableIfStatement 20872 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 20873 && !isHapticFeedbackEnabled()) { 20874 return false; 20875 } 20876 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 20877 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 20878 } 20879 20880 /** 20881 * Request that the visibility of the status bar or other screen/window 20882 * decorations be changed. 20883 * 20884 * <p>This method is used to put the over device UI into temporary modes 20885 * where the user's attention is focused more on the application content, 20886 * by dimming or hiding surrounding system affordances. This is typically 20887 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 20888 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 20889 * to be placed behind the action bar (and with these flags other system 20890 * affordances) so that smooth transitions between hiding and showing them 20891 * can be done. 20892 * 20893 * <p>Two representative examples of the use of system UI visibility is 20894 * implementing a content browsing application (like a magazine reader) 20895 * and a video playing application. 20896 * 20897 * <p>The first code shows a typical implementation of a View in a content 20898 * browsing application. In this implementation, the application goes 20899 * into a content-oriented mode by hiding the status bar and action bar, 20900 * and putting the navigation elements into lights out mode. The user can 20901 * then interact with content while in this mode. Such an application should 20902 * provide an easy way for the user to toggle out of the mode (such as to 20903 * check information in the status bar or access notifications). In the 20904 * implementation here, this is done simply by tapping on the content. 20905 * 20906 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 20907 * content} 20908 * 20909 * <p>This second code sample shows a typical implementation of a View 20910 * in a video playing application. In this situation, while the video is 20911 * playing the application would like to go into a complete full-screen mode, 20912 * to use as much of the display as possible for the video. When in this state 20913 * the user can not interact with the application; the system intercepts 20914 * touching on the screen to pop the UI out of full screen mode. See 20915 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 20916 * 20917 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 20918 * content} 20919 * 20920 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 20921 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 20922 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 20923 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 20924 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 20925 */ 20926 public void setSystemUiVisibility(int visibility) { 20927 if (visibility != mSystemUiVisibility) { 20928 mSystemUiVisibility = visibility; 20929 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 20930 mParent.recomputeViewAttributes(this); 20931 } 20932 } 20933 } 20934 20935 /** 20936 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 20937 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 20938 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 20939 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 20940 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 20941 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 20942 */ 20943 public int getSystemUiVisibility() { 20944 return mSystemUiVisibility; 20945 } 20946 20947 /** 20948 * Returns the current system UI visibility that is currently set for 20949 * the entire window. This is the combination of the 20950 * {@link #setSystemUiVisibility(int)} values supplied by all of the 20951 * views in the window. 20952 */ 20953 public int getWindowSystemUiVisibility() { 20954 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 20955 } 20956 20957 /** 20958 * Override to find out when the window's requested system UI visibility 20959 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 20960 * This is different from the callbacks received through 20961 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 20962 * in that this is only telling you about the local request of the window, 20963 * not the actual values applied by the system. 20964 */ 20965 public void onWindowSystemUiVisibilityChanged(int visible) { 20966 } 20967 20968 /** 20969 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 20970 * the view hierarchy. 20971 */ 20972 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 20973 onWindowSystemUiVisibilityChanged(visible); 20974 } 20975 20976 /** 20977 * Set a listener to receive callbacks when the visibility of the system bar changes. 20978 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 20979 */ 20980 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 20981 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 20982 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 20983 mParent.recomputeViewAttributes(this); 20984 } 20985 } 20986 20987 /** 20988 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 20989 * the view hierarchy. 20990 */ 20991 public void dispatchSystemUiVisibilityChanged(int visibility) { 20992 ListenerInfo li = mListenerInfo; 20993 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 20994 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 20995 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 20996 } 20997 } 20998 20999 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 21000 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 21001 if (val != mSystemUiVisibility) { 21002 setSystemUiVisibility(val); 21003 return true; 21004 } 21005 return false; 21006 } 21007 21008 /** @hide */ 21009 public void setDisabledSystemUiVisibility(int flags) { 21010 if (mAttachInfo != null) { 21011 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 21012 mAttachInfo.mDisabledSystemUiVisibility = flags; 21013 if (mParent != null) { 21014 mParent.recomputeViewAttributes(this); 21015 } 21016 } 21017 } 21018 } 21019 21020 /** 21021 * Creates an image that the system displays during the drag and drop 21022 * operation. This is called a "drag shadow". The default implementation 21023 * for a DragShadowBuilder based on a View returns an image that has exactly the same 21024 * appearance as the given View. The default also positions the center of the drag shadow 21025 * directly under the touch point. If no View is provided (the constructor with no parameters 21026 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 21027 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 21028 * default is an invisible drag shadow. 21029 * <p> 21030 * You are not required to use the View you provide to the constructor as the basis of the 21031 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 21032 * anything you want as the drag shadow. 21033 * </p> 21034 * <p> 21035 * You pass a DragShadowBuilder object to the system when you start the drag. The system 21036 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 21037 * size and position of the drag shadow. It uses this data to construct a 21038 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 21039 * so that your application can draw the shadow image in the Canvas. 21040 * </p> 21041 * 21042 * <div class="special reference"> 21043 * <h3>Developer Guides</h3> 21044 * <p>For a guide to implementing drag and drop features, read the 21045 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 21046 * </div> 21047 */ 21048 public static class DragShadowBuilder { 21049 private final WeakReference<View> mView; 21050 21051 /** 21052 * Constructs a shadow image builder based on a View. By default, the resulting drag 21053 * shadow will have the same appearance and dimensions as the View, with the touch point 21054 * over the center of the View. 21055 * @param view A View. Any View in scope can be used. 21056 */ 21057 public DragShadowBuilder(View view) { 21058 mView = new WeakReference<View>(view); 21059 } 21060 21061 /** 21062 * Construct a shadow builder object with no associated View. This 21063 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 21064 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 21065 * to supply the drag shadow's dimensions and appearance without 21066 * reference to any View object. If they are not overridden, then the result is an 21067 * invisible drag shadow. 21068 */ 21069 public DragShadowBuilder() { 21070 mView = new WeakReference<View>(null); 21071 } 21072 21073 /** 21074 * Returns the View object that had been passed to the 21075 * {@link #View.DragShadowBuilder(View)} 21076 * constructor. If that View parameter was {@code null} or if the 21077 * {@link #View.DragShadowBuilder()} 21078 * constructor was used to instantiate the builder object, this method will return 21079 * null. 21080 * 21081 * @return The View object associate with this builder object. 21082 */ 21083 @SuppressWarnings({"JavadocReference"}) 21084 final public View getView() { 21085 return mView.get(); 21086 } 21087 21088 /** 21089 * Provides the metrics for the shadow image. These include the dimensions of 21090 * the shadow image, and the point within that shadow that should 21091 * be centered under the touch location while dragging. 21092 * <p> 21093 * The default implementation sets the dimensions of the shadow to be the 21094 * same as the dimensions of the View itself and centers the shadow under 21095 * the touch point. 21096 * </p> 21097 * 21098 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 21099 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 21100 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 21101 * image. 21102 * 21103 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 21104 * shadow image that should be underneath the touch point during the drag and drop 21105 * operation. Your application must set {@link android.graphics.Point#x} to the 21106 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 21107 */ 21108 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 21109 final View view = mView.get(); 21110 if (view != null) { 21111 outShadowSize.set(view.getWidth(), view.getHeight()); 21112 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 21113 } else { 21114 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 21115 } 21116 } 21117 21118 /** 21119 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 21120 * based on the dimensions it received from the 21121 * {@link #onProvideShadowMetrics(Point, Point)} callback. 21122 * 21123 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 21124 */ 21125 public void onDrawShadow(Canvas canvas) { 21126 final View view = mView.get(); 21127 if (view != null) { 21128 view.draw(canvas); 21129 } else { 21130 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 21131 } 21132 } 21133 } 21134 21135 /** 21136 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 21137 * startDragAndDrop()} for newer platform versions. 21138 */ 21139 @Deprecated 21140 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 21141 Object myLocalState, int flags) { 21142 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 21143 } 21144 21145 /** 21146 * Starts a drag and drop operation. When your application calls this method, it passes a 21147 * {@link android.view.View.DragShadowBuilder} object to the system. The 21148 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 21149 * to get metrics for the drag shadow, and then calls the object's 21150 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 21151 * <p> 21152 * Once the system has the drag shadow, it begins the drag and drop operation by sending 21153 * drag events to all the View objects in your application that are currently visible. It does 21154 * this either by calling the View object's drag listener (an implementation of 21155 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 21156 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 21157 * Both are passed a {@link android.view.DragEvent} object that has a 21158 * {@link android.view.DragEvent#getAction()} value of 21159 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 21160 * </p> 21161 * <p> 21162 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 21163 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 21164 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 21165 * to the View the user selected for dragging. 21166 * </p> 21167 * @param data A {@link android.content.ClipData} object pointing to the data to be 21168 * transferred by the drag and drop operation. 21169 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21170 * drag shadow. 21171 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 21172 * drop operation. When dispatching drag events to views in the same activity this object 21173 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 21174 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 21175 * will return null). 21176 * <p> 21177 * myLocalState is a lightweight mechanism for the sending information from the dragged View 21178 * to the target Views. For example, it can contain flags that differentiate between a 21179 * a copy operation and a move operation. 21180 * </p> 21181 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 21182 * flags, or any combination of the following: 21183 * <ul> 21184 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 21185 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 21186 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 21187 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 21188 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 21189 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 21190 * </ul> 21191 * @return {@code true} if the method completes successfully, or 21192 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 21193 * do a drag, and so no drag operation is in progress. 21194 */ 21195 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 21196 Object myLocalState, int flags) { 21197 if (ViewDebug.DEBUG_DRAG) { 21198 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 21199 } 21200 if (mAttachInfo == null) { 21201 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 21202 return false; 21203 } 21204 21205 if (data != null) { 21206 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 21207 } 21208 21209 boolean okay = false; 21210 21211 Point shadowSize = new Point(); 21212 Point shadowTouchPoint = new Point(); 21213 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 21214 21215 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 21216 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 21217 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 21218 } 21219 21220 if (ViewDebug.DEBUG_DRAG) { 21221 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 21222 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 21223 } 21224 if (mAttachInfo.mDragSurface != null) { 21225 mAttachInfo.mDragSurface.release(); 21226 } 21227 mAttachInfo.mDragSurface = new Surface(); 21228 try { 21229 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 21230 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 21231 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 21232 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 21233 if (mAttachInfo.mDragToken != null) { 21234 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21235 try { 21236 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21237 shadowBuilder.onDrawShadow(canvas); 21238 } finally { 21239 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21240 } 21241 21242 final ViewRootImpl root = getViewRootImpl(); 21243 21244 // Cache the local state object for delivery with DragEvents 21245 root.setLocalDragState(myLocalState); 21246 21247 // repurpose 'shadowSize' for the last touch point 21248 root.getLastTouchPoint(shadowSize); 21249 21250 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 21251 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 21252 shadowTouchPoint.x, shadowTouchPoint.y, data); 21253 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 21254 } 21255 } catch (Exception e) { 21256 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 21257 mAttachInfo.mDragSurface.destroy(); 21258 mAttachInfo.mDragSurface = null; 21259 } 21260 21261 return okay; 21262 } 21263 21264 /** 21265 * Cancels an ongoing drag and drop operation. 21266 * <p> 21267 * A {@link android.view.DragEvent} object with 21268 * {@link android.view.DragEvent#getAction()} value of 21269 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 21270 * {@link android.view.DragEvent#getResult()} value of {@code false} 21271 * will be sent to every 21272 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 21273 * even if they are not currently visible. 21274 * </p> 21275 * <p> 21276 * This method can be called on any View in the same window as the View on which 21277 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 21278 * was called. 21279 * </p> 21280 */ 21281 public final void cancelDragAndDrop() { 21282 if (ViewDebug.DEBUG_DRAG) { 21283 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 21284 } 21285 if (mAttachInfo == null) { 21286 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 21287 return; 21288 } 21289 if (mAttachInfo.mDragToken != null) { 21290 try { 21291 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 21292 } catch (Exception e) { 21293 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 21294 } 21295 mAttachInfo.mDragToken = null; 21296 } else { 21297 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 21298 } 21299 } 21300 21301 /** 21302 * Updates the drag shadow for the ongoing drag and drop operation. 21303 * 21304 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21305 * new drag shadow. 21306 */ 21307 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 21308 if (ViewDebug.DEBUG_DRAG) { 21309 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 21310 } 21311 if (mAttachInfo == null) { 21312 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 21313 return; 21314 } 21315 if (mAttachInfo.mDragToken != null) { 21316 try { 21317 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21318 try { 21319 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21320 shadowBuilder.onDrawShadow(canvas); 21321 } finally { 21322 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21323 } 21324 } catch (Exception e) { 21325 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 21326 } 21327 } else { 21328 Log.e(VIEW_LOG_TAG, "No active drag"); 21329 } 21330 } 21331 21332 /** 21333 * Starts a move from {startX, startY}, the amount of the movement will be the offset 21334 * between {startX, startY} and the new cursor positon. 21335 * @param startX horizontal coordinate where the move started. 21336 * @param startY vertical coordinate where the move started. 21337 * @return whether moving was started successfully. 21338 * @hide 21339 */ 21340 public final boolean startMovingTask(float startX, float startY) { 21341 if (ViewDebug.DEBUG_POSITIONING) { 21342 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 21343 } 21344 try { 21345 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 21346 } catch (RemoteException e) { 21347 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 21348 } 21349 return false; 21350 } 21351 21352 /** 21353 * Handles drag events sent by the system following a call to 21354 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 21355 * startDragAndDrop()}. 21356 *<p> 21357 * When the system calls this method, it passes a 21358 * {@link android.view.DragEvent} object. A call to 21359 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 21360 * in DragEvent. The method uses these to determine what is happening in the drag and drop 21361 * operation. 21362 * @param event The {@link android.view.DragEvent} sent by the system. 21363 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 21364 * in DragEvent, indicating the type of drag event represented by this object. 21365 * @return {@code true} if the method was successful, otherwise {@code false}. 21366 * <p> 21367 * The method should return {@code true} in response to an action type of 21368 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 21369 * operation. 21370 * </p> 21371 * <p> 21372 * The method should also return {@code true} in response to an action type of 21373 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 21374 * {@code false} if it didn't. 21375 * </p> 21376 * <p> 21377 * For all other events, the return value is ignored. 21378 * </p> 21379 */ 21380 public boolean onDragEvent(DragEvent event) { 21381 return false; 21382 } 21383 21384 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 21385 boolean dispatchDragEnterExitInPreN(DragEvent event) { 21386 return callDragEventHandler(event); 21387 } 21388 21389 /** 21390 * Detects if this View is enabled and has a drag event listener. 21391 * If both are true, then it calls the drag event listener with the 21392 * {@link android.view.DragEvent} it received. If the drag event listener returns 21393 * {@code true}, then dispatchDragEvent() returns {@code true}. 21394 * <p> 21395 * For all other cases, the method calls the 21396 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 21397 * method and returns its result. 21398 * </p> 21399 * <p> 21400 * This ensures that a drag event is always consumed, even if the View does not have a drag 21401 * event listener. However, if the View has a listener and the listener returns true, then 21402 * onDragEvent() is not called. 21403 * </p> 21404 */ 21405 public boolean dispatchDragEvent(DragEvent event) { 21406 event.mEventHandlerWasCalled = true; 21407 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 21408 event.mAction == DragEvent.ACTION_DROP) { 21409 // About to deliver an event with coordinates to this view. Notify that now this view 21410 // has drag focus. This will send exit/enter events as needed. 21411 getViewRootImpl().setDragFocus(this, event); 21412 } 21413 return callDragEventHandler(event); 21414 } 21415 21416 final boolean callDragEventHandler(DragEvent event) { 21417 final boolean result; 21418 21419 ListenerInfo li = mListenerInfo; 21420 //noinspection SimplifiableIfStatement 21421 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 21422 && li.mOnDragListener.onDrag(this, event)) { 21423 result = true; 21424 } else { 21425 result = onDragEvent(event); 21426 } 21427 21428 switch (event.mAction) { 21429 case DragEvent.ACTION_DRAG_ENTERED: { 21430 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 21431 refreshDrawableState(); 21432 } break; 21433 case DragEvent.ACTION_DRAG_EXITED: { 21434 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 21435 refreshDrawableState(); 21436 } break; 21437 case DragEvent.ACTION_DRAG_ENDED: { 21438 mPrivateFlags2 &= ~View.DRAG_MASK; 21439 refreshDrawableState(); 21440 } break; 21441 } 21442 21443 return result; 21444 } 21445 21446 boolean canAcceptDrag() { 21447 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 21448 } 21449 21450 /** 21451 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 21452 * it is ever exposed at all. 21453 * @hide 21454 */ 21455 public void onCloseSystemDialogs(String reason) { 21456 } 21457 21458 /** 21459 * Given a Drawable whose bounds have been set to draw into this view, 21460 * update a Region being computed for 21461 * {@link #gatherTransparentRegion(android.graphics.Region)} so 21462 * that any non-transparent parts of the Drawable are removed from the 21463 * given transparent region. 21464 * 21465 * @param dr The Drawable whose transparency is to be applied to the region. 21466 * @param region A Region holding the current transparency information, 21467 * where any parts of the region that are set are considered to be 21468 * transparent. On return, this region will be modified to have the 21469 * transparency information reduced by the corresponding parts of the 21470 * Drawable that are not transparent. 21471 * {@hide} 21472 */ 21473 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 21474 if (DBG) { 21475 Log.i("View", "Getting transparent region for: " + this); 21476 } 21477 final Region r = dr.getTransparentRegion(); 21478 final Rect db = dr.getBounds(); 21479 final AttachInfo attachInfo = mAttachInfo; 21480 if (r != null && attachInfo != null) { 21481 final int w = getRight()-getLeft(); 21482 final int h = getBottom()-getTop(); 21483 if (db.left > 0) { 21484 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 21485 r.op(0, 0, db.left, h, Region.Op.UNION); 21486 } 21487 if (db.right < w) { 21488 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 21489 r.op(db.right, 0, w, h, Region.Op.UNION); 21490 } 21491 if (db.top > 0) { 21492 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 21493 r.op(0, 0, w, db.top, Region.Op.UNION); 21494 } 21495 if (db.bottom < h) { 21496 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 21497 r.op(0, db.bottom, w, h, Region.Op.UNION); 21498 } 21499 final int[] location = attachInfo.mTransparentLocation; 21500 getLocationInWindow(location); 21501 r.translate(location[0], location[1]); 21502 region.op(r, Region.Op.INTERSECT); 21503 } else { 21504 region.op(db, Region.Op.DIFFERENCE); 21505 } 21506 } 21507 21508 private void checkForLongClick(int delayOffset, float x, float y) { 21509 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 21510 mHasPerformedLongPress = false; 21511 21512 if (mPendingCheckForLongPress == null) { 21513 mPendingCheckForLongPress = new CheckForLongPress(); 21514 } 21515 mPendingCheckForLongPress.setAnchor(x, y); 21516 mPendingCheckForLongPress.rememberWindowAttachCount(); 21517 mPendingCheckForLongPress.rememberPressedState(); 21518 postDelayed(mPendingCheckForLongPress, 21519 ViewConfiguration.getLongPressTimeout() - delayOffset); 21520 } 21521 } 21522 21523 /** 21524 * Inflate a view from an XML resource. This convenience method wraps the {@link 21525 * LayoutInflater} class, which provides a full range of options for view inflation. 21526 * 21527 * @param context The Context object for your activity or application. 21528 * @param resource The resource ID to inflate 21529 * @param root A view group that will be the parent. Used to properly inflate the 21530 * layout_* parameters. 21531 * @see LayoutInflater 21532 */ 21533 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 21534 LayoutInflater factory = LayoutInflater.from(context); 21535 return factory.inflate(resource, root); 21536 } 21537 21538 /** 21539 * Scroll the view with standard behavior for scrolling beyond the normal 21540 * content boundaries. Views that call this method should override 21541 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 21542 * results of an over-scroll operation. 21543 * 21544 * Views can use this method to handle any touch or fling-based scrolling. 21545 * 21546 * @param deltaX Change in X in pixels 21547 * @param deltaY Change in Y in pixels 21548 * @param scrollX Current X scroll value in pixels before applying deltaX 21549 * @param scrollY Current Y scroll value in pixels before applying deltaY 21550 * @param scrollRangeX Maximum content scroll range along the X axis 21551 * @param scrollRangeY Maximum content scroll range along the Y axis 21552 * @param maxOverScrollX Number of pixels to overscroll by in either direction 21553 * along the X axis. 21554 * @param maxOverScrollY Number of pixels to overscroll by in either direction 21555 * along the Y axis. 21556 * @param isTouchEvent true if this scroll operation is the result of a touch event. 21557 * @return true if scrolling was clamped to an over-scroll boundary along either 21558 * axis, false otherwise. 21559 */ 21560 @SuppressWarnings({"UnusedParameters"}) 21561 protected boolean overScrollBy(int deltaX, int deltaY, 21562 int scrollX, int scrollY, 21563 int scrollRangeX, int scrollRangeY, 21564 int maxOverScrollX, int maxOverScrollY, 21565 boolean isTouchEvent) { 21566 final int overScrollMode = mOverScrollMode; 21567 final boolean canScrollHorizontal = 21568 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 21569 final boolean canScrollVertical = 21570 computeVerticalScrollRange() > computeVerticalScrollExtent(); 21571 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 21572 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 21573 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 21574 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 21575 21576 int newScrollX = scrollX + deltaX; 21577 if (!overScrollHorizontal) { 21578 maxOverScrollX = 0; 21579 } 21580 21581 int newScrollY = scrollY + deltaY; 21582 if (!overScrollVertical) { 21583 maxOverScrollY = 0; 21584 } 21585 21586 // Clamp values if at the limits and record 21587 final int left = -maxOverScrollX; 21588 final int right = maxOverScrollX + scrollRangeX; 21589 final int top = -maxOverScrollY; 21590 final int bottom = maxOverScrollY + scrollRangeY; 21591 21592 boolean clampedX = false; 21593 if (newScrollX > right) { 21594 newScrollX = right; 21595 clampedX = true; 21596 } else if (newScrollX < left) { 21597 newScrollX = left; 21598 clampedX = true; 21599 } 21600 21601 boolean clampedY = false; 21602 if (newScrollY > bottom) { 21603 newScrollY = bottom; 21604 clampedY = true; 21605 } else if (newScrollY < top) { 21606 newScrollY = top; 21607 clampedY = true; 21608 } 21609 21610 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 21611 21612 return clampedX || clampedY; 21613 } 21614 21615 /** 21616 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 21617 * respond to the results of an over-scroll operation. 21618 * 21619 * @param scrollX New X scroll value in pixels 21620 * @param scrollY New Y scroll value in pixels 21621 * @param clampedX True if scrollX was clamped to an over-scroll boundary 21622 * @param clampedY True if scrollY was clamped to an over-scroll boundary 21623 */ 21624 protected void onOverScrolled(int scrollX, int scrollY, 21625 boolean clampedX, boolean clampedY) { 21626 // Intentionally empty. 21627 } 21628 21629 /** 21630 * Returns the over-scroll mode for this view. The result will be 21631 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21632 * (allow over-scrolling only if the view content is larger than the container), 21633 * or {@link #OVER_SCROLL_NEVER}. 21634 * 21635 * @return This view's over-scroll mode. 21636 */ 21637 public int getOverScrollMode() { 21638 return mOverScrollMode; 21639 } 21640 21641 /** 21642 * Set the over-scroll mode for this view. Valid over-scroll modes are 21643 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21644 * (allow over-scrolling only if the view content is larger than the container), 21645 * or {@link #OVER_SCROLL_NEVER}. 21646 * 21647 * Setting the over-scroll mode of a view will have an effect only if the 21648 * view is capable of scrolling. 21649 * 21650 * @param overScrollMode The new over-scroll mode for this view. 21651 */ 21652 public void setOverScrollMode(int overScrollMode) { 21653 if (overScrollMode != OVER_SCROLL_ALWAYS && 21654 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 21655 overScrollMode != OVER_SCROLL_NEVER) { 21656 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 21657 } 21658 mOverScrollMode = overScrollMode; 21659 } 21660 21661 /** 21662 * Enable or disable nested scrolling for this view. 21663 * 21664 * <p>If this property is set to true the view will be permitted to initiate nested 21665 * scrolling operations with a compatible parent view in the current hierarchy. If this 21666 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 21667 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 21668 * the nested scroll.</p> 21669 * 21670 * @param enabled true to enable nested scrolling, false to disable 21671 * 21672 * @see #isNestedScrollingEnabled() 21673 */ 21674 public void setNestedScrollingEnabled(boolean enabled) { 21675 if (enabled) { 21676 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 21677 } else { 21678 stopNestedScroll(); 21679 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 21680 } 21681 } 21682 21683 /** 21684 * Returns true if nested scrolling is enabled for this view. 21685 * 21686 * <p>If nested scrolling is enabled and this View class implementation supports it, 21687 * this view will act as a nested scrolling child view when applicable, forwarding data 21688 * about the scroll operation in progress to a compatible and cooperating nested scrolling 21689 * parent.</p> 21690 * 21691 * @return true if nested scrolling is enabled 21692 * 21693 * @see #setNestedScrollingEnabled(boolean) 21694 */ 21695 public boolean isNestedScrollingEnabled() { 21696 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 21697 PFLAG3_NESTED_SCROLLING_ENABLED; 21698 } 21699 21700 /** 21701 * Begin a nestable scroll operation along the given axes. 21702 * 21703 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 21704 * 21705 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 21706 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 21707 * In the case of touch scrolling the nested scroll will be terminated automatically in 21708 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 21709 * In the event of programmatic scrolling the caller must explicitly call 21710 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 21711 * 21712 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 21713 * If it returns false the caller may ignore the rest of this contract until the next scroll. 21714 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 21715 * 21716 * <p>At each incremental step of the scroll the caller should invoke 21717 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 21718 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 21719 * parent at least partially consumed the scroll and the caller should adjust the amount it 21720 * scrolls by.</p> 21721 * 21722 * <p>After applying the remainder of the scroll delta the caller should invoke 21723 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 21724 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 21725 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 21726 * </p> 21727 * 21728 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 21729 * {@link #SCROLL_AXIS_VERTICAL}. 21730 * @return true if a cooperative parent was found and nested scrolling has been enabled for 21731 * the current gesture. 21732 * 21733 * @see #stopNestedScroll() 21734 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21735 * @see #dispatchNestedScroll(int, int, int, int, int[]) 21736 */ 21737 public boolean startNestedScroll(int axes) { 21738 if (hasNestedScrollingParent()) { 21739 // Already in progress 21740 return true; 21741 } 21742 if (isNestedScrollingEnabled()) { 21743 ViewParent p = getParent(); 21744 View child = this; 21745 while (p != null) { 21746 try { 21747 if (p.onStartNestedScroll(child, this, axes)) { 21748 mNestedScrollingParent = p; 21749 p.onNestedScrollAccepted(child, this, axes); 21750 return true; 21751 } 21752 } catch (AbstractMethodError e) { 21753 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 21754 "method onStartNestedScroll", e); 21755 // Allow the search upward to continue 21756 } 21757 if (p instanceof View) { 21758 child = (View) p; 21759 } 21760 p = p.getParent(); 21761 } 21762 } 21763 return false; 21764 } 21765 21766 /** 21767 * Stop a nested scroll in progress. 21768 * 21769 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 21770 * 21771 * @see #startNestedScroll(int) 21772 */ 21773 public void stopNestedScroll() { 21774 if (mNestedScrollingParent != null) { 21775 mNestedScrollingParent.onStopNestedScroll(this); 21776 mNestedScrollingParent = null; 21777 } 21778 } 21779 21780 /** 21781 * Returns true if this view has a nested scrolling parent. 21782 * 21783 * <p>The presence of a nested scrolling parent indicates that this view has initiated 21784 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 21785 * 21786 * @return whether this view has a nested scrolling parent 21787 */ 21788 public boolean hasNestedScrollingParent() { 21789 return mNestedScrollingParent != null; 21790 } 21791 21792 /** 21793 * Dispatch one step of a nested scroll in progress. 21794 * 21795 * <p>Implementations of views that support nested scrolling should call this to report 21796 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 21797 * is not currently in progress or nested scrolling is not 21798 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 21799 * 21800 * <p>Compatible View implementations should also call 21801 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 21802 * consuming a component of the scroll event themselves.</p> 21803 * 21804 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 21805 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 21806 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 21807 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 21808 * @param offsetInWindow Optional. If not null, on return this will contain the offset 21809 * in local view coordinates of this view from before this operation 21810 * to after it completes. View implementations may use this to adjust 21811 * expected input coordinate tracking. 21812 * @return true if the event was dispatched, false if it could not be dispatched. 21813 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21814 */ 21815 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 21816 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 21817 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21818 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 21819 int startX = 0; 21820 int startY = 0; 21821 if (offsetInWindow != null) { 21822 getLocationInWindow(offsetInWindow); 21823 startX = offsetInWindow[0]; 21824 startY = offsetInWindow[1]; 21825 } 21826 21827 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 21828 dxUnconsumed, dyUnconsumed); 21829 21830 if (offsetInWindow != null) { 21831 getLocationInWindow(offsetInWindow); 21832 offsetInWindow[0] -= startX; 21833 offsetInWindow[1] -= startY; 21834 } 21835 return true; 21836 } else if (offsetInWindow != null) { 21837 // No motion, no dispatch. Keep offsetInWindow up to date. 21838 offsetInWindow[0] = 0; 21839 offsetInWindow[1] = 0; 21840 } 21841 } 21842 return false; 21843 } 21844 21845 /** 21846 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 21847 * 21848 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 21849 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 21850 * scrolling operation to consume some or all of the scroll operation before the child view 21851 * consumes it.</p> 21852 * 21853 * @param dx Horizontal scroll distance in pixels 21854 * @param dy Vertical scroll distance in pixels 21855 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 21856 * and consumed[1] the consumed dy. 21857 * @param offsetInWindow Optional. If not null, on return this will contain the offset 21858 * in local view coordinates of this view from before this operation 21859 * to after it completes. View implementations may use this to adjust 21860 * expected input coordinate tracking. 21861 * @return true if the parent consumed some or all of the scroll delta 21862 * @see #dispatchNestedScroll(int, int, int, int, int[]) 21863 */ 21864 public boolean dispatchNestedPreScroll(int dx, int dy, 21865 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 21866 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21867 if (dx != 0 || dy != 0) { 21868 int startX = 0; 21869 int startY = 0; 21870 if (offsetInWindow != null) { 21871 getLocationInWindow(offsetInWindow); 21872 startX = offsetInWindow[0]; 21873 startY = offsetInWindow[1]; 21874 } 21875 21876 if (consumed == null) { 21877 if (mTempNestedScrollConsumed == null) { 21878 mTempNestedScrollConsumed = new int[2]; 21879 } 21880 consumed = mTempNestedScrollConsumed; 21881 } 21882 consumed[0] = 0; 21883 consumed[1] = 0; 21884 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 21885 21886 if (offsetInWindow != null) { 21887 getLocationInWindow(offsetInWindow); 21888 offsetInWindow[0] -= startX; 21889 offsetInWindow[1] -= startY; 21890 } 21891 return consumed[0] != 0 || consumed[1] != 0; 21892 } else if (offsetInWindow != null) { 21893 offsetInWindow[0] = 0; 21894 offsetInWindow[1] = 0; 21895 } 21896 } 21897 return false; 21898 } 21899 21900 /** 21901 * Dispatch a fling to a nested scrolling parent. 21902 * 21903 * <p>This method should be used to indicate that a nested scrolling child has detected 21904 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 21905 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 21906 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 21907 * along a scrollable axis.</p> 21908 * 21909 * <p>If a nested scrolling child view would normally fling but it is at the edge of 21910 * its own content, it can use this method to delegate the fling to its nested scrolling 21911 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 21912 * 21913 * @param velocityX Horizontal fling velocity in pixels per second 21914 * @param velocityY Vertical fling velocity in pixels per second 21915 * @param consumed true if the child consumed the fling, false otherwise 21916 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 21917 */ 21918 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 21919 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21920 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 21921 } 21922 return false; 21923 } 21924 21925 /** 21926 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 21927 * 21928 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 21929 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 21930 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 21931 * before the child view consumes it. If this method returns <code>true</code>, a nested 21932 * parent view consumed the fling and this view should not scroll as a result.</p> 21933 * 21934 * <p>For a better user experience, only one view in a nested scrolling chain should consume 21935 * the fling at a time. If a parent view consumed the fling this method will return false. 21936 * Custom view implementations should account for this in two ways:</p> 21937 * 21938 * <ul> 21939 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 21940 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 21941 * position regardless.</li> 21942 * <li>If a nested parent does consume the fling, this view should not scroll at all, 21943 * even to settle back to a valid idle position.</li> 21944 * </ul> 21945 * 21946 * <p>Views should also not offer fling velocities to nested parent views along an axis 21947 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 21948 * should not offer a horizontal fling velocity to its parents since scrolling along that 21949 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 21950 * 21951 * @param velocityX Horizontal fling velocity in pixels per second 21952 * @param velocityY Vertical fling velocity in pixels per second 21953 * @return true if a nested scrolling parent consumed the fling 21954 */ 21955 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 21956 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21957 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 21958 } 21959 return false; 21960 } 21961 21962 /** 21963 * Gets a scale factor that determines the distance the view should scroll 21964 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 21965 * @return The vertical scroll scale factor. 21966 * @hide 21967 */ 21968 protected float getVerticalScrollFactor() { 21969 if (mVerticalScrollFactor == 0) { 21970 TypedValue outValue = new TypedValue(); 21971 if (!mContext.getTheme().resolveAttribute( 21972 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 21973 throw new IllegalStateException( 21974 "Expected theme to define listPreferredItemHeight."); 21975 } 21976 mVerticalScrollFactor = outValue.getDimension( 21977 mContext.getResources().getDisplayMetrics()); 21978 } 21979 return mVerticalScrollFactor; 21980 } 21981 21982 /** 21983 * Gets a scale factor that determines the distance the view should scroll 21984 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 21985 * @return The horizontal scroll scale factor. 21986 * @hide 21987 */ 21988 protected float getHorizontalScrollFactor() { 21989 // TODO: Should use something else. 21990 return getVerticalScrollFactor(); 21991 } 21992 21993 /** 21994 * Return the value specifying the text direction or policy that was set with 21995 * {@link #setTextDirection(int)}. 21996 * 21997 * @return the defined text direction. It can be one of: 21998 * 21999 * {@link #TEXT_DIRECTION_INHERIT}, 22000 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22001 * {@link #TEXT_DIRECTION_ANY_RTL}, 22002 * {@link #TEXT_DIRECTION_LTR}, 22003 * {@link #TEXT_DIRECTION_RTL}, 22004 * {@link #TEXT_DIRECTION_LOCALE}, 22005 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22006 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22007 * 22008 * @attr ref android.R.styleable#View_textDirection 22009 * 22010 * @hide 22011 */ 22012 @ViewDebug.ExportedProperty(category = "text", mapping = { 22013 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22014 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22015 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22016 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22017 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22018 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22019 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22020 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22021 }) 22022 public int getRawTextDirection() { 22023 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 22024 } 22025 22026 /** 22027 * Set the text direction. 22028 * 22029 * @param textDirection the direction to set. Should be one of: 22030 * 22031 * {@link #TEXT_DIRECTION_INHERIT}, 22032 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22033 * {@link #TEXT_DIRECTION_ANY_RTL}, 22034 * {@link #TEXT_DIRECTION_LTR}, 22035 * {@link #TEXT_DIRECTION_RTL}, 22036 * {@link #TEXT_DIRECTION_LOCALE} 22037 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22038 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 22039 * 22040 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 22041 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 22042 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 22043 * 22044 * @attr ref android.R.styleable#View_textDirection 22045 */ 22046 public void setTextDirection(int textDirection) { 22047 if (getRawTextDirection() != textDirection) { 22048 // Reset the current text direction and the resolved one 22049 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 22050 resetResolvedTextDirection(); 22051 // Set the new text direction 22052 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 22053 // Do resolution 22054 resolveTextDirection(); 22055 // Notify change 22056 onRtlPropertiesChanged(getLayoutDirection()); 22057 // Refresh 22058 requestLayout(); 22059 invalidate(true); 22060 } 22061 } 22062 22063 /** 22064 * Return the resolved text direction. 22065 * 22066 * @return the resolved text direction. Returns one of: 22067 * 22068 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22069 * {@link #TEXT_DIRECTION_ANY_RTL}, 22070 * {@link #TEXT_DIRECTION_LTR}, 22071 * {@link #TEXT_DIRECTION_RTL}, 22072 * {@link #TEXT_DIRECTION_LOCALE}, 22073 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22074 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22075 * 22076 * @attr ref android.R.styleable#View_textDirection 22077 */ 22078 @ViewDebug.ExportedProperty(category = "text", mapping = { 22079 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22080 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22081 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22082 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22083 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22084 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22085 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22086 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22087 }) 22088 public int getTextDirection() { 22089 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 22090 } 22091 22092 /** 22093 * Resolve the text direction. 22094 * 22095 * @return true if resolution has been done, false otherwise. 22096 * 22097 * @hide 22098 */ 22099 public boolean resolveTextDirection() { 22100 // Reset any previous text direction resolution 22101 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22102 22103 if (hasRtlSupport()) { 22104 // Set resolved text direction flag depending on text direction flag 22105 final int textDirection = getRawTextDirection(); 22106 switch(textDirection) { 22107 case TEXT_DIRECTION_INHERIT: 22108 if (!canResolveTextDirection()) { 22109 // We cannot do the resolution if there is no parent, so use the default one 22110 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22111 // Resolution will need to happen again later 22112 return false; 22113 } 22114 22115 // Parent has not yet resolved, so we still return the default 22116 try { 22117 if (!mParent.isTextDirectionResolved()) { 22118 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22119 // Resolution will need to happen again later 22120 return false; 22121 } 22122 } catch (AbstractMethodError e) { 22123 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22124 " does not fully implement ViewParent", e); 22125 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 22126 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22127 return true; 22128 } 22129 22130 // Set current resolved direction to the same value as the parent's one 22131 int parentResolvedDirection; 22132 try { 22133 parentResolvedDirection = mParent.getTextDirection(); 22134 } catch (AbstractMethodError e) { 22135 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22136 " does not fully implement ViewParent", e); 22137 parentResolvedDirection = TEXT_DIRECTION_LTR; 22138 } 22139 switch (parentResolvedDirection) { 22140 case TEXT_DIRECTION_FIRST_STRONG: 22141 case TEXT_DIRECTION_ANY_RTL: 22142 case TEXT_DIRECTION_LTR: 22143 case TEXT_DIRECTION_RTL: 22144 case TEXT_DIRECTION_LOCALE: 22145 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22146 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22147 mPrivateFlags2 |= 22148 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22149 break; 22150 default: 22151 // Default resolved direction is "first strong" heuristic 22152 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22153 } 22154 break; 22155 case TEXT_DIRECTION_FIRST_STRONG: 22156 case TEXT_DIRECTION_ANY_RTL: 22157 case TEXT_DIRECTION_LTR: 22158 case TEXT_DIRECTION_RTL: 22159 case TEXT_DIRECTION_LOCALE: 22160 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22161 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22162 // Resolved direction is the same as text direction 22163 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22164 break; 22165 default: 22166 // Default resolved direction is "first strong" heuristic 22167 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22168 } 22169 } else { 22170 // Default resolved direction is "first strong" heuristic 22171 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22172 } 22173 22174 // Set to resolved 22175 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 22176 return true; 22177 } 22178 22179 /** 22180 * Check if text direction resolution can be done. 22181 * 22182 * @return true if text direction resolution can be done otherwise return false. 22183 */ 22184 public boolean canResolveTextDirection() { 22185 switch (getRawTextDirection()) { 22186 case TEXT_DIRECTION_INHERIT: 22187 if (mParent != null) { 22188 try { 22189 return mParent.canResolveTextDirection(); 22190 } catch (AbstractMethodError e) { 22191 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22192 " does not fully implement ViewParent", e); 22193 } 22194 } 22195 return false; 22196 22197 default: 22198 return true; 22199 } 22200 } 22201 22202 /** 22203 * Reset resolved text direction. Text direction will be resolved during a call to 22204 * {@link #onMeasure(int, int)}. 22205 * 22206 * @hide 22207 */ 22208 public void resetResolvedTextDirection() { 22209 // Reset any previous text direction resolution 22210 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22211 // Set to default value 22212 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22213 } 22214 22215 /** 22216 * @return true if text direction is inherited. 22217 * 22218 * @hide 22219 */ 22220 public boolean isTextDirectionInherited() { 22221 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 22222 } 22223 22224 /** 22225 * @return true if text direction is resolved. 22226 */ 22227 public boolean isTextDirectionResolved() { 22228 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 22229 } 22230 22231 /** 22232 * Return the value specifying the text alignment or policy that was set with 22233 * {@link #setTextAlignment(int)}. 22234 * 22235 * @return the defined text alignment. It can be one of: 22236 * 22237 * {@link #TEXT_ALIGNMENT_INHERIT}, 22238 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22239 * {@link #TEXT_ALIGNMENT_CENTER}, 22240 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22241 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22242 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22243 * {@link #TEXT_ALIGNMENT_VIEW_END} 22244 * 22245 * @attr ref android.R.styleable#View_textAlignment 22246 * 22247 * @hide 22248 */ 22249 @ViewDebug.ExportedProperty(category = "text", mapping = { 22250 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22251 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22252 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22253 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22254 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22255 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22256 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22257 }) 22258 @TextAlignment 22259 public int getRawTextAlignment() { 22260 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 22261 } 22262 22263 /** 22264 * Set the text alignment. 22265 * 22266 * @param textAlignment The text alignment to set. Should be one of 22267 * 22268 * {@link #TEXT_ALIGNMENT_INHERIT}, 22269 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22270 * {@link #TEXT_ALIGNMENT_CENTER}, 22271 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22272 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22273 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22274 * {@link #TEXT_ALIGNMENT_VIEW_END} 22275 * 22276 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 22277 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 22278 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 22279 * 22280 * @attr ref android.R.styleable#View_textAlignment 22281 */ 22282 public void setTextAlignment(@TextAlignment int textAlignment) { 22283 if (textAlignment != getRawTextAlignment()) { 22284 // Reset the current and resolved text alignment 22285 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 22286 resetResolvedTextAlignment(); 22287 // Set the new text alignment 22288 mPrivateFlags2 |= 22289 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 22290 // Do resolution 22291 resolveTextAlignment(); 22292 // Notify change 22293 onRtlPropertiesChanged(getLayoutDirection()); 22294 // Refresh 22295 requestLayout(); 22296 invalidate(true); 22297 } 22298 } 22299 22300 /** 22301 * Return the resolved text alignment. 22302 * 22303 * @return the resolved text alignment. Returns one of: 22304 * 22305 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22306 * {@link #TEXT_ALIGNMENT_CENTER}, 22307 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22308 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22309 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22310 * {@link #TEXT_ALIGNMENT_VIEW_END} 22311 * 22312 * @attr ref android.R.styleable#View_textAlignment 22313 */ 22314 @ViewDebug.ExportedProperty(category = "text", mapping = { 22315 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22316 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22317 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22318 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22319 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22320 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22321 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22322 }) 22323 @TextAlignment 22324 public int getTextAlignment() { 22325 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 22326 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 22327 } 22328 22329 /** 22330 * Resolve the text alignment. 22331 * 22332 * @return true if resolution has been done, false otherwise. 22333 * 22334 * @hide 22335 */ 22336 public boolean resolveTextAlignment() { 22337 // Reset any previous text alignment resolution 22338 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22339 22340 if (hasRtlSupport()) { 22341 // Set resolved text alignment flag depending on text alignment flag 22342 final int textAlignment = getRawTextAlignment(); 22343 switch (textAlignment) { 22344 case TEXT_ALIGNMENT_INHERIT: 22345 // Check if we can resolve the text alignment 22346 if (!canResolveTextAlignment()) { 22347 // We cannot do the resolution if there is no parent so use the default 22348 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22349 // Resolution will need to happen again later 22350 return false; 22351 } 22352 22353 // Parent has not yet resolved, so we still return the default 22354 try { 22355 if (!mParent.isTextAlignmentResolved()) { 22356 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22357 // Resolution will need to happen again later 22358 return false; 22359 } 22360 } catch (AbstractMethodError e) { 22361 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22362 " does not fully implement ViewParent", e); 22363 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 22364 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22365 return true; 22366 } 22367 22368 int parentResolvedTextAlignment; 22369 try { 22370 parentResolvedTextAlignment = mParent.getTextAlignment(); 22371 } catch (AbstractMethodError e) { 22372 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22373 " does not fully implement ViewParent", e); 22374 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 22375 } 22376 switch (parentResolvedTextAlignment) { 22377 case TEXT_ALIGNMENT_GRAVITY: 22378 case TEXT_ALIGNMENT_TEXT_START: 22379 case TEXT_ALIGNMENT_TEXT_END: 22380 case TEXT_ALIGNMENT_CENTER: 22381 case TEXT_ALIGNMENT_VIEW_START: 22382 case TEXT_ALIGNMENT_VIEW_END: 22383 // Resolved text alignment is the same as the parent resolved 22384 // text alignment 22385 mPrivateFlags2 |= 22386 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22387 break; 22388 default: 22389 // Use default resolved text alignment 22390 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22391 } 22392 break; 22393 case TEXT_ALIGNMENT_GRAVITY: 22394 case TEXT_ALIGNMENT_TEXT_START: 22395 case TEXT_ALIGNMENT_TEXT_END: 22396 case TEXT_ALIGNMENT_CENTER: 22397 case TEXT_ALIGNMENT_VIEW_START: 22398 case TEXT_ALIGNMENT_VIEW_END: 22399 // Resolved text alignment is the same as text alignment 22400 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22401 break; 22402 default: 22403 // Use default resolved text alignment 22404 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22405 } 22406 } else { 22407 // Use default resolved text alignment 22408 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22409 } 22410 22411 // Set the resolved 22412 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22413 return true; 22414 } 22415 22416 /** 22417 * Check if text alignment resolution can be done. 22418 * 22419 * @return true if text alignment resolution can be done otherwise return false. 22420 */ 22421 public boolean canResolveTextAlignment() { 22422 switch (getRawTextAlignment()) { 22423 case TEXT_DIRECTION_INHERIT: 22424 if (mParent != null) { 22425 try { 22426 return mParent.canResolveTextAlignment(); 22427 } catch (AbstractMethodError e) { 22428 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22429 " does not fully implement ViewParent", e); 22430 } 22431 } 22432 return false; 22433 22434 default: 22435 return true; 22436 } 22437 } 22438 22439 /** 22440 * Reset resolved text alignment. Text alignment will be resolved during a call to 22441 * {@link #onMeasure(int, int)}. 22442 * 22443 * @hide 22444 */ 22445 public void resetResolvedTextAlignment() { 22446 // Reset any previous text alignment resolution 22447 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22448 // Set to default 22449 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22450 } 22451 22452 /** 22453 * @return true if text alignment is inherited. 22454 * 22455 * @hide 22456 */ 22457 public boolean isTextAlignmentInherited() { 22458 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 22459 } 22460 22461 /** 22462 * @return true if text alignment is resolved. 22463 */ 22464 public boolean isTextAlignmentResolved() { 22465 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22466 } 22467 22468 /** 22469 * Generate a value suitable for use in {@link #setId(int)}. 22470 * This value will not collide with ID values generated at build time by aapt for R.id. 22471 * 22472 * @return a generated ID value 22473 */ 22474 public static int generateViewId() { 22475 for (;;) { 22476 final int result = sNextGeneratedId.get(); 22477 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 22478 int newValue = result + 1; 22479 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 22480 if (sNextGeneratedId.compareAndSet(result, newValue)) { 22481 return result; 22482 } 22483 } 22484 } 22485 22486 /** 22487 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 22488 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 22489 * a normal View or a ViewGroup with 22490 * {@link android.view.ViewGroup#isTransitionGroup()} true. 22491 * @hide 22492 */ 22493 public void captureTransitioningViews(List<View> transitioningViews) { 22494 if (getVisibility() == View.VISIBLE) { 22495 transitioningViews.add(this); 22496 } 22497 } 22498 22499 /** 22500 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 22501 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 22502 * @hide 22503 */ 22504 public void findNamedViews(Map<String, View> namedElements) { 22505 if (getVisibility() == VISIBLE || mGhostView != null) { 22506 String transitionName = getTransitionName(); 22507 if (transitionName != null) { 22508 namedElements.put(transitionName, this); 22509 } 22510 } 22511 } 22512 22513 /** 22514 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 22515 * The default implementation does not care the location or event types, but some subclasses 22516 * may use it (such as WebViews). 22517 * @param event The MotionEvent from a mouse 22518 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 22519 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 22520 * @see PointerIcon 22521 */ 22522 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 22523 final float x = event.getX(pointerIndex); 22524 final float y = event.getY(pointerIndex); 22525 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 22526 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 22527 } 22528 return mPointerIcon; 22529 } 22530 22531 /** 22532 * Set the pointer icon for the current view. 22533 * Passing {@code null} will restore the pointer icon to its default value. 22534 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 22535 */ 22536 public void setPointerIcon(PointerIcon pointerIcon) { 22537 mPointerIcon = pointerIcon; 22538 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 22539 return; 22540 } 22541 try { 22542 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 22543 } catch (RemoteException e) { 22544 } 22545 } 22546 22547 /** 22548 * Gets the pointer icon for the current view. 22549 */ 22550 public PointerIcon getPointerIcon() { 22551 return mPointerIcon; 22552 } 22553 22554 // 22555 // Properties 22556 // 22557 /** 22558 * A Property wrapper around the <code>alpha</code> functionality handled by the 22559 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 22560 */ 22561 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 22562 @Override 22563 public void setValue(View object, float value) { 22564 object.setAlpha(value); 22565 } 22566 22567 @Override 22568 public Float get(View object) { 22569 return object.getAlpha(); 22570 } 22571 }; 22572 22573 /** 22574 * A Property wrapper around the <code>translationX</code> functionality handled by the 22575 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 22576 */ 22577 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 22578 @Override 22579 public void setValue(View object, float value) { 22580 object.setTranslationX(value); 22581 } 22582 22583 @Override 22584 public Float get(View object) { 22585 return object.getTranslationX(); 22586 } 22587 }; 22588 22589 /** 22590 * A Property wrapper around the <code>translationY</code> functionality handled by the 22591 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 22592 */ 22593 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 22594 @Override 22595 public void setValue(View object, float value) { 22596 object.setTranslationY(value); 22597 } 22598 22599 @Override 22600 public Float get(View object) { 22601 return object.getTranslationY(); 22602 } 22603 }; 22604 22605 /** 22606 * A Property wrapper around the <code>translationZ</code> functionality handled by the 22607 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 22608 */ 22609 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 22610 @Override 22611 public void setValue(View object, float value) { 22612 object.setTranslationZ(value); 22613 } 22614 22615 @Override 22616 public Float get(View object) { 22617 return object.getTranslationZ(); 22618 } 22619 }; 22620 22621 /** 22622 * A Property wrapper around the <code>x</code> functionality handled by the 22623 * {@link View#setX(float)} and {@link View#getX()} methods. 22624 */ 22625 public static final Property<View, Float> X = new FloatProperty<View>("x") { 22626 @Override 22627 public void setValue(View object, float value) { 22628 object.setX(value); 22629 } 22630 22631 @Override 22632 public Float get(View object) { 22633 return object.getX(); 22634 } 22635 }; 22636 22637 /** 22638 * A Property wrapper around the <code>y</code> functionality handled by the 22639 * {@link View#setY(float)} and {@link View#getY()} methods. 22640 */ 22641 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 22642 @Override 22643 public void setValue(View object, float value) { 22644 object.setY(value); 22645 } 22646 22647 @Override 22648 public Float get(View object) { 22649 return object.getY(); 22650 } 22651 }; 22652 22653 /** 22654 * A Property wrapper around the <code>z</code> functionality handled by the 22655 * {@link View#setZ(float)} and {@link View#getZ()} methods. 22656 */ 22657 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 22658 @Override 22659 public void setValue(View object, float value) { 22660 object.setZ(value); 22661 } 22662 22663 @Override 22664 public Float get(View object) { 22665 return object.getZ(); 22666 } 22667 }; 22668 22669 /** 22670 * A Property wrapper around the <code>rotation</code> functionality handled by the 22671 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 22672 */ 22673 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 22674 @Override 22675 public void setValue(View object, float value) { 22676 object.setRotation(value); 22677 } 22678 22679 @Override 22680 public Float get(View object) { 22681 return object.getRotation(); 22682 } 22683 }; 22684 22685 /** 22686 * A Property wrapper around the <code>rotationX</code> functionality handled by the 22687 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 22688 */ 22689 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 22690 @Override 22691 public void setValue(View object, float value) { 22692 object.setRotationX(value); 22693 } 22694 22695 @Override 22696 public Float get(View object) { 22697 return object.getRotationX(); 22698 } 22699 }; 22700 22701 /** 22702 * A Property wrapper around the <code>rotationY</code> functionality handled by the 22703 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 22704 */ 22705 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 22706 @Override 22707 public void setValue(View object, float value) { 22708 object.setRotationY(value); 22709 } 22710 22711 @Override 22712 public Float get(View object) { 22713 return object.getRotationY(); 22714 } 22715 }; 22716 22717 /** 22718 * A Property wrapper around the <code>scaleX</code> functionality handled by the 22719 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 22720 */ 22721 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 22722 @Override 22723 public void setValue(View object, float value) { 22724 object.setScaleX(value); 22725 } 22726 22727 @Override 22728 public Float get(View object) { 22729 return object.getScaleX(); 22730 } 22731 }; 22732 22733 /** 22734 * A Property wrapper around the <code>scaleY</code> functionality handled by the 22735 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 22736 */ 22737 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 22738 @Override 22739 public void setValue(View object, float value) { 22740 object.setScaleY(value); 22741 } 22742 22743 @Override 22744 public Float get(View object) { 22745 return object.getScaleY(); 22746 } 22747 }; 22748 22749 /** 22750 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 22751 * Each MeasureSpec represents a requirement for either the width or the height. 22752 * A MeasureSpec is comprised of a size and a mode. There are three possible 22753 * modes: 22754 * <dl> 22755 * <dt>UNSPECIFIED</dt> 22756 * <dd> 22757 * The parent has not imposed any constraint on the child. It can be whatever size 22758 * it wants. 22759 * </dd> 22760 * 22761 * <dt>EXACTLY</dt> 22762 * <dd> 22763 * The parent has determined an exact size for the child. The child is going to be 22764 * given those bounds regardless of how big it wants to be. 22765 * </dd> 22766 * 22767 * <dt>AT_MOST</dt> 22768 * <dd> 22769 * The child can be as large as it wants up to the specified size. 22770 * </dd> 22771 * </dl> 22772 * 22773 * MeasureSpecs are implemented as ints to reduce object allocation. This class 22774 * is provided to pack and unpack the <size, mode> tuple into the int. 22775 */ 22776 public static class MeasureSpec { 22777 private static final int MODE_SHIFT = 30; 22778 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 22779 22780 /** @hide */ 22781 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 22782 @Retention(RetentionPolicy.SOURCE) 22783 public @interface MeasureSpecMode {} 22784 22785 /** 22786 * Measure specification mode: The parent has not imposed any constraint 22787 * on the child. It can be whatever size it wants. 22788 */ 22789 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 22790 22791 /** 22792 * Measure specification mode: The parent has determined an exact size 22793 * for the child. The child is going to be given those bounds regardless 22794 * of how big it wants to be. 22795 */ 22796 public static final int EXACTLY = 1 << MODE_SHIFT; 22797 22798 /** 22799 * Measure specification mode: The child can be as large as it wants up 22800 * to the specified size. 22801 */ 22802 public static final int AT_MOST = 2 << MODE_SHIFT; 22803 22804 /** 22805 * Creates a measure specification based on the supplied size and mode. 22806 * 22807 * The mode must always be one of the following: 22808 * <ul> 22809 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 22810 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 22811 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 22812 * </ul> 22813 * 22814 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 22815 * implementation was such that the order of arguments did not matter 22816 * and overflow in either value could impact the resulting MeasureSpec. 22817 * {@link android.widget.RelativeLayout} was affected by this bug. 22818 * Apps targeting API levels greater than 17 will get the fixed, more strict 22819 * behavior.</p> 22820 * 22821 * @param size the size of the measure specification 22822 * @param mode the mode of the measure specification 22823 * @return the measure specification based on size and mode 22824 */ 22825 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 22826 @MeasureSpecMode int mode) { 22827 if (sUseBrokenMakeMeasureSpec) { 22828 return size + mode; 22829 } else { 22830 return (size & ~MODE_MASK) | (mode & MODE_MASK); 22831 } 22832 } 22833 22834 /** 22835 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 22836 * will automatically get a size of 0. Older apps expect this. 22837 * 22838 * @hide internal use only for compatibility with system widgets and older apps 22839 */ 22840 public static int makeSafeMeasureSpec(int size, int mode) { 22841 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 22842 return 0; 22843 } 22844 return makeMeasureSpec(size, mode); 22845 } 22846 22847 /** 22848 * Extracts the mode from the supplied measure specification. 22849 * 22850 * @param measureSpec the measure specification to extract the mode from 22851 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 22852 * {@link android.view.View.MeasureSpec#AT_MOST} or 22853 * {@link android.view.View.MeasureSpec#EXACTLY} 22854 */ 22855 @MeasureSpecMode 22856 public static int getMode(int measureSpec) { 22857 //noinspection ResourceType 22858 return (measureSpec & MODE_MASK); 22859 } 22860 22861 /** 22862 * Extracts the size from the supplied measure specification. 22863 * 22864 * @param measureSpec the measure specification to extract the size from 22865 * @return the size in pixels defined in the supplied measure specification 22866 */ 22867 public static int getSize(int measureSpec) { 22868 return (measureSpec & ~MODE_MASK); 22869 } 22870 22871 static int adjust(int measureSpec, int delta) { 22872 final int mode = getMode(measureSpec); 22873 int size = getSize(measureSpec); 22874 if (mode == UNSPECIFIED) { 22875 // No need to adjust size for UNSPECIFIED mode. 22876 return makeMeasureSpec(size, UNSPECIFIED); 22877 } 22878 size += delta; 22879 if (size < 0) { 22880 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 22881 ") spec: " + toString(measureSpec) + " delta: " + delta); 22882 size = 0; 22883 } 22884 return makeMeasureSpec(size, mode); 22885 } 22886 22887 /** 22888 * Returns a String representation of the specified measure 22889 * specification. 22890 * 22891 * @param measureSpec the measure specification to convert to a String 22892 * @return a String with the following format: "MeasureSpec: MODE SIZE" 22893 */ 22894 public static String toString(int measureSpec) { 22895 int mode = getMode(measureSpec); 22896 int size = getSize(measureSpec); 22897 22898 StringBuilder sb = new StringBuilder("MeasureSpec: "); 22899 22900 if (mode == UNSPECIFIED) 22901 sb.append("UNSPECIFIED "); 22902 else if (mode == EXACTLY) 22903 sb.append("EXACTLY "); 22904 else if (mode == AT_MOST) 22905 sb.append("AT_MOST "); 22906 else 22907 sb.append(mode).append(" "); 22908 22909 sb.append(size); 22910 return sb.toString(); 22911 } 22912 } 22913 22914 private final class CheckForLongPress implements Runnable { 22915 private int mOriginalWindowAttachCount; 22916 private float mX; 22917 private float mY; 22918 private boolean mOriginalPressedState; 22919 22920 @Override 22921 public void run() { 22922 if ((mOriginalPressedState == isPressed()) && (mParent != null) 22923 && mOriginalWindowAttachCount == mWindowAttachCount) { 22924 if (performLongClick(mX, mY)) { 22925 mHasPerformedLongPress = true; 22926 } 22927 } 22928 } 22929 22930 public void setAnchor(float x, float y) { 22931 mX = x; 22932 mY = y; 22933 } 22934 22935 public void rememberWindowAttachCount() { 22936 mOriginalWindowAttachCount = mWindowAttachCount; 22937 } 22938 22939 public void rememberPressedState() { 22940 mOriginalPressedState = isPressed(); 22941 } 22942 } 22943 22944 private final class CheckForTap implements Runnable { 22945 public float x; 22946 public float y; 22947 22948 @Override 22949 public void run() { 22950 mPrivateFlags &= ~PFLAG_PREPRESSED; 22951 setPressed(true, x, y); 22952 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 22953 } 22954 } 22955 22956 private final class PerformClick implements Runnable { 22957 @Override 22958 public void run() { 22959 performClick(); 22960 } 22961 } 22962 22963 /** 22964 * This method returns a ViewPropertyAnimator object, which can be used to animate 22965 * specific properties on this View. 22966 * 22967 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 22968 */ 22969 public ViewPropertyAnimator animate() { 22970 if (mAnimator == null) { 22971 mAnimator = new ViewPropertyAnimator(this); 22972 } 22973 return mAnimator; 22974 } 22975 22976 /** 22977 * Sets the name of the View to be used to identify Views in Transitions. 22978 * Names should be unique in the View hierarchy. 22979 * 22980 * @param transitionName The name of the View to uniquely identify it for Transitions. 22981 */ 22982 public final void setTransitionName(String transitionName) { 22983 mTransitionName = transitionName; 22984 } 22985 22986 /** 22987 * Returns the name of the View to be used to identify Views in Transitions. 22988 * Names should be unique in the View hierarchy. 22989 * 22990 * <p>This returns null if the View has not been given a name.</p> 22991 * 22992 * @return The name used of the View to be used to identify Views in Transitions or null 22993 * if no name has been given. 22994 */ 22995 @ViewDebug.ExportedProperty 22996 public String getTransitionName() { 22997 return mTransitionName; 22998 } 22999 23000 /** 23001 * @hide 23002 */ 23003 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 23004 // Do nothing. 23005 } 23006 23007 /** 23008 * Interface definition for a callback to be invoked when a hardware key event is 23009 * dispatched to this view. The callback will be invoked before the key event is 23010 * given to the view. This is only useful for hardware keyboards; a software input 23011 * method has no obligation to trigger this listener. 23012 */ 23013 public interface OnKeyListener { 23014 /** 23015 * Called when a hardware key is dispatched to a view. This allows listeners to 23016 * get a chance to respond before the target view. 23017 * <p>Key presses in software keyboards will generally NOT trigger this method, 23018 * although some may elect to do so in some situations. Do not assume a 23019 * software input method has to be key-based; even if it is, it may use key presses 23020 * in a different way than you expect, so there is no way to reliably catch soft 23021 * input key presses. 23022 * 23023 * @param v The view the key has been dispatched to. 23024 * @param keyCode The code for the physical key that was pressed 23025 * @param event The KeyEvent object containing full information about 23026 * the event. 23027 * @return True if the listener has consumed the event, false otherwise. 23028 */ 23029 boolean onKey(View v, int keyCode, KeyEvent event); 23030 } 23031 23032 /** 23033 * Interface definition for a callback to be invoked when a touch event is 23034 * dispatched to this view. The callback will be invoked before the touch 23035 * event is given to the view. 23036 */ 23037 public interface OnTouchListener { 23038 /** 23039 * Called when a touch event is dispatched to a view. This allows listeners to 23040 * get a chance to respond before the target view. 23041 * 23042 * @param v The view the touch event has been dispatched to. 23043 * @param event The MotionEvent object containing full information about 23044 * the event. 23045 * @return True if the listener has consumed the event, false otherwise. 23046 */ 23047 boolean onTouch(View v, MotionEvent event); 23048 } 23049 23050 /** 23051 * Interface definition for a callback to be invoked when a hover event is 23052 * dispatched to this view. The callback will be invoked before the hover 23053 * event is given to the view. 23054 */ 23055 public interface OnHoverListener { 23056 /** 23057 * Called when a hover event is dispatched to a view. This allows listeners to 23058 * get a chance to respond before the target view. 23059 * 23060 * @param v The view the hover event has been dispatched to. 23061 * @param event The MotionEvent object containing full information about 23062 * the event. 23063 * @return True if the listener has consumed the event, false otherwise. 23064 */ 23065 boolean onHover(View v, MotionEvent event); 23066 } 23067 23068 /** 23069 * Interface definition for a callback to be invoked when a generic motion event is 23070 * dispatched to this view. The callback will be invoked before the generic motion 23071 * event is given to the view. 23072 */ 23073 public interface OnGenericMotionListener { 23074 /** 23075 * Called when a generic motion event is dispatched to a view. This allows listeners to 23076 * get a chance to respond before the target view. 23077 * 23078 * @param v The view the generic motion event has been dispatched to. 23079 * @param event The MotionEvent object containing full information about 23080 * the event. 23081 * @return True if the listener has consumed the event, false otherwise. 23082 */ 23083 boolean onGenericMotion(View v, MotionEvent event); 23084 } 23085 23086 /** 23087 * Interface definition for a callback to be invoked when a view has been clicked and held. 23088 */ 23089 public interface OnLongClickListener { 23090 /** 23091 * Called when a view has been clicked and held. 23092 * 23093 * @param v The view that was clicked and held. 23094 * 23095 * @return true if the callback consumed the long click, false otherwise. 23096 */ 23097 boolean onLongClick(View v); 23098 } 23099 23100 /** 23101 * Interface definition for a callback to be invoked when a drag is being dispatched 23102 * to this view. The callback will be invoked before the hosting view's own 23103 * onDrag(event) method. If the listener wants to fall back to the hosting view's 23104 * onDrag(event) behavior, it should return 'false' from this callback. 23105 * 23106 * <div class="special reference"> 23107 * <h3>Developer Guides</h3> 23108 * <p>For a guide to implementing drag and drop features, read the 23109 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 23110 * </div> 23111 */ 23112 public interface OnDragListener { 23113 /** 23114 * Called when a drag event is dispatched to a view. This allows listeners 23115 * to get a chance to override base View behavior. 23116 * 23117 * @param v The View that received the drag event. 23118 * @param event The {@link android.view.DragEvent} object for the drag event. 23119 * @return {@code true} if the drag event was handled successfully, or {@code false} 23120 * if the drag event was not handled. Note that {@code false} will trigger the View 23121 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 23122 */ 23123 boolean onDrag(View v, DragEvent event); 23124 } 23125 23126 /** 23127 * Interface definition for a callback to be invoked when the focus state of 23128 * a view changed. 23129 */ 23130 public interface OnFocusChangeListener { 23131 /** 23132 * Called when the focus state of a view has changed. 23133 * 23134 * @param v The view whose state has changed. 23135 * @param hasFocus The new focus state of v. 23136 */ 23137 void onFocusChange(View v, boolean hasFocus); 23138 } 23139 23140 /** 23141 * Interface definition for a callback to be invoked when a view is clicked. 23142 */ 23143 public interface OnClickListener { 23144 /** 23145 * Called when a view has been clicked. 23146 * 23147 * @param v The view that was clicked. 23148 */ 23149 void onClick(View v); 23150 } 23151 23152 /** 23153 * Interface definition for a callback to be invoked when a view is context clicked. 23154 */ 23155 public interface OnContextClickListener { 23156 /** 23157 * Called when a view is context clicked. 23158 * 23159 * @param v The view that has been context clicked. 23160 * @return true if the callback consumed the context click, false otherwise. 23161 */ 23162 boolean onContextClick(View v); 23163 } 23164 23165 /** 23166 * Interface definition for a callback to be invoked when the context menu 23167 * for this view is being built. 23168 */ 23169 public interface OnCreateContextMenuListener { 23170 /** 23171 * Called when the context menu for this view is being built. It is not 23172 * safe to hold onto the menu after this method returns. 23173 * 23174 * @param menu The context menu that is being built 23175 * @param v The view for which the context menu is being built 23176 * @param menuInfo Extra information about the item for which the 23177 * context menu should be shown. This information will vary 23178 * depending on the class of v. 23179 */ 23180 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 23181 } 23182 23183 /** 23184 * Interface definition for a callback to be invoked when the status bar changes 23185 * visibility. This reports <strong>global</strong> changes to the system UI 23186 * state, not what the application is requesting. 23187 * 23188 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 23189 */ 23190 public interface OnSystemUiVisibilityChangeListener { 23191 /** 23192 * Called when the status bar changes visibility because of a call to 23193 * {@link View#setSystemUiVisibility(int)}. 23194 * 23195 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 23196 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 23197 * This tells you the <strong>global</strong> state of these UI visibility 23198 * flags, not what your app is currently applying. 23199 */ 23200 public void onSystemUiVisibilityChange(int visibility); 23201 } 23202 23203 /** 23204 * Interface definition for a callback to be invoked when this view is attached 23205 * or detached from its window. 23206 */ 23207 public interface OnAttachStateChangeListener { 23208 /** 23209 * Called when the view is attached to a window. 23210 * @param v The view that was attached 23211 */ 23212 public void onViewAttachedToWindow(View v); 23213 /** 23214 * Called when the view is detached from a window. 23215 * @param v The view that was detached 23216 */ 23217 public void onViewDetachedFromWindow(View v); 23218 } 23219 23220 /** 23221 * Listener for applying window insets on a view in a custom way. 23222 * 23223 * <p>Apps may choose to implement this interface if they want to apply custom policy 23224 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 23225 * is set, its 23226 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 23227 * method will be called instead of the View's own 23228 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 23229 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 23230 * the View's normal behavior as part of its own.</p> 23231 */ 23232 public interface OnApplyWindowInsetsListener { 23233 /** 23234 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 23235 * on a View, this listener method will be called instead of the view's own 23236 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 23237 * 23238 * @param v The view applying window insets 23239 * @param insets The insets to apply 23240 * @return The insets supplied, minus any insets that were consumed 23241 */ 23242 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 23243 } 23244 23245 private final class UnsetPressedState implements Runnable { 23246 @Override 23247 public void run() { 23248 setPressed(false); 23249 } 23250 } 23251 23252 /** 23253 * Base class for derived classes that want to save and restore their own 23254 * state in {@link android.view.View#onSaveInstanceState()}. 23255 */ 23256 public static class BaseSavedState extends AbsSavedState { 23257 String mStartActivityRequestWhoSaved; 23258 23259 /** 23260 * Constructor used when reading from a parcel. Reads the state of the superclass. 23261 * 23262 * @param source parcel to read from 23263 */ 23264 public BaseSavedState(Parcel source) { 23265 this(source, null); 23266 } 23267 23268 /** 23269 * Constructor used when reading from a parcel using a given class loader. 23270 * Reads the state of the superclass. 23271 * 23272 * @param source parcel to read from 23273 * @param loader ClassLoader to use for reading 23274 */ 23275 public BaseSavedState(Parcel source, ClassLoader loader) { 23276 super(source, loader); 23277 mStartActivityRequestWhoSaved = source.readString(); 23278 } 23279 23280 /** 23281 * Constructor called by derived classes when creating their SavedState objects 23282 * 23283 * @param superState The state of the superclass of this view 23284 */ 23285 public BaseSavedState(Parcelable superState) { 23286 super(superState); 23287 } 23288 23289 @Override 23290 public void writeToParcel(Parcel out, int flags) { 23291 super.writeToParcel(out, flags); 23292 out.writeString(mStartActivityRequestWhoSaved); 23293 } 23294 23295 public static final Parcelable.Creator<BaseSavedState> CREATOR 23296 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 23297 @Override 23298 public BaseSavedState createFromParcel(Parcel in) { 23299 return new BaseSavedState(in); 23300 } 23301 23302 @Override 23303 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 23304 return new BaseSavedState(in, loader); 23305 } 23306 23307 @Override 23308 public BaseSavedState[] newArray(int size) { 23309 return new BaseSavedState[size]; 23310 } 23311 }; 23312 } 23313 23314 /** 23315 * A set of information given to a view when it is attached to its parent 23316 * window. 23317 */ 23318 final static class AttachInfo { 23319 interface Callbacks { 23320 void playSoundEffect(int effectId); 23321 boolean performHapticFeedback(int effectId, boolean always); 23322 } 23323 23324 /** 23325 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 23326 * to a Handler. This class contains the target (View) to invalidate and 23327 * the coordinates of the dirty rectangle. 23328 * 23329 * For performance purposes, this class also implements a pool of up to 23330 * POOL_LIMIT objects that get reused. This reduces memory allocations 23331 * whenever possible. 23332 */ 23333 static class InvalidateInfo { 23334 private static final int POOL_LIMIT = 10; 23335 23336 private static final SynchronizedPool<InvalidateInfo> sPool = 23337 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 23338 23339 View target; 23340 23341 int left; 23342 int top; 23343 int right; 23344 int bottom; 23345 23346 public static InvalidateInfo obtain() { 23347 InvalidateInfo instance = sPool.acquire(); 23348 return (instance != null) ? instance : new InvalidateInfo(); 23349 } 23350 23351 public void recycle() { 23352 target = null; 23353 sPool.release(this); 23354 } 23355 } 23356 23357 final IWindowSession mSession; 23358 23359 final IWindow mWindow; 23360 23361 final IBinder mWindowToken; 23362 23363 final Display mDisplay; 23364 23365 final Callbacks mRootCallbacks; 23366 23367 IWindowId mIWindowId; 23368 WindowId mWindowId; 23369 23370 /** 23371 * The top view of the hierarchy. 23372 */ 23373 View mRootView; 23374 23375 IBinder mPanelParentWindowToken; 23376 23377 boolean mHardwareAccelerated; 23378 boolean mHardwareAccelerationRequested; 23379 ThreadedRenderer mThreadedRenderer; 23380 List<RenderNode> mPendingAnimatingRenderNodes; 23381 23382 /** 23383 * The state of the display to which the window is attached, as reported 23384 * by {@link Display#getState()}. Note that the display state constants 23385 * declared by {@link Display} do not exactly line up with the screen state 23386 * constants declared by {@link View} (there are more display states than 23387 * screen states). 23388 */ 23389 int mDisplayState = Display.STATE_UNKNOWN; 23390 23391 /** 23392 * Scale factor used by the compatibility mode 23393 */ 23394 float mApplicationScale; 23395 23396 /** 23397 * Indicates whether the application is in compatibility mode 23398 */ 23399 boolean mScalingRequired; 23400 23401 /** 23402 * Left position of this view's window 23403 */ 23404 int mWindowLeft; 23405 23406 /** 23407 * Top position of this view's window 23408 */ 23409 int mWindowTop; 23410 23411 /** 23412 * Indicates whether views need to use 32-bit drawing caches 23413 */ 23414 boolean mUse32BitDrawingCache; 23415 23416 /** 23417 * For windows that are full-screen but using insets to layout inside 23418 * of the screen areas, these are the current insets to appear inside 23419 * the overscan area of the display. 23420 */ 23421 final Rect mOverscanInsets = new Rect(); 23422 23423 /** 23424 * For windows that are full-screen but using insets to layout inside 23425 * of the screen decorations, these are the current insets for the 23426 * content of the window. 23427 */ 23428 final Rect mContentInsets = new Rect(); 23429 23430 /** 23431 * For windows that are full-screen but using insets to layout inside 23432 * of the screen decorations, these are the current insets for the 23433 * actual visible parts of the window. 23434 */ 23435 final Rect mVisibleInsets = new Rect(); 23436 23437 /** 23438 * For windows that are full-screen but using insets to layout inside 23439 * of the screen decorations, these are the current insets for the 23440 * stable system windows. 23441 */ 23442 final Rect mStableInsets = new Rect(); 23443 23444 /** 23445 * For windows that include areas that are not covered by real surface these are the outsets 23446 * for real surface. 23447 */ 23448 final Rect mOutsets = new Rect(); 23449 23450 /** 23451 * In multi-window we force show the navigation bar. Because we don't want that the surface 23452 * size changes in this mode, we instead have a flag whether the navigation bar size should 23453 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 23454 */ 23455 boolean mAlwaysConsumeNavBar; 23456 23457 /** 23458 * The internal insets given by this window. This value is 23459 * supplied by the client (through 23460 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 23461 * be given to the window manager when changed to be used in laying 23462 * out windows behind it. 23463 */ 23464 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 23465 = new ViewTreeObserver.InternalInsetsInfo(); 23466 23467 /** 23468 * Set to true when mGivenInternalInsets is non-empty. 23469 */ 23470 boolean mHasNonEmptyGivenInternalInsets; 23471 23472 /** 23473 * All views in the window's hierarchy that serve as scroll containers, 23474 * used to determine if the window can be resized or must be panned 23475 * to adjust for a soft input area. 23476 */ 23477 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 23478 23479 final KeyEvent.DispatcherState mKeyDispatchState 23480 = new KeyEvent.DispatcherState(); 23481 23482 /** 23483 * Indicates whether the view's window currently has the focus. 23484 */ 23485 boolean mHasWindowFocus; 23486 23487 /** 23488 * The current visibility of the window. 23489 */ 23490 int mWindowVisibility; 23491 23492 /** 23493 * Indicates the time at which drawing started to occur. 23494 */ 23495 long mDrawingTime; 23496 23497 /** 23498 * Indicates whether or not ignoring the DIRTY_MASK flags. 23499 */ 23500 boolean mIgnoreDirtyState; 23501 23502 /** 23503 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 23504 * to avoid clearing that flag prematurely. 23505 */ 23506 boolean mSetIgnoreDirtyState = false; 23507 23508 /** 23509 * Indicates whether the view's window is currently in touch mode. 23510 */ 23511 boolean mInTouchMode; 23512 23513 /** 23514 * Indicates whether the view has requested unbuffered input dispatching for the current 23515 * event stream. 23516 */ 23517 boolean mUnbufferedDispatchRequested; 23518 23519 /** 23520 * Indicates that ViewAncestor should trigger a global layout change 23521 * the next time it performs a traversal 23522 */ 23523 boolean mRecomputeGlobalAttributes; 23524 23525 /** 23526 * Always report new attributes at next traversal. 23527 */ 23528 boolean mForceReportNewAttributes; 23529 23530 /** 23531 * Set during a traveral if any views want to keep the screen on. 23532 */ 23533 boolean mKeepScreenOn; 23534 23535 /** 23536 * Set during a traveral if the light center needs to be updated. 23537 */ 23538 boolean mNeedsUpdateLightCenter; 23539 23540 /** 23541 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 23542 */ 23543 int mSystemUiVisibility; 23544 23545 /** 23546 * Hack to force certain system UI visibility flags to be cleared. 23547 */ 23548 int mDisabledSystemUiVisibility; 23549 23550 /** 23551 * Last global system UI visibility reported by the window manager. 23552 */ 23553 int mGlobalSystemUiVisibility = -1; 23554 23555 /** 23556 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 23557 * attached. 23558 */ 23559 boolean mHasSystemUiListeners; 23560 23561 /** 23562 * Set if the window has requested to extend into the overscan region 23563 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 23564 */ 23565 boolean mOverscanRequested; 23566 23567 /** 23568 * Set if the visibility of any views has changed. 23569 */ 23570 boolean mViewVisibilityChanged; 23571 23572 /** 23573 * Set to true if a view has been scrolled. 23574 */ 23575 boolean mViewScrollChanged; 23576 23577 /** 23578 * Set to true if high contrast mode enabled 23579 */ 23580 boolean mHighContrastText; 23581 23582 /** 23583 * Set to true if a pointer event is currently being handled. 23584 */ 23585 boolean mHandlingPointerEvent; 23586 23587 /** 23588 * Global to the view hierarchy used as a temporary for dealing with 23589 * x/y points in the transparent region computations. 23590 */ 23591 final int[] mTransparentLocation = new int[2]; 23592 23593 /** 23594 * Global to the view hierarchy used as a temporary for dealing with 23595 * x/y points in the ViewGroup.invalidateChild implementation. 23596 */ 23597 final int[] mInvalidateChildLocation = new int[2]; 23598 23599 /** 23600 * Global to the view hierarchy used as a temporary for dealing with 23601 * computing absolute on-screen location. 23602 */ 23603 final int[] mTmpLocation = new int[2]; 23604 23605 /** 23606 * Global to the view hierarchy used as a temporary for dealing with 23607 * x/y location when view is transformed. 23608 */ 23609 final float[] mTmpTransformLocation = new float[2]; 23610 23611 /** 23612 * The view tree observer used to dispatch global events like 23613 * layout, pre-draw, touch mode change, etc. 23614 */ 23615 final ViewTreeObserver mTreeObserver; 23616 23617 /** 23618 * A Canvas used by the view hierarchy to perform bitmap caching. 23619 */ 23620 Canvas mCanvas; 23621 23622 /** 23623 * The view root impl. 23624 */ 23625 final ViewRootImpl mViewRootImpl; 23626 23627 /** 23628 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 23629 * handler can be used to pump events in the UI events queue. 23630 */ 23631 final Handler mHandler; 23632 23633 /** 23634 * Temporary for use in computing invalidate rectangles while 23635 * calling up the hierarchy. 23636 */ 23637 final Rect mTmpInvalRect = new Rect(); 23638 23639 /** 23640 * Temporary for use in computing hit areas with transformed views 23641 */ 23642 final RectF mTmpTransformRect = new RectF(); 23643 23644 /** 23645 * Temporary for use in computing hit areas with transformed views 23646 */ 23647 final RectF mTmpTransformRect1 = new RectF(); 23648 23649 /** 23650 * Temporary list of rectanges. 23651 */ 23652 final List<RectF> mTmpRectList = new ArrayList<>(); 23653 23654 /** 23655 * Temporary for use in transforming invalidation rect 23656 */ 23657 final Matrix mTmpMatrix = new Matrix(); 23658 23659 /** 23660 * Temporary for use in transforming invalidation rect 23661 */ 23662 final Transformation mTmpTransformation = new Transformation(); 23663 23664 /** 23665 * Temporary for use in querying outlines from OutlineProviders 23666 */ 23667 final Outline mTmpOutline = new Outline(); 23668 23669 /** 23670 * Temporary list for use in collecting focusable descendents of a view. 23671 */ 23672 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 23673 23674 /** 23675 * The id of the window for accessibility purposes. 23676 */ 23677 int mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 23678 23679 /** 23680 * Flags related to accessibility processing. 23681 * 23682 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 23683 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 23684 */ 23685 int mAccessibilityFetchFlags; 23686 23687 /** 23688 * The drawable for highlighting accessibility focus. 23689 */ 23690 Drawable mAccessibilityFocusDrawable; 23691 23692 /** 23693 * Show where the margins, bounds and layout bounds are for each view. 23694 */ 23695 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 23696 23697 /** 23698 * Point used to compute visible regions. 23699 */ 23700 final Point mPoint = new Point(); 23701 23702 /** 23703 * Used to track which View originated a requestLayout() call, used when 23704 * requestLayout() is called during layout. 23705 */ 23706 View mViewRequestingLayout; 23707 23708 /** 23709 * Used to track views that need (at least) a partial relayout at their current size 23710 * during the next traversal. 23711 */ 23712 List<View> mPartialLayoutViews = new ArrayList<>(); 23713 23714 /** 23715 * Swapped with mPartialLayoutViews during layout to avoid concurrent 23716 * modification. Lazily assigned during ViewRootImpl layout. 23717 */ 23718 List<View> mEmptyPartialLayoutViews; 23719 23720 /** 23721 * Used to track the identity of the current drag operation. 23722 */ 23723 IBinder mDragToken; 23724 23725 /** 23726 * The drag shadow surface for the current drag operation. 23727 */ 23728 public Surface mDragSurface; 23729 23730 23731 /** 23732 * The view that currently has a tooltip displayed. 23733 */ 23734 View mTooltipHost; 23735 23736 /** 23737 * Creates a new set of attachment information with the specified 23738 * events handler and thread. 23739 * 23740 * @param handler the events handler the view must use 23741 */ 23742 AttachInfo(IWindowSession session, IWindow window, Display display, 23743 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 23744 Context context) { 23745 mSession = session; 23746 mWindow = window; 23747 mWindowToken = window.asBinder(); 23748 mDisplay = display; 23749 mViewRootImpl = viewRootImpl; 23750 mHandler = handler; 23751 mRootCallbacks = effectPlayer; 23752 mTreeObserver = new ViewTreeObserver(context); 23753 } 23754 } 23755 23756 /** 23757 * <p>ScrollabilityCache holds various fields used by a View when scrolling 23758 * is supported. This avoids keeping too many unused fields in most 23759 * instances of View.</p> 23760 */ 23761 private static class ScrollabilityCache implements Runnable { 23762 23763 /** 23764 * Scrollbars are not visible 23765 */ 23766 public static final int OFF = 0; 23767 23768 /** 23769 * Scrollbars are visible 23770 */ 23771 public static final int ON = 1; 23772 23773 /** 23774 * Scrollbars are fading away 23775 */ 23776 public static final int FADING = 2; 23777 23778 public boolean fadeScrollBars; 23779 23780 public int fadingEdgeLength; 23781 public int scrollBarDefaultDelayBeforeFade; 23782 public int scrollBarFadeDuration; 23783 23784 public int scrollBarSize; 23785 public ScrollBarDrawable scrollBar; 23786 public float[] interpolatorValues; 23787 public View host; 23788 23789 public final Paint paint; 23790 public final Matrix matrix; 23791 public Shader shader; 23792 23793 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 23794 23795 private static final float[] OPAQUE = { 255 }; 23796 private static final float[] TRANSPARENT = { 0.0f }; 23797 23798 /** 23799 * When fading should start. This time moves into the future every time 23800 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 23801 */ 23802 public long fadeStartTime; 23803 23804 23805 /** 23806 * The current state of the scrollbars: ON, OFF, or FADING 23807 */ 23808 public int state = OFF; 23809 23810 private int mLastColor; 23811 23812 public final Rect mScrollBarBounds = new Rect(); 23813 23814 public static final int NOT_DRAGGING = 0; 23815 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 23816 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 23817 public int mScrollBarDraggingState = NOT_DRAGGING; 23818 23819 public float mScrollBarDraggingPos = 0; 23820 23821 public ScrollabilityCache(ViewConfiguration configuration, View host) { 23822 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 23823 scrollBarSize = configuration.getScaledScrollBarSize(); 23824 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 23825 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 23826 23827 paint = new Paint(); 23828 matrix = new Matrix(); 23829 // use use a height of 1, and then wack the matrix each time we 23830 // actually use it. 23831 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 23832 paint.setShader(shader); 23833 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 23834 23835 this.host = host; 23836 } 23837 23838 public void setFadeColor(int color) { 23839 if (color != mLastColor) { 23840 mLastColor = color; 23841 23842 if (color != 0) { 23843 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 23844 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 23845 paint.setShader(shader); 23846 // Restore the default transfer mode (src_over) 23847 paint.setXfermode(null); 23848 } else { 23849 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 23850 paint.setShader(shader); 23851 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 23852 } 23853 } 23854 } 23855 23856 public void run() { 23857 long now = AnimationUtils.currentAnimationTimeMillis(); 23858 if (now >= fadeStartTime) { 23859 23860 // the animation fades the scrollbars out by changing 23861 // the opacity (alpha) from fully opaque to fully 23862 // transparent 23863 int nextFrame = (int) now; 23864 int framesCount = 0; 23865 23866 Interpolator interpolator = scrollBarInterpolator; 23867 23868 // Start opaque 23869 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 23870 23871 // End transparent 23872 nextFrame += scrollBarFadeDuration; 23873 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 23874 23875 state = FADING; 23876 23877 // Kick off the fade animation 23878 host.invalidate(true); 23879 } 23880 } 23881 } 23882 23883 /** 23884 * Resuable callback for sending 23885 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 23886 */ 23887 private class SendViewScrolledAccessibilityEvent implements Runnable { 23888 public volatile boolean mIsPending; 23889 23890 public void run() { 23891 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 23892 mIsPending = false; 23893 } 23894 } 23895 23896 /** 23897 * <p> 23898 * This class represents a delegate that can be registered in a {@link View} 23899 * to enhance accessibility support via composition rather via inheritance. 23900 * It is specifically targeted to widget developers that extend basic View 23901 * classes i.e. classes in package android.view, that would like their 23902 * applications to be backwards compatible. 23903 * </p> 23904 * <div class="special reference"> 23905 * <h3>Developer Guides</h3> 23906 * <p>For more information about making applications accessible, read the 23907 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 23908 * developer guide.</p> 23909 * </div> 23910 * <p> 23911 * A scenario in which a developer would like to use an accessibility delegate 23912 * is overriding a method introduced in a later API version than the minimal API 23913 * version supported by the application. For example, the method 23914 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 23915 * in API version 4 when the accessibility APIs were first introduced. If a 23916 * developer would like his application to run on API version 4 devices (assuming 23917 * all other APIs used by the application are version 4 or lower) and take advantage 23918 * of this method, instead of overriding the method which would break the application's 23919 * backwards compatibility, he can override the corresponding method in this 23920 * delegate and register the delegate in the target View if the API version of 23921 * the system is high enough, i.e. the API version is the same as or higher than the API 23922 * version that introduced 23923 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 23924 * </p> 23925 * <p> 23926 * Here is an example implementation: 23927 * </p> 23928 * <code><pre><p> 23929 * if (Build.VERSION.SDK_INT >= 14) { 23930 * // If the API version is equal of higher than the version in 23931 * // which onInitializeAccessibilityNodeInfo was introduced we 23932 * // register a delegate with a customized implementation. 23933 * View view = findViewById(R.id.view_id); 23934 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 23935 * public void onInitializeAccessibilityNodeInfo(View host, 23936 * AccessibilityNodeInfo info) { 23937 * // Let the default implementation populate the info. 23938 * super.onInitializeAccessibilityNodeInfo(host, info); 23939 * // Set some other information. 23940 * info.setEnabled(host.isEnabled()); 23941 * } 23942 * }); 23943 * } 23944 * </code></pre></p> 23945 * <p> 23946 * This delegate contains methods that correspond to the accessibility methods 23947 * in View. If a delegate has been specified the implementation in View hands 23948 * off handling to the corresponding method in this delegate. The default 23949 * implementation the delegate methods behaves exactly as the corresponding 23950 * method in View for the case of no accessibility delegate been set. Hence, 23951 * to customize the behavior of a View method, clients can override only the 23952 * corresponding delegate method without altering the behavior of the rest 23953 * accessibility related methods of the host view. 23954 * </p> 23955 * <p> 23956 * <strong>Note:</strong> On platform versions prior to 23957 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 23958 * views in the {@code android.widget.*} package are called <i>before</i> 23959 * host methods. This prevents certain properties such as class name from 23960 * being modified by overriding 23961 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 23962 * as any changes will be overwritten by the host class. 23963 * <p> 23964 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 23965 * methods are called <i>after</i> host methods, which all properties to be 23966 * modified without being overwritten by the host class. 23967 */ 23968 public static class AccessibilityDelegate { 23969 23970 /** 23971 * Sends an accessibility event of the given type. If accessibility is not 23972 * enabled this method has no effect. 23973 * <p> 23974 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 23975 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 23976 * been set. 23977 * </p> 23978 * 23979 * @param host The View hosting the delegate. 23980 * @param eventType The type of the event to send. 23981 * 23982 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 23983 */ 23984 public void sendAccessibilityEvent(View host, int eventType) { 23985 host.sendAccessibilityEventInternal(eventType); 23986 } 23987 23988 /** 23989 * Performs the specified accessibility action on the view. For 23990 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 23991 * <p> 23992 * The default implementation behaves as 23993 * {@link View#performAccessibilityAction(int, Bundle) 23994 * View#performAccessibilityAction(int, Bundle)} for the case of 23995 * no accessibility delegate been set. 23996 * </p> 23997 * 23998 * @param action The action to perform. 23999 * @return Whether the action was performed. 24000 * 24001 * @see View#performAccessibilityAction(int, Bundle) 24002 * View#performAccessibilityAction(int, Bundle) 24003 */ 24004 public boolean performAccessibilityAction(View host, int action, Bundle args) { 24005 return host.performAccessibilityActionInternal(action, args); 24006 } 24007 24008 /** 24009 * Sends an accessibility event. This method behaves exactly as 24010 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 24011 * empty {@link AccessibilityEvent} and does not perform a check whether 24012 * accessibility is enabled. 24013 * <p> 24014 * The default implementation behaves as 24015 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24016 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 24017 * the case of no accessibility delegate been set. 24018 * </p> 24019 * 24020 * @param host The View hosting the delegate. 24021 * @param event The event to send. 24022 * 24023 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24024 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24025 */ 24026 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 24027 host.sendAccessibilityEventUncheckedInternal(event); 24028 } 24029 24030 /** 24031 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 24032 * to its children for adding their text content to the event. 24033 * <p> 24034 * The default implementation behaves as 24035 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24036 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 24037 * the case of no accessibility delegate been set. 24038 * </p> 24039 * 24040 * @param host The View hosting the delegate. 24041 * @param event The event. 24042 * @return True if the event population was completed. 24043 * 24044 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24045 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24046 */ 24047 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 24048 return host.dispatchPopulateAccessibilityEventInternal(event); 24049 } 24050 24051 /** 24052 * Gives a chance to the host View to populate the accessibility event with its 24053 * text content. 24054 * <p> 24055 * The default implementation behaves as 24056 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 24057 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 24058 * the case of no accessibility delegate been set. 24059 * </p> 24060 * 24061 * @param host The View hosting the delegate. 24062 * @param event The accessibility event which to populate. 24063 * 24064 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 24065 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 24066 */ 24067 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 24068 host.onPopulateAccessibilityEventInternal(event); 24069 } 24070 24071 /** 24072 * Initializes an {@link AccessibilityEvent} with information about the 24073 * the host View which is the event source. 24074 * <p> 24075 * The default implementation behaves as 24076 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 24077 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 24078 * the case of no accessibility delegate been set. 24079 * </p> 24080 * 24081 * @param host The View hosting the delegate. 24082 * @param event The event to initialize. 24083 * 24084 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 24085 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 24086 */ 24087 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 24088 host.onInitializeAccessibilityEventInternal(event); 24089 } 24090 24091 /** 24092 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 24093 * <p> 24094 * The default implementation behaves as 24095 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24096 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 24097 * the case of no accessibility delegate been set. 24098 * </p> 24099 * 24100 * @param host The View hosting the delegate. 24101 * @param info The instance to initialize. 24102 * 24103 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24104 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24105 */ 24106 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 24107 host.onInitializeAccessibilityNodeInfoInternal(info); 24108 } 24109 24110 /** 24111 * Called when a child of the host View has requested sending an 24112 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 24113 * to augment the event. 24114 * <p> 24115 * The default implementation behaves as 24116 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24117 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 24118 * the case of no accessibility delegate been set. 24119 * </p> 24120 * 24121 * @param host The View hosting the delegate. 24122 * @param child The child which requests sending the event. 24123 * @param event The event to be sent. 24124 * @return True if the event should be sent 24125 * 24126 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24127 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24128 */ 24129 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 24130 AccessibilityEvent event) { 24131 return host.onRequestSendAccessibilityEventInternal(child, event); 24132 } 24133 24134 /** 24135 * Gets the provider for managing a virtual view hierarchy rooted at this View 24136 * and reported to {@link android.accessibilityservice.AccessibilityService}s 24137 * that explore the window content. 24138 * <p> 24139 * The default implementation behaves as 24140 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 24141 * the case of no accessibility delegate been set. 24142 * </p> 24143 * 24144 * @return The provider. 24145 * 24146 * @see AccessibilityNodeProvider 24147 */ 24148 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 24149 return null; 24150 } 24151 24152 /** 24153 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 24154 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 24155 * This method is responsible for obtaining an accessibility node info from a 24156 * pool of reusable instances and calling 24157 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 24158 * view to initialize the former. 24159 * <p> 24160 * <strong>Note:</strong> The client is responsible for recycling the obtained 24161 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 24162 * creation. 24163 * </p> 24164 * <p> 24165 * The default implementation behaves as 24166 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 24167 * the case of no accessibility delegate been set. 24168 * </p> 24169 * @return A populated {@link AccessibilityNodeInfo}. 24170 * 24171 * @see AccessibilityNodeInfo 24172 * 24173 * @hide 24174 */ 24175 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 24176 return host.createAccessibilityNodeInfoInternal(); 24177 } 24178 } 24179 24180 private class MatchIdPredicate implements Predicate<View> { 24181 public int mId; 24182 24183 @Override 24184 public boolean apply(View view) { 24185 return (view.mID == mId); 24186 } 24187 } 24188 24189 private class MatchLabelForPredicate implements Predicate<View> { 24190 private int mLabeledId; 24191 24192 @Override 24193 public boolean apply(View view) { 24194 return (view.mLabelForId == mLabeledId); 24195 } 24196 } 24197 24198 private class SendViewStateChangedAccessibilityEvent implements Runnable { 24199 private int mChangeTypes = 0; 24200 private boolean mPosted; 24201 private boolean mPostedWithDelay; 24202 private long mLastEventTimeMillis; 24203 24204 @Override 24205 public void run() { 24206 mPosted = false; 24207 mPostedWithDelay = false; 24208 mLastEventTimeMillis = SystemClock.uptimeMillis(); 24209 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 24210 final AccessibilityEvent event = AccessibilityEvent.obtain(); 24211 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 24212 event.setContentChangeTypes(mChangeTypes); 24213 sendAccessibilityEventUnchecked(event); 24214 } 24215 mChangeTypes = 0; 24216 } 24217 24218 public void runOrPost(int changeType) { 24219 mChangeTypes |= changeType; 24220 24221 // If this is a live region or the child of a live region, collect 24222 // all events from this frame and send them on the next frame. 24223 if (inLiveRegion()) { 24224 // If we're already posted with a delay, remove that. 24225 if (mPostedWithDelay) { 24226 removeCallbacks(this); 24227 mPostedWithDelay = false; 24228 } 24229 // Only post if we're not already posted. 24230 if (!mPosted) { 24231 post(this); 24232 mPosted = true; 24233 } 24234 return; 24235 } 24236 24237 if (mPosted) { 24238 return; 24239 } 24240 24241 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 24242 final long minEventIntevalMillis = 24243 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 24244 if (timeSinceLastMillis >= minEventIntevalMillis) { 24245 removeCallbacks(this); 24246 run(); 24247 } else { 24248 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 24249 mPostedWithDelay = true; 24250 } 24251 } 24252 } 24253 24254 private boolean inLiveRegion() { 24255 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24256 return true; 24257 } 24258 24259 ViewParent parent = getParent(); 24260 while (parent instanceof View) { 24261 if (((View) parent).getAccessibilityLiveRegion() 24262 != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24263 return true; 24264 } 24265 parent = parent.getParent(); 24266 } 24267 24268 return false; 24269 } 24270 24271 /** 24272 * Dump all private flags in readable format, useful for documentation and 24273 * sanity checking. 24274 */ 24275 private static void dumpFlags() { 24276 final HashMap<String, String> found = Maps.newHashMap(); 24277 try { 24278 for (Field field : View.class.getDeclaredFields()) { 24279 final int modifiers = field.getModifiers(); 24280 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 24281 if (field.getType().equals(int.class)) { 24282 final int value = field.getInt(null); 24283 dumpFlag(found, field.getName(), value); 24284 } else if (field.getType().equals(int[].class)) { 24285 final int[] values = (int[]) field.get(null); 24286 for (int i = 0; i < values.length; i++) { 24287 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 24288 } 24289 } 24290 } 24291 } 24292 } catch (IllegalAccessException e) { 24293 throw new RuntimeException(e); 24294 } 24295 24296 final ArrayList<String> keys = Lists.newArrayList(); 24297 keys.addAll(found.keySet()); 24298 Collections.sort(keys); 24299 for (String key : keys) { 24300 Log.d(VIEW_LOG_TAG, found.get(key)); 24301 } 24302 } 24303 24304 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 24305 // Sort flags by prefix, then by bits, always keeping unique keys 24306 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 24307 final int prefix = name.indexOf('_'); 24308 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 24309 final String output = bits + " " + name; 24310 found.put(key, output); 24311 } 24312 24313 /** {@hide} */ 24314 public void encode(@NonNull ViewHierarchyEncoder stream) { 24315 stream.beginObject(this); 24316 encodeProperties(stream); 24317 stream.endObject(); 24318 } 24319 24320 /** {@hide} */ 24321 @CallSuper 24322 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 24323 Object resolveId = ViewDebug.resolveId(getContext(), mID); 24324 if (resolveId instanceof String) { 24325 stream.addProperty("id", (String) resolveId); 24326 } else { 24327 stream.addProperty("id", mID); 24328 } 24329 24330 stream.addProperty("misc:transformation.alpha", 24331 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 24332 stream.addProperty("misc:transitionName", getTransitionName()); 24333 24334 // layout 24335 stream.addProperty("layout:left", mLeft); 24336 stream.addProperty("layout:right", mRight); 24337 stream.addProperty("layout:top", mTop); 24338 stream.addProperty("layout:bottom", mBottom); 24339 stream.addProperty("layout:width", getWidth()); 24340 stream.addProperty("layout:height", getHeight()); 24341 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 24342 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 24343 stream.addProperty("layout:hasTransientState", hasTransientState()); 24344 stream.addProperty("layout:baseline", getBaseline()); 24345 24346 // layout params 24347 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 24348 if (layoutParams != null) { 24349 stream.addPropertyKey("layoutParams"); 24350 layoutParams.encode(stream); 24351 } 24352 24353 // scrolling 24354 stream.addProperty("scrolling:scrollX", mScrollX); 24355 stream.addProperty("scrolling:scrollY", mScrollY); 24356 24357 // padding 24358 stream.addProperty("padding:paddingLeft", mPaddingLeft); 24359 stream.addProperty("padding:paddingRight", mPaddingRight); 24360 stream.addProperty("padding:paddingTop", mPaddingTop); 24361 stream.addProperty("padding:paddingBottom", mPaddingBottom); 24362 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 24363 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 24364 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 24365 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 24366 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 24367 24368 // measurement 24369 stream.addProperty("measurement:minHeight", mMinHeight); 24370 stream.addProperty("measurement:minWidth", mMinWidth); 24371 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 24372 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 24373 24374 // drawing 24375 stream.addProperty("drawing:elevation", getElevation()); 24376 stream.addProperty("drawing:translationX", getTranslationX()); 24377 stream.addProperty("drawing:translationY", getTranslationY()); 24378 stream.addProperty("drawing:translationZ", getTranslationZ()); 24379 stream.addProperty("drawing:rotation", getRotation()); 24380 stream.addProperty("drawing:rotationX", getRotationX()); 24381 stream.addProperty("drawing:rotationY", getRotationY()); 24382 stream.addProperty("drawing:scaleX", getScaleX()); 24383 stream.addProperty("drawing:scaleY", getScaleY()); 24384 stream.addProperty("drawing:pivotX", getPivotX()); 24385 stream.addProperty("drawing:pivotY", getPivotY()); 24386 stream.addProperty("drawing:opaque", isOpaque()); 24387 stream.addProperty("drawing:alpha", getAlpha()); 24388 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 24389 stream.addProperty("drawing:shadow", hasShadow()); 24390 stream.addProperty("drawing:solidColor", getSolidColor()); 24391 stream.addProperty("drawing:layerType", mLayerType); 24392 stream.addProperty("drawing:willNotDraw", willNotDraw()); 24393 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 24394 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 24395 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 24396 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 24397 24398 // focus 24399 stream.addProperty("focus:hasFocus", hasFocus()); 24400 stream.addProperty("focus:isFocused", isFocused()); 24401 stream.addProperty("focus:isFocusable", isFocusable()); 24402 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 24403 24404 stream.addProperty("misc:clickable", isClickable()); 24405 stream.addProperty("misc:pressed", isPressed()); 24406 stream.addProperty("misc:selected", isSelected()); 24407 stream.addProperty("misc:touchMode", isInTouchMode()); 24408 stream.addProperty("misc:hovered", isHovered()); 24409 stream.addProperty("misc:activated", isActivated()); 24410 24411 stream.addProperty("misc:visibility", getVisibility()); 24412 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 24413 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 24414 24415 stream.addProperty("misc:enabled", isEnabled()); 24416 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 24417 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 24418 24419 // theme attributes 24420 Resources.Theme theme = getContext().getTheme(); 24421 if (theme != null) { 24422 stream.addPropertyKey("theme"); 24423 theme.encode(stream); 24424 } 24425 24426 // view attribute information 24427 int n = mAttributes != null ? mAttributes.length : 0; 24428 stream.addProperty("meta:__attrCount__", n/2); 24429 for (int i = 0; i < n; i += 2) { 24430 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 24431 } 24432 24433 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 24434 24435 // text 24436 stream.addProperty("text:textDirection", getTextDirection()); 24437 stream.addProperty("text:textAlignment", getTextAlignment()); 24438 24439 // accessibility 24440 CharSequence contentDescription = getContentDescription(); 24441 stream.addProperty("accessibility:contentDescription", 24442 contentDescription == null ? "" : contentDescription.toString()); 24443 stream.addProperty("accessibility:labelFor", getLabelFor()); 24444 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 24445 } 24446 24447 /** 24448 * Determine if this view is rendered on a round wearable device and is the main view 24449 * on the screen. 24450 */ 24451 private boolean shouldDrawRoundScrollbar() { 24452 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 24453 return false; 24454 } 24455 24456 final View rootView = getRootView(); 24457 final WindowInsets insets = getRootWindowInsets(); 24458 24459 int height = getHeight(); 24460 int width = getWidth(); 24461 int displayHeight = rootView.getHeight(); 24462 int displayWidth = rootView.getWidth(); 24463 24464 if (height != displayHeight || width != displayWidth) { 24465 return false; 24466 } 24467 24468 getLocationOnScreen(mAttachInfo.mTmpLocation); 24469 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 24470 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 24471 } 24472 24473 /** 24474 * Sets the tooltip text which will be displayed in a small popup next to the view. 24475 * <p> 24476 * The tooltip will be displayed: 24477 * <li>On long click, unless is not handled otherwise (by OnLongClickListener or a context 24478 * menu). </li> 24479 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 24480 * 24481 * @param tooltip the tooltip text, or null if no tooltip is required 24482 */ 24483 public final void setTooltip(@Nullable CharSequence tooltip) { 24484 if (TextUtils.isEmpty(tooltip)) { 24485 setFlags(0, TOOLTIP); 24486 hideTooltip(); 24487 mTooltipInfo = null; 24488 } else { 24489 setFlags(TOOLTIP, TOOLTIP); 24490 if (mTooltipInfo == null) { 24491 mTooltipInfo = new TooltipInfo(); 24492 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 24493 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 24494 } 24495 mTooltipInfo.mTooltip = tooltip; 24496 if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) { 24497 mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltip); 24498 } 24499 } 24500 } 24501 24502 /** 24503 * Returns the view's tooltip text. 24504 * 24505 * @return the tooltip text 24506 */ 24507 @Nullable 24508 public final CharSequence getTooltip() { 24509 return mTooltipInfo != null ? mTooltipInfo.mTooltip : null; 24510 } 24511 24512 private boolean showTooltip(int x, int y, boolean fromLongClick) { 24513 if (mAttachInfo == null) { 24514 return false; 24515 } 24516 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 24517 return false; 24518 } 24519 final CharSequence tooltipText = getTooltip(); 24520 if (TextUtils.isEmpty(tooltipText)) { 24521 return false; 24522 } 24523 hideTooltip(); 24524 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 24525 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 24526 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 24527 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, tooltipText); 24528 mAttachInfo.mTooltipHost = this; 24529 return true; 24530 } 24531 24532 void hideTooltip() { 24533 if (mTooltipInfo == null) { 24534 return; 24535 } 24536 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24537 if (mTooltipInfo.mTooltipPopup == null) { 24538 return; 24539 } 24540 mTooltipInfo.mTooltipPopup.hide(); 24541 mTooltipInfo.mTooltipPopup = null; 24542 mTooltipInfo.mTooltipFromLongClick = false; 24543 if (mAttachInfo != null) { 24544 mAttachInfo.mTooltipHost = null; 24545 } 24546 } 24547 24548 private boolean showLongClickTooltip(int x, int y) { 24549 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24550 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24551 return showTooltip(x, y, true); 24552 } 24553 24554 private void showHoverTooltip() { 24555 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 24556 } 24557 24558 boolean dispatchTooltipHoverEvent(MotionEvent event) { 24559 if (mTooltipInfo == null) { 24560 return false; 24561 } 24562 switch(event.getAction()) { 24563 case MotionEvent.ACTION_HOVER_MOVE: 24564 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 24565 break; 24566 } 24567 if (!mTooltipInfo.mTooltipFromLongClick) { 24568 if (mTooltipInfo.mTooltipPopup == null) { 24569 // Schedule showing the tooltip after a timeout. 24570 mTooltipInfo.mAnchorX = (int) event.getX(); 24571 mTooltipInfo.mAnchorY = (int) event.getY(); 24572 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24573 postDelayed(mTooltipInfo.mShowTooltipRunnable, 24574 ViewConfiguration.getHoverTooltipShowTimeout()); 24575 } 24576 24577 // Hide hover-triggered tooltip after a period of inactivity. 24578 // Match the timeout used by NativeInputManager to hide the mouse pointer 24579 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 24580 final int timeout; 24581 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 24582 == SYSTEM_UI_FLAG_LOW_PROFILE) { 24583 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 24584 } else { 24585 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 24586 } 24587 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24588 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 24589 } 24590 return true; 24591 24592 case MotionEvent.ACTION_HOVER_EXIT: 24593 if (!mTooltipInfo.mTooltipFromLongClick) { 24594 hideTooltip(); 24595 } 24596 break; 24597 } 24598 return false; 24599 } 24600 24601 void handleTooltipKey(KeyEvent event) { 24602 switch (event.getAction()) { 24603 case KeyEvent.ACTION_DOWN: 24604 if (event.getRepeatCount() == 0) { 24605 hideTooltip(); 24606 } 24607 break; 24608 24609 case KeyEvent.ACTION_UP: 24610 handleTooltipUp(); 24611 break; 24612 } 24613 } 24614 24615 private void handleTooltipUp() { 24616 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 24617 return; 24618 } 24619 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24620 postDelayed(mTooltipInfo.mHideTooltipRunnable, 24621 ViewConfiguration.getLongPressTooltipHideTimeout()); 24622 } 24623 24624 /** 24625 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 24626 * is not showing. 24627 * @hide 24628 */ 24629 @TestApi 24630 public View getTooltipView() { 24631 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 24632 return null; 24633 } 24634 return mTooltipInfo.mTooltipPopup.getContentView(); 24635 } 24636} 24637