View.java revision 8102d91377367b9cd63d221da8354436815e7679
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 /** 1252 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1253 * item. 1254 */ 1255 public static final int FOCUS_BACKWARD = 0x00000001; 1256 1257 /** 1258 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1259 * item. 1260 */ 1261 public static final int FOCUS_FORWARD = 0x00000002; 1262 1263 /** 1264 * Use with {@link #focusSearch(int)}. Move focus to the left. 1265 */ 1266 public static final int FOCUS_LEFT = 0x00000011; 1267 1268 /** 1269 * Use with {@link #focusSearch(int)}. Move focus up. 1270 */ 1271 public static final int FOCUS_UP = 0x00000021; 1272 1273 /** 1274 * Use with {@link #focusSearch(int)}. Move focus to the right. 1275 */ 1276 public static final int FOCUS_RIGHT = 0x00000042; 1277 1278 /** 1279 * Use with {@link #focusSearch(int)}. Move focus down. 1280 */ 1281 public static final int FOCUS_DOWN = 0x00000082; 1282 1283 /** 1284 * Bits of {@link #getMeasuredWidthAndState()} and 1285 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1286 */ 1287 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1288 1289 /** 1290 * Bits of {@link #getMeasuredWidthAndState()} and 1291 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1292 */ 1293 public static final int MEASURED_STATE_MASK = 0xff000000; 1294 1295 /** 1296 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1297 * for functions that combine both width and height into a single int, 1298 * such as {@link #getMeasuredState()} and the childState argument of 1299 * {@link #resolveSizeAndState(int, int, int)}. 1300 */ 1301 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1302 1303 /** 1304 * Bit of {@link #getMeasuredWidthAndState()} and 1305 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1306 * is smaller that the space the view would like to have. 1307 */ 1308 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1309 1310 /** 1311 * Base View state sets 1312 */ 1313 // Singles 1314 /** 1315 * Indicates the view has no states set. States are used with 1316 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1317 * view depending on its state. 1318 * 1319 * @see android.graphics.drawable.Drawable 1320 * @see #getDrawableState() 1321 */ 1322 protected static final int[] EMPTY_STATE_SET; 1323 /** 1324 * Indicates the view is enabled. States are used with 1325 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1326 * view depending on its state. 1327 * 1328 * @see android.graphics.drawable.Drawable 1329 * @see #getDrawableState() 1330 */ 1331 protected static final int[] ENABLED_STATE_SET; 1332 /** 1333 * Indicates the view is focused. States are used with 1334 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1335 * view depending on its state. 1336 * 1337 * @see android.graphics.drawable.Drawable 1338 * @see #getDrawableState() 1339 */ 1340 protected static final int[] FOCUSED_STATE_SET; 1341 /** 1342 * Indicates the view is selected. States are used with 1343 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1344 * view depending on its state. 1345 * 1346 * @see android.graphics.drawable.Drawable 1347 * @see #getDrawableState() 1348 */ 1349 protected static final int[] SELECTED_STATE_SET; 1350 /** 1351 * Indicates the view is pressed. States are used with 1352 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1353 * view depending on its state. 1354 * 1355 * @see android.graphics.drawable.Drawable 1356 * @see #getDrawableState() 1357 */ 1358 protected static final int[] PRESSED_STATE_SET; 1359 /** 1360 * Indicates the view's window has focus. States are used with 1361 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1362 * view depending on its state. 1363 * 1364 * @see android.graphics.drawable.Drawable 1365 * @see #getDrawableState() 1366 */ 1367 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1368 // Doubles 1369 /** 1370 * Indicates the view is enabled and has the focus. 1371 * 1372 * @see #ENABLED_STATE_SET 1373 * @see #FOCUSED_STATE_SET 1374 */ 1375 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1376 /** 1377 * Indicates the view is enabled and selected. 1378 * 1379 * @see #ENABLED_STATE_SET 1380 * @see #SELECTED_STATE_SET 1381 */ 1382 protected static final int[] ENABLED_SELECTED_STATE_SET; 1383 /** 1384 * Indicates the view is enabled and that its window has focus. 1385 * 1386 * @see #ENABLED_STATE_SET 1387 * @see #WINDOW_FOCUSED_STATE_SET 1388 */ 1389 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1390 /** 1391 * Indicates the view is focused and selected. 1392 * 1393 * @see #FOCUSED_STATE_SET 1394 * @see #SELECTED_STATE_SET 1395 */ 1396 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1397 /** 1398 * Indicates the view has the focus and that its window has the focus. 1399 * 1400 * @see #FOCUSED_STATE_SET 1401 * @see #WINDOW_FOCUSED_STATE_SET 1402 */ 1403 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1404 /** 1405 * Indicates the view is selected and that its window has the focus. 1406 * 1407 * @see #SELECTED_STATE_SET 1408 * @see #WINDOW_FOCUSED_STATE_SET 1409 */ 1410 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1411 // Triples 1412 /** 1413 * Indicates the view is enabled, focused and selected. 1414 * 1415 * @see #ENABLED_STATE_SET 1416 * @see #FOCUSED_STATE_SET 1417 * @see #SELECTED_STATE_SET 1418 */ 1419 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1420 /** 1421 * Indicates the view is enabled, focused and its window has the focus. 1422 * 1423 * @see #ENABLED_STATE_SET 1424 * @see #FOCUSED_STATE_SET 1425 * @see #WINDOW_FOCUSED_STATE_SET 1426 */ 1427 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1428 /** 1429 * Indicates the view is enabled, selected and its window has the focus. 1430 * 1431 * @see #ENABLED_STATE_SET 1432 * @see #SELECTED_STATE_SET 1433 * @see #WINDOW_FOCUSED_STATE_SET 1434 */ 1435 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1436 /** 1437 * Indicates the view is focused, selected and its window has the focus. 1438 * 1439 * @see #FOCUSED_STATE_SET 1440 * @see #SELECTED_STATE_SET 1441 * @see #WINDOW_FOCUSED_STATE_SET 1442 */ 1443 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1444 /** 1445 * Indicates the view is enabled, focused, selected and its window 1446 * has the focus. 1447 * 1448 * @see #ENABLED_STATE_SET 1449 * @see #FOCUSED_STATE_SET 1450 * @see #SELECTED_STATE_SET 1451 * @see #WINDOW_FOCUSED_STATE_SET 1452 */ 1453 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1454 /** 1455 * Indicates the view is pressed and its window has the focus. 1456 * 1457 * @see #PRESSED_STATE_SET 1458 * @see #WINDOW_FOCUSED_STATE_SET 1459 */ 1460 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1461 /** 1462 * Indicates the view is pressed and selected. 1463 * 1464 * @see #PRESSED_STATE_SET 1465 * @see #SELECTED_STATE_SET 1466 */ 1467 protected static final int[] PRESSED_SELECTED_STATE_SET; 1468 /** 1469 * Indicates the view is pressed, selected and its window has the focus. 1470 * 1471 * @see #PRESSED_STATE_SET 1472 * @see #SELECTED_STATE_SET 1473 * @see #WINDOW_FOCUSED_STATE_SET 1474 */ 1475 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1476 /** 1477 * Indicates the view is pressed and focused. 1478 * 1479 * @see #PRESSED_STATE_SET 1480 * @see #FOCUSED_STATE_SET 1481 */ 1482 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1483 /** 1484 * Indicates the view is pressed, focused and its window has the focus. 1485 * 1486 * @see #PRESSED_STATE_SET 1487 * @see #FOCUSED_STATE_SET 1488 * @see #WINDOW_FOCUSED_STATE_SET 1489 */ 1490 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1491 /** 1492 * Indicates the view is pressed, focused and selected. 1493 * 1494 * @see #PRESSED_STATE_SET 1495 * @see #SELECTED_STATE_SET 1496 * @see #FOCUSED_STATE_SET 1497 */ 1498 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1499 /** 1500 * Indicates the view is pressed, focused, selected and its window has the focus. 1501 * 1502 * @see #PRESSED_STATE_SET 1503 * @see #FOCUSED_STATE_SET 1504 * @see #SELECTED_STATE_SET 1505 * @see #WINDOW_FOCUSED_STATE_SET 1506 */ 1507 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1508 /** 1509 * Indicates the view is pressed and enabled. 1510 * 1511 * @see #PRESSED_STATE_SET 1512 * @see #ENABLED_STATE_SET 1513 */ 1514 protected static final int[] PRESSED_ENABLED_STATE_SET; 1515 /** 1516 * Indicates the view is pressed, enabled and its window has the focus. 1517 * 1518 * @see #PRESSED_STATE_SET 1519 * @see #ENABLED_STATE_SET 1520 * @see #WINDOW_FOCUSED_STATE_SET 1521 */ 1522 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1523 /** 1524 * Indicates the view is pressed, enabled and selected. 1525 * 1526 * @see #PRESSED_STATE_SET 1527 * @see #ENABLED_STATE_SET 1528 * @see #SELECTED_STATE_SET 1529 */ 1530 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1531 /** 1532 * Indicates the view is pressed, enabled, selected and its window has the 1533 * focus. 1534 * 1535 * @see #PRESSED_STATE_SET 1536 * @see #ENABLED_STATE_SET 1537 * @see #SELECTED_STATE_SET 1538 * @see #WINDOW_FOCUSED_STATE_SET 1539 */ 1540 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1541 /** 1542 * Indicates the view is pressed, enabled and focused. 1543 * 1544 * @see #PRESSED_STATE_SET 1545 * @see #ENABLED_STATE_SET 1546 * @see #FOCUSED_STATE_SET 1547 */ 1548 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1549 /** 1550 * Indicates the view is pressed, enabled, focused and its window has the 1551 * focus. 1552 * 1553 * @see #PRESSED_STATE_SET 1554 * @see #ENABLED_STATE_SET 1555 * @see #FOCUSED_STATE_SET 1556 * @see #WINDOW_FOCUSED_STATE_SET 1557 */ 1558 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1559 /** 1560 * Indicates the view is pressed, enabled, focused and selected. 1561 * 1562 * @see #PRESSED_STATE_SET 1563 * @see #ENABLED_STATE_SET 1564 * @see #SELECTED_STATE_SET 1565 * @see #FOCUSED_STATE_SET 1566 */ 1567 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1568 /** 1569 * Indicates the view is pressed, enabled, focused, selected and its window 1570 * has the focus. 1571 * 1572 * @see #PRESSED_STATE_SET 1573 * @see #ENABLED_STATE_SET 1574 * @see #SELECTED_STATE_SET 1575 * @see #FOCUSED_STATE_SET 1576 * @see #WINDOW_FOCUSED_STATE_SET 1577 */ 1578 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1579 1580 static { 1581 EMPTY_STATE_SET = StateSet.get(0); 1582 1583 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1584 1585 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1586 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1587 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1588 1589 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1590 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1591 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1592 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1593 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1594 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1595 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1596 | StateSet.VIEW_STATE_FOCUSED); 1597 1598 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1599 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1600 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1601 ENABLED_SELECTED_STATE_SET = StateSet.get( 1602 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1603 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1604 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1605 | StateSet.VIEW_STATE_ENABLED); 1606 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1607 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1608 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1609 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1610 | StateSet.VIEW_STATE_ENABLED); 1611 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1612 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1613 | StateSet.VIEW_STATE_ENABLED); 1614 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1615 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1616 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1617 1618 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1619 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1620 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1621 PRESSED_SELECTED_STATE_SET = StateSet.get( 1622 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1623 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1624 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1625 | StateSet.VIEW_STATE_PRESSED); 1626 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1627 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1628 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1629 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1630 | StateSet.VIEW_STATE_PRESSED); 1631 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1632 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1633 | StateSet.VIEW_STATE_PRESSED); 1634 PRESSED_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_PRESSED); 1637 PRESSED_ENABLED_STATE_SET = StateSet.get( 1638 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1639 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1640 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1641 | StateSet.VIEW_STATE_PRESSED); 1642 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1643 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1644 | StateSet.VIEW_STATE_PRESSED); 1645 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1646 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1647 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1648 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 1649 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 1650 | StateSet.VIEW_STATE_PRESSED); 1651 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1652 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1653 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1654 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1655 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1656 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1657 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1658 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1659 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 1660 | StateSet.VIEW_STATE_PRESSED); 1661 } 1662 1663 /** 1664 * Accessibility event types that are dispatched for text population. 1665 */ 1666 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 1667 AccessibilityEvent.TYPE_VIEW_CLICKED 1668 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 1669 | AccessibilityEvent.TYPE_VIEW_SELECTED 1670 | AccessibilityEvent.TYPE_VIEW_FOCUSED 1671 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 1672 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 1673 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 1674 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 1675 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 1676 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 1677 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 1678 1679 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 1680 1681 static final int DEBUG_CORNERS_SIZE_DIP = 8; 1682 1683 /** 1684 * Temporary Rect currently for use in setBackground(). This will probably 1685 * be extended in the future to hold our own class with more than just 1686 * a Rect. :) 1687 */ 1688 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 1689 1690 /** 1691 * Map used to store views' tags. 1692 */ 1693 private SparseArray<Object> mKeyedTags; 1694 1695 /** 1696 * The next available accessibility id. 1697 */ 1698 private static int sNextAccessibilityViewId; 1699 1700 /** 1701 * The animation currently associated with this view. 1702 * @hide 1703 */ 1704 protected Animation mCurrentAnimation = null; 1705 1706 /** 1707 * Width as measured during measure pass. 1708 * {@hide} 1709 */ 1710 @ViewDebug.ExportedProperty(category = "measurement") 1711 int mMeasuredWidth; 1712 1713 /** 1714 * Height as measured during measure pass. 1715 * {@hide} 1716 */ 1717 @ViewDebug.ExportedProperty(category = "measurement") 1718 int mMeasuredHeight; 1719 1720 /** 1721 * Flag to indicate that this view was marked INVALIDATED, or had its display list 1722 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 1723 * its display list. This flag, used only when hw accelerated, allows us to clear the 1724 * flag while retaining this information until it's needed (at getDisplayList() time and 1725 * in drawChild(), when we decide to draw a view's children's display lists into our own). 1726 * 1727 * {@hide} 1728 */ 1729 boolean mRecreateDisplayList = false; 1730 1731 /** 1732 * The view's identifier. 1733 * {@hide} 1734 * 1735 * @see #setId(int) 1736 * @see #getId() 1737 */ 1738 @IdRes 1739 @ViewDebug.ExportedProperty(resolveId = true) 1740 int mID = NO_ID; 1741 1742 /** 1743 * The stable ID of this view for accessibility purposes. 1744 */ 1745 int mAccessibilityViewId = NO_ID; 1746 1747 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 1748 1749 SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent; 1750 1751 /** 1752 * The view's tag. 1753 * {@hide} 1754 * 1755 * @see #setTag(Object) 1756 * @see #getTag() 1757 */ 1758 protected Object mTag = null; 1759 1760 // for mPrivateFlags: 1761 /** {@hide} */ 1762 static final int PFLAG_WANTS_FOCUS = 0x00000001; 1763 /** {@hide} */ 1764 static final int PFLAG_FOCUSED = 0x00000002; 1765 /** {@hide} */ 1766 static final int PFLAG_SELECTED = 0x00000004; 1767 /** {@hide} */ 1768 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 1769 /** {@hide} */ 1770 static final int PFLAG_HAS_BOUNDS = 0x00000010; 1771 /** {@hide} */ 1772 static final int PFLAG_DRAWN = 0x00000020; 1773 /** 1774 * When this flag is set, this view is running an animation on behalf of its 1775 * children and should therefore not cancel invalidate requests, even if they 1776 * lie outside of this view's bounds. 1777 * 1778 * {@hide} 1779 */ 1780 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 1781 /** {@hide} */ 1782 static final int PFLAG_SKIP_DRAW = 0x00000080; 1783 /** {@hide} */ 1784 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 1785 /** {@hide} */ 1786 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 1787 /** {@hide} */ 1788 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 1789 /** {@hide} */ 1790 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 1791 /** {@hide} */ 1792 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 1793 1794 private static final int PFLAG_PRESSED = 0x00004000; 1795 1796 /** {@hide} */ 1797 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 1798 /** 1799 * Flag used to indicate that this view should be drawn once more (and only once 1800 * more) after its animation has completed. 1801 * {@hide} 1802 */ 1803 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 1804 1805 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 1806 1807 /** 1808 * Indicates that the View returned true when onSetAlpha() was called and that 1809 * the alpha must be restored. 1810 * {@hide} 1811 */ 1812 static final int PFLAG_ALPHA_SET = 0x00040000; 1813 1814 /** 1815 * Set by {@link #setScrollContainer(boolean)}. 1816 */ 1817 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 1818 1819 /** 1820 * Set by {@link #setScrollContainer(boolean)}. 1821 */ 1822 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 1823 1824 /** 1825 * View flag indicating whether this view was invalidated (fully or partially.) 1826 * 1827 * @hide 1828 */ 1829 static final int PFLAG_DIRTY = 0x00200000; 1830 1831 /** 1832 * View flag indicating whether this view was invalidated by an opaque 1833 * invalidate request. 1834 * 1835 * @hide 1836 */ 1837 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 1838 1839 /** 1840 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 1841 * 1842 * @hide 1843 */ 1844 static final int PFLAG_DIRTY_MASK = 0x00600000; 1845 1846 /** 1847 * Indicates whether the background is opaque. 1848 * 1849 * @hide 1850 */ 1851 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 1852 1853 /** 1854 * Indicates whether the scrollbars are opaque. 1855 * 1856 * @hide 1857 */ 1858 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 1859 1860 /** 1861 * Indicates whether the view is opaque. 1862 * 1863 * @hide 1864 */ 1865 static final int PFLAG_OPAQUE_MASK = 0x01800000; 1866 1867 /** 1868 * Indicates a prepressed state; 1869 * the short time between ACTION_DOWN and recognizing 1870 * a 'real' press. Prepressed is used to recognize quick taps 1871 * even when they are shorter than ViewConfiguration.getTapTimeout(). 1872 * 1873 * @hide 1874 */ 1875 private static final int PFLAG_PREPRESSED = 0x02000000; 1876 1877 /** 1878 * Indicates whether the view is temporarily detached. 1879 * 1880 * @hide 1881 */ 1882 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 1883 1884 /** 1885 * Indicates that we should awaken scroll bars once attached 1886 * 1887 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 1888 * during window attachment and it is no longer needed. Feel free to repurpose it. 1889 * 1890 * @hide 1891 */ 1892 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 1893 1894 /** 1895 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 1896 * @hide 1897 */ 1898 private static final int PFLAG_HOVERED = 0x10000000; 1899 1900 /** 1901 * no longer needed, should be reused 1902 */ 1903 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 1904 1905 /** {@hide} */ 1906 static final int PFLAG_ACTIVATED = 0x40000000; 1907 1908 /** 1909 * Indicates that this view was specifically invalidated, not just dirtied because some 1910 * child view was invalidated. The flag is used to determine when we need to recreate 1911 * a view's display list (as opposed to just returning a reference to its existing 1912 * display list). 1913 * 1914 * @hide 1915 */ 1916 static final int PFLAG_INVALIDATED = 0x80000000; 1917 1918 /** 1919 * Masks for mPrivateFlags2, as generated by dumpFlags(): 1920 * 1921 * |-------|-------|-------|-------| 1922 * 1 PFLAG2_DRAG_CAN_ACCEPT 1923 * 1 PFLAG2_DRAG_HOVERED 1924 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 1925 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 1926 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 1927 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 1928 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 1929 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 1930 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 1931 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 1932 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 1933 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 1934 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 1935 * 111 PFLAG2_TEXT_DIRECTION_MASK 1936 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 1937 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 1938 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 1939 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 1940 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 1941 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 1942 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 1943 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 1944 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 1945 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 1946 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 1947 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 1948 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 1949 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 1950 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 1951 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 1952 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 1953 * 1 PFLAG2_VIEW_QUICK_REJECTED 1954 * 1 PFLAG2_PADDING_RESOLVED 1955 * 1 PFLAG2_DRAWABLE_RESOLVED 1956 * 1 PFLAG2_HAS_TRANSIENT_STATE 1957 * |-------|-------|-------|-------| 1958 */ 1959 1960 /** 1961 * Indicates that this view has reported that it can accept the current drag's content. 1962 * Cleared when the drag operation concludes. 1963 * @hide 1964 */ 1965 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 1966 1967 /** 1968 * Indicates that this view is currently directly under the drag location in a 1969 * drag-and-drop operation involving content that it can accept. Cleared when 1970 * the drag exits the view, or when the drag operation concludes. 1971 * @hide 1972 */ 1973 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 1974 1975 /** @hide */ 1976 @IntDef({ 1977 LAYOUT_DIRECTION_LTR, 1978 LAYOUT_DIRECTION_RTL, 1979 LAYOUT_DIRECTION_INHERIT, 1980 LAYOUT_DIRECTION_LOCALE 1981 }) 1982 @Retention(RetentionPolicy.SOURCE) 1983 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 1984 public @interface LayoutDir {} 1985 1986 /** @hide */ 1987 @IntDef({ 1988 LAYOUT_DIRECTION_LTR, 1989 LAYOUT_DIRECTION_RTL 1990 }) 1991 @Retention(RetentionPolicy.SOURCE) 1992 public @interface ResolvedLayoutDir {} 1993 1994 /** 1995 * A flag to indicate that the layout direction of this view has not been defined yet. 1996 * @hide 1997 */ 1998 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 1999 2000 /** 2001 * Horizontal layout direction of this view is from Left to Right. 2002 * Use with {@link #setLayoutDirection}. 2003 */ 2004 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2005 2006 /** 2007 * Horizontal layout direction of this view is from Right to Left. 2008 * Use with {@link #setLayoutDirection}. 2009 */ 2010 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2011 2012 /** 2013 * Horizontal layout direction of this view is inherited from its parent. 2014 * Use with {@link #setLayoutDirection}. 2015 */ 2016 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2017 2018 /** 2019 * Horizontal layout direction of this view is from deduced from the default language 2020 * script for the locale. Use with {@link #setLayoutDirection}. 2021 */ 2022 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2023 2024 /** 2025 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2026 * @hide 2027 */ 2028 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2029 2030 /** 2031 * Mask for use with private flags indicating bits used for horizontal layout direction. 2032 * @hide 2033 */ 2034 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2035 2036 /** 2037 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2038 * right-to-left direction. 2039 * @hide 2040 */ 2041 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2042 2043 /** 2044 * Indicates whether the view horizontal layout direction has been resolved. 2045 * @hide 2046 */ 2047 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2048 2049 /** 2050 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2051 * @hide 2052 */ 2053 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2054 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2055 2056 /* 2057 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2058 * flag value. 2059 * @hide 2060 */ 2061 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2062 LAYOUT_DIRECTION_LTR, 2063 LAYOUT_DIRECTION_RTL, 2064 LAYOUT_DIRECTION_INHERIT, 2065 LAYOUT_DIRECTION_LOCALE 2066 }; 2067 2068 /** 2069 * Default horizontal layout direction. 2070 */ 2071 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2072 2073 /** 2074 * Default horizontal layout direction. 2075 * @hide 2076 */ 2077 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2078 2079 /** 2080 * Text direction is inherited through {@link ViewGroup} 2081 */ 2082 public static final int TEXT_DIRECTION_INHERIT = 0; 2083 2084 /** 2085 * Text direction is using "first strong algorithm". The first strong directional character 2086 * determines the paragraph direction. If there is no strong directional character, the 2087 * paragraph direction is the view's resolved layout direction. 2088 */ 2089 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2090 2091 /** 2092 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2093 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2094 * If there are neither, the paragraph direction is the view's resolved layout direction. 2095 */ 2096 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2097 2098 /** 2099 * Text direction is forced to LTR. 2100 */ 2101 public static final int TEXT_DIRECTION_LTR = 3; 2102 2103 /** 2104 * Text direction is forced to RTL. 2105 */ 2106 public static final int TEXT_DIRECTION_RTL = 4; 2107 2108 /** 2109 * Text direction is coming from the system Locale. 2110 */ 2111 public static final int TEXT_DIRECTION_LOCALE = 5; 2112 2113 /** 2114 * Text direction is using "first strong algorithm". The first strong directional character 2115 * determines the paragraph direction. If there is no strong directional character, the 2116 * paragraph direction is LTR. 2117 */ 2118 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2119 2120 /** 2121 * Text direction is using "first strong algorithm". The first strong directional character 2122 * determines the paragraph direction. If there is no strong directional character, the 2123 * paragraph direction is RTL. 2124 */ 2125 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2126 2127 /** 2128 * Default text direction is inherited 2129 */ 2130 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2131 2132 /** 2133 * Default resolved text direction 2134 * @hide 2135 */ 2136 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2137 2138 /** 2139 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2140 * @hide 2141 */ 2142 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2143 2144 /** 2145 * Mask for use with private flags indicating bits used for text direction. 2146 * @hide 2147 */ 2148 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2149 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2150 2151 /** 2152 * Array of text direction flags for mapping attribute "textDirection" to correct 2153 * flag value. 2154 * @hide 2155 */ 2156 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2157 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2158 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2159 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2160 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2161 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2162 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2163 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2164 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2165 }; 2166 2167 /** 2168 * Indicates whether the view text direction has been resolved. 2169 * @hide 2170 */ 2171 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2172 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2173 2174 /** 2175 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2176 * @hide 2177 */ 2178 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2179 2180 /** 2181 * Mask for use with private flags indicating bits used for resolved text direction. 2182 * @hide 2183 */ 2184 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2185 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2186 2187 /** 2188 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2189 * @hide 2190 */ 2191 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2192 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2193 2194 /** @hide */ 2195 @IntDef({ 2196 TEXT_ALIGNMENT_INHERIT, 2197 TEXT_ALIGNMENT_GRAVITY, 2198 TEXT_ALIGNMENT_CENTER, 2199 TEXT_ALIGNMENT_TEXT_START, 2200 TEXT_ALIGNMENT_TEXT_END, 2201 TEXT_ALIGNMENT_VIEW_START, 2202 TEXT_ALIGNMENT_VIEW_END 2203 }) 2204 @Retention(RetentionPolicy.SOURCE) 2205 public @interface TextAlignment {} 2206 2207 /** 2208 * Default text alignment. The text alignment of this View is inherited from its parent. 2209 * Use with {@link #setTextAlignment(int)} 2210 */ 2211 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2212 2213 /** 2214 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2215 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2216 * 2217 * Use with {@link #setTextAlignment(int)} 2218 */ 2219 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2220 2221 /** 2222 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2223 * 2224 * Use with {@link #setTextAlignment(int)} 2225 */ 2226 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2227 2228 /** 2229 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2230 * 2231 * Use with {@link #setTextAlignment(int)} 2232 */ 2233 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2234 2235 /** 2236 * Center the paragraph, e.g. ALIGN_CENTER. 2237 * 2238 * Use with {@link #setTextAlignment(int)} 2239 */ 2240 public static final int TEXT_ALIGNMENT_CENTER = 4; 2241 2242 /** 2243 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2244 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2245 * 2246 * Use with {@link #setTextAlignment(int)} 2247 */ 2248 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2249 2250 /** 2251 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2252 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2253 * 2254 * Use with {@link #setTextAlignment(int)} 2255 */ 2256 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2257 2258 /** 2259 * Default text alignment is inherited 2260 */ 2261 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2262 2263 /** 2264 * Default resolved text alignment 2265 * @hide 2266 */ 2267 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2268 2269 /** 2270 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2271 * @hide 2272 */ 2273 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2274 2275 /** 2276 * Mask for use with private flags indicating bits used for text alignment. 2277 * @hide 2278 */ 2279 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2280 2281 /** 2282 * Array of text direction flags for mapping attribute "textAlignment" to correct 2283 * flag value. 2284 * @hide 2285 */ 2286 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2287 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2288 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2289 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2290 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2291 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2292 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2293 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2294 }; 2295 2296 /** 2297 * Indicates whether the view text alignment has been resolved. 2298 * @hide 2299 */ 2300 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2301 2302 /** 2303 * Bit shift to get the resolved text alignment. 2304 * @hide 2305 */ 2306 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2307 2308 /** 2309 * Mask for use with private flags indicating bits used for text alignment. 2310 * @hide 2311 */ 2312 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2313 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2314 2315 /** 2316 * Indicates whether if the view text alignment has been resolved to gravity 2317 */ 2318 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2319 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2320 2321 // Accessiblity constants for mPrivateFlags2 2322 2323 /** 2324 * Shift for the bits in {@link #mPrivateFlags2} related to the 2325 * "importantForAccessibility" attribute. 2326 */ 2327 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2328 2329 /** 2330 * Automatically determine whether a view is important for accessibility. 2331 */ 2332 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2333 2334 /** 2335 * The view is important for accessibility. 2336 */ 2337 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2338 2339 /** 2340 * The view is not important for accessibility. 2341 */ 2342 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2343 2344 /** 2345 * The view is not important for accessibility, nor are any of its 2346 * descendant views. 2347 */ 2348 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2349 2350 /** 2351 * The default whether the view is important for accessibility. 2352 */ 2353 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2354 2355 /** 2356 * Mask for obtaining the bits which specify how to determine 2357 * whether a view is important for accessibility. 2358 */ 2359 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2360 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2361 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2362 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2363 2364 /** 2365 * Shift for the bits in {@link #mPrivateFlags2} related to the 2366 * "accessibilityLiveRegion" attribute. 2367 */ 2368 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2369 2370 /** 2371 * Live region mode specifying that accessibility services should not 2372 * automatically announce changes to this view. This is the default live 2373 * region mode for most views. 2374 * <p> 2375 * Use with {@link #setAccessibilityLiveRegion(int)}. 2376 */ 2377 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2378 2379 /** 2380 * Live region mode specifying that accessibility services should announce 2381 * changes to this view. 2382 * <p> 2383 * Use with {@link #setAccessibilityLiveRegion(int)}. 2384 */ 2385 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2386 2387 /** 2388 * Live region mode specifying that accessibility services should interrupt 2389 * ongoing speech to immediately announce changes to this view. 2390 * <p> 2391 * Use with {@link #setAccessibilityLiveRegion(int)}. 2392 */ 2393 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2394 2395 /** 2396 * The default whether the view is important for accessibility. 2397 */ 2398 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2399 2400 /** 2401 * Mask for obtaining the bits which specify a view's accessibility live 2402 * region mode. 2403 */ 2404 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2405 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2406 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2407 2408 /** 2409 * Flag indicating whether a view has accessibility focus. 2410 */ 2411 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2412 2413 /** 2414 * Flag whether the accessibility state of the subtree rooted at this view changed. 2415 */ 2416 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2417 2418 /** 2419 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2420 * is used to check whether later changes to the view's transform should invalidate the 2421 * view to force the quickReject test to run again. 2422 */ 2423 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2424 2425 /** 2426 * Flag indicating that start/end padding has been resolved into left/right padding 2427 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2428 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2429 * during measurement. In some special cases this is required such as when an adapter-based 2430 * view measures prospective children without attaching them to a window. 2431 */ 2432 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2433 2434 /** 2435 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2436 */ 2437 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2438 2439 /** 2440 * Indicates that the view is tracking some sort of transient state 2441 * that the app should not need to be aware of, but that the framework 2442 * should take special care to preserve. 2443 */ 2444 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2445 2446 /** 2447 * Group of bits indicating that RTL properties resolution is done. 2448 */ 2449 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2450 PFLAG2_TEXT_DIRECTION_RESOLVED | 2451 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2452 PFLAG2_PADDING_RESOLVED | 2453 PFLAG2_DRAWABLE_RESOLVED; 2454 2455 // There are a couple of flags left in mPrivateFlags2 2456 2457 /* End of masks for mPrivateFlags2 */ 2458 2459 /** 2460 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2461 * 2462 * |-------|-------|-------|-------| 2463 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2464 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2465 * 1 PFLAG3_IS_LAID_OUT 2466 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2467 * 1 PFLAG3_CALLED_SUPER 2468 * 1 PFLAG3_APPLYING_INSETS 2469 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2470 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2471 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2472 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2473 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2474 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2475 * 1 PFLAG3_SCROLL_INDICATOR_START 2476 * 1 PFLAG3_SCROLL_INDICATOR_END 2477 * 1 PFLAG3_ASSIST_BLOCKED 2478 * 1 PFLAG3_CLUSTER 2479 * 1 PFLAG3_SECTION 2480 * xxxxxx * NO LONGER NEEDED, SHOULD BE REUSED * 2481 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2482 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2483 * 1 PFLAG3_TEMPORARY_DETACH 2484 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2485 * |-------|-------|-------|-------| 2486 */ 2487 2488 /** 2489 * Flag indicating that view has a transform animation set on it. This is used to track whether 2490 * an animation is cleared between successive frames, in order to tell the associated 2491 * DisplayList to clear its animation matrix. 2492 */ 2493 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2494 2495 /** 2496 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2497 * animation is cleared between successive frames, in order to tell the associated 2498 * DisplayList to restore its alpha value. 2499 */ 2500 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2501 2502 /** 2503 * Flag indicating that the view has been through at least one layout since it 2504 * was last attached to a window. 2505 */ 2506 static final int PFLAG3_IS_LAID_OUT = 0x4; 2507 2508 /** 2509 * Flag indicating that a call to measure() was skipped and should be done 2510 * instead when layout() is invoked. 2511 */ 2512 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2513 2514 /** 2515 * Flag indicating that an overridden method correctly called down to 2516 * the superclass implementation as required by the API spec. 2517 */ 2518 static final int PFLAG3_CALLED_SUPER = 0x10; 2519 2520 /** 2521 * Flag indicating that we're in the process of applying window insets. 2522 */ 2523 static final int PFLAG3_APPLYING_INSETS = 0x20; 2524 2525 /** 2526 * Flag indicating that we're in the process of fitting system windows using the old method. 2527 */ 2528 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2529 2530 /** 2531 * Flag indicating that nested scrolling is enabled for this view. 2532 * The view will optionally cooperate with views up its parent chain to allow for 2533 * integrated nested scrolling along the same axis. 2534 */ 2535 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2536 2537 /** 2538 * Flag indicating that the bottom scroll indicator should be displayed 2539 * when this view can scroll up. 2540 */ 2541 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2542 2543 /** 2544 * Flag indicating that the bottom scroll indicator should be displayed 2545 * when this view can scroll down. 2546 */ 2547 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2548 2549 /** 2550 * Flag indicating that the left scroll indicator should be displayed 2551 * when this view can scroll left. 2552 */ 2553 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2554 2555 /** 2556 * Flag indicating that the right scroll indicator should be displayed 2557 * when this view can scroll right. 2558 */ 2559 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2560 2561 /** 2562 * Flag indicating that the start scroll indicator should be displayed 2563 * when this view can scroll in the start direction. 2564 */ 2565 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2566 2567 /** 2568 * Flag indicating that the end scroll indicator should be displayed 2569 * when this view can scroll in the end direction. 2570 */ 2571 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2572 2573 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2574 2575 static final int SCROLL_INDICATORS_NONE = 0x0000; 2576 2577 /** 2578 * Mask for use with setFlags indicating bits used for indicating which 2579 * scroll indicators are enabled. 2580 */ 2581 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2582 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2583 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2584 | PFLAG3_SCROLL_INDICATOR_END; 2585 2586 /** 2587 * Left-shift required to translate between public scroll indicator flags 2588 * and internal PFLAGS3 flags. When used as a right-shift, translates 2589 * PFLAGS3 flags to public flags. 2590 */ 2591 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2592 2593 /** @hide */ 2594 @Retention(RetentionPolicy.SOURCE) 2595 @IntDef(flag = true, 2596 value = { 2597 SCROLL_INDICATOR_TOP, 2598 SCROLL_INDICATOR_BOTTOM, 2599 SCROLL_INDICATOR_LEFT, 2600 SCROLL_INDICATOR_RIGHT, 2601 SCROLL_INDICATOR_START, 2602 SCROLL_INDICATOR_END, 2603 }) 2604 public @interface ScrollIndicators {} 2605 2606 /** 2607 * Scroll indicator direction for the top edge of the view. 2608 * 2609 * @see #setScrollIndicators(int) 2610 * @see #setScrollIndicators(int, int) 2611 * @see #getScrollIndicators() 2612 */ 2613 public static final int SCROLL_INDICATOR_TOP = 2614 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2615 2616 /** 2617 * Scroll indicator direction for the bottom edge of the view. 2618 * 2619 * @see #setScrollIndicators(int) 2620 * @see #setScrollIndicators(int, int) 2621 * @see #getScrollIndicators() 2622 */ 2623 public static final int SCROLL_INDICATOR_BOTTOM = 2624 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2625 2626 /** 2627 * Scroll indicator direction for the left edge of the view. 2628 * 2629 * @see #setScrollIndicators(int) 2630 * @see #setScrollIndicators(int, int) 2631 * @see #getScrollIndicators() 2632 */ 2633 public static final int SCROLL_INDICATOR_LEFT = 2634 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2635 2636 /** 2637 * Scroll indicator direction for the right edge of the view. 2638 * 2639 * @see #setScrollIndicators(int) 2640 * @see #setScrollIndicators(int, int) 2641 * @see #getScrollIndicators() 2642 */ 2643 public static final int SCROLL_INDICATOR_RIGHT = 2644 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2645 2646 /** 2647 * Scroll indicator direction for the starting edge of the view. 2648 * <p> 2649 * Resolved according to the view's layout direction, see 2650 * {@link #getLayoutDirection()} for more information. 2651 * 2652 * @see #setScrollIndicators(int) 2653 * @see #setScrollIndicators(int, int) 2654 * @see #getScrollIndicators() 2655 */ 2656 public static final int SCROLL_INDICATOR_START = 2657 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2658 2659 /** 2660 * Scroll indicator direction for the ending edge of the view. 2661 * <p> 2662 * Resolved according to the view's layout direction, see 2663 * {@link #getLayoutDirection()} for more information. 2664 * 2665 * @see #setScrollIndicators(int) 2666 * @see #setScrollIndicators(int, int) 2667 * @see #getScrollIndicators() 2668 */ 2669 public static final int SCROLL_INDICATOR_END = 2670 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2671 2672 /** 2673 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 2674 * into this view.<p> 2675 */ 2676 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 2677 2678 /** 2679 * Flag indicating that the view is a root of a keyboard navigation cluster. 2680 * 2681 * @see #isKeyboardNavigationCluster() 2682 * @see #setKeyboardNavigationCluster(boolean) 2683 */ 2684 private static final int PFLAG3_CLUSTER = 0x8000; 2685 2686 /** 2687 * Flag indicating that the view is a root of a keyboard navigation section. 2688 * 2689 * @see #isKeyboardNavigationSection() 2690 * @see #setKeyboardNavigationSection(boolean) 2691 */ 2692 private static final int PFLAG3_SECTION = 0x10000; 2693 2694 /** 2695 * Whether this view has rendered elements that overlap (see {@link 2696 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 2697 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 2698 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 2699 * determined by whatever {@link #hasOverlappingRendering()} returns. 2700 */ 2701 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 2702 2703 /** 2704 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 2705 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 2706 */ 2707 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 2708 2709 /** 2710 * Flag indicating that the view is temporarily detached from the parent view. 2711 * 2712 * @see #onStartTemporaryDetach() 2713 * @see #onFinishTemporaryDetach() 2714 */ 2715 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 2716 2717 /** 2718 * Flag indicating that the view does not wish to be revealed within its parent 2719 * hierarchy when it gains focus. Expressed in the negative since the historical 2720 * default behavior is to reveal on focus; this flag suppresses that behavior. 2721 * 2722 * @see #setRevealOnFocusHint(boolean) 2723 * @see #getRevealOnFocusHint() 2724 */ 2725 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 2726 2727 /* End of masks for mPrivateFlags3 */ 2728 2729 /** 2730 * Always allow a user to over-scroll this view, provided it is a 2731 * view that can scroll. 2732 * 2733 * @see #getOverScrollMode() 2734 * @see #setOverScrollMode(int) 2735 */ 2736 public static final int OVER_SCROLL_ALWAYS = 0; 2737 2738 /** 2739 * Allow a user to over-scroll this view only if the content is large 2740 * enough to meaningfully scroll, provided it is a view that can scroll. 2741 * 2742 * @see #getOverScrollMode() 2743 * @see #setOverScrollMode(int) 2744 */ 2745 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 2746 2747 /** 2748 * Never allow a user to over-scroll this view. 2749 * 2750 * @see #getOverScrollMode() 2751 * @see #setOverScrollMode(int) 2752 */ 2753 public static final int OVER_SCROLL_NEVER = 2; 2754 2755 /** 2756 * Special constant for {@link #setSystemUiVisibility(int)}: View has 2757 * requested the system UI (status bar) to be visible (the default). 2758 * 2759 * @see #setSystemUiVisibility(int) 2760 */ 2761 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 2762 2763 /** 2764 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 2765 * system UI to enter an unobtrusive "low profile" mode. 2766 * 2767 * <p>This is for use in games, book readers, video players, or any other 2768 * "immersive" application where the usual system chrome is deemed too distracting. 2769 * 2770 * <p>In low profile mode, the status bar and/or navigation icons may dim. 2771 * 2772 * @see #setSystemUiVisibility(int) 2773 */ 2774 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 2775 2776 /** 2777 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 2778 * system navigation be temporarily hidden. 2779 * 2780 * <p>This is an even less obtrusive state than that called for by 2781 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 2782 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 2783 * those to disappear. This is useful (in conjunction with the 2784 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 2785 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 2786 * window flags) for displaying content using every last pixel on the display. 2787 * 2788 * <p>There is a limitation: because navigation controls are so important, the least user 2789 * interaction will cause them to reappear immediately. When this happens, both 2790 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 2791 * so that both elements reappear at the same time. 2792 * 2793 * @see #setSystemUiVisibility(int) 2794 */ 2795 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 2796 2797 /** 2798 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 2799 * into the normal fullscreen mode so that its content can take over the screen 2800 * while still allowing the user to interact with the application. 2801 * 2802 * <p>This has the same visual effect as 2803 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 2804 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 2805 * meaning that non-critical screen decorations (such as the status bar) will be 2806 * hidden while the user is in the View's window, focusing the experience on 2807 * that content. Unlike the window flag, if you are using ActionBar in 2808 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2809 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 2810 * hide the action bar. 2811 * 2812 * <p>This approach to going fullscreen is best used over the window flag when 2813 * it is a transient state -- that is, the application does this at certain 2814 * points in its user interaction where it wants to allow the user to focus 2815 * on content, but not as a continuous state. For situations where the application 2816 * would like to simply stay full screen the entire time (such as a game that 2817 * wants to take over the screen), the 2818 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 2819 * is usually a better approach. The state set here will be removed by the system 2820 * in various situations (such as the user moving to another application) like 2821 * the other system UI states. 2822 * 2823 * <p>When using this flag, the application should provide some easy facility 2824 * for the user to go out of it. A common example would be in an e-book 2825 * reader, where tapping on the screen brings back whatever screen and UI 2826 * decorations that had been hidden while the user was immersed in reading 2827 * the book. 2828 * 2829 * @see #setSystemUiVisibility(int) 2830 */ 2831 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 2832 2833 /** 2834 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 2835 * flags, we would like a stable view of the content insets given to 2836 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 2837 * will always represent the worst case that the application can expect 2838 * as a continuous state. In the stock Android UI this is the space for 2839 * the system bar, nav bar, and status bar, but not more transient elements 2840 * such as an input method. 2841 * 2842 * The stable layout your UI sees is based on the system UI modes you can 2843 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 2844 * then you will get a stable layout for changes of the 2845 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 2846 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 2847 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 2848 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 2849 * with a stable layout. (Note that you should avoid using 2850 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 2851 * 2852 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 2853 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 2854 * then a hidden status bar will be considered a "stable" state for purposes 2855 * here. This allows your UI to continually hide the status bar, while still 2856 * using the system UI flags to hide the action bar while still retaining 2857 * a stable layout. Note that changing the window fullscreen flag will never 2858 * provide a stable layout for a clean transition. 2859 * 2860 * <p>If you are using ActionBar in 2861 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2862 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 2863 * insets it adds to those given to the application. 2864 */ 2865 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 2866 2867 /** 2868 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2869 * to be laid out as if it has requested 2870 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 2871 * allows it to avoid artifacts when switching in and out of that mode, at 2872 * the expense that some of its user interface may be covered by screen 2873 * decorations when they are shown. You can perform layout of your inner 2874 * UI elements to account for the navigation system UI through the 2875 * {@link #fitSystemWindows(Rect)} method. 2876 */ 2877 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 2878 2879 /** 2880 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2881 * to be laid out as if it has requested 2882 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 2883 * allows it to avoid artifacts when switching in and out of that mode, at 2884 * the expense that some of its user interface may be covered by screen 2885 * decorations when they are shown. You can perform layout of your inner 2886 * UI elements to account for non-fullscreen system UI through the 2887 * {@link #fitSystemWindows(Rect)} method. 2888 */ 2889 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 2890 2891 /** 2892 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2893 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 2894 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 2895 * user interaction. 2896 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 2897 * has an effect when used in combination with that flag.</p> 2898 */ 2899 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 2900 2901 /** 2902 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2903 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 2904 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 2905 * experience while also hiding the system bars. If this flag is not set, 2906 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 2907 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 2908 * if the user swipes from the top of the screen. 2909 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 2910 * system gestures, such as swiping from the top of the screen. These transient system bars 2911 * will overlay app’s content, may have some degree of transparency, and will automatically 2912 * hide after a short timeout. 2913 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 2914 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 2915 * with one or both of those flags.</p> 2916 */ 2917 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 2918 2919 /** 2920 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 2921 * is compatible with light status bar backgrounds. 2922 * 2923 * <p>For this to take effect, the window must request 2924 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2925 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2926 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 2927 * FLAG_TRANSLUCENT_STATUS}. 2928 * 2929 * @see android.R.attr#windowLightStatusBar 2930 */ 2931 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 2932 2933 /** 2934 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 2935 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 2936 */ 2937 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 2938 2939 /** 2940 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 2941 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 2942 */ 2943 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 2944 2945 /** 2946 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 2947 * that is compatible with light navigation bar backgrounds. 2948 * 2949 * <p>For this to take effect, the window must request 2950 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2951 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2952 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 2953 * FLAG_TRANSLUCENT_NAVIGATION}. 2954 */ 2955 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 2956 2957 /** 2958 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 2959 */ 2960 @Deprecated 2961 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 2962 2963 /** 2964 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 2965 */ 2966 @Deprecated 2967 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 2968 2969 /** 2970 * @hide 2971 * 2972 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2973 * out of the public fields to keep the undefined bits out of the developer's way. 2974 * 2975 * Flag to make the status bar not expandable. Unless you also 2976 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 2977 */ 2978 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 2979 2980 /** 2981 * @hide 2982 * 2983 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2984 * out of the public fields to keep the undefined bits out of the developer's way. 2985 * 2986 * Flag to hide notification icons and scrolling ticker text. 2987 */ 2988 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 2989 2990 /** 2991 * @hide 2992 * 2993 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2994 * out of the public fields to keep the undefined bits out of the developer's way. 2995 * 2996 * Flag to disable incoming notification alerts. This will not block 2997 * icons, but it will block sound, vibrating and other visual or aural notifications. 2998 */ 2999 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3000 3001 /** 3002 * @hide 3003 * 3004 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3005 * out of the public fields to keep the undefined bits out of the developer's way. 3006 * 3007 * Flag to hide only the scrolling ticker. Note that 3008 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3009 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3010 */ 3011 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3012 3013 /** 3014 * @hide 3015 * 3016 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3017 * out of the public fields to keep the undefined bits out of the developer's way. 3018 * 3019 * Flag to hide the center system info area. 3020 */ 3021 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3022 3023 /** 3024 * @hide 3025 * 3026 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3027 * out of the public fields to keep the undefined bits out of the developer's way. 3028 * 3029 * Flag to hide only the home button. Don't use this 3030 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3031 */ 3032 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3033 3034 /** 3035 * @hide 3036 * 3037 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3038 * out of the public fields to keep the undefined bits out of the developer's way. 3039 * 3040 * Flag to hide only the back button. Don't use this 3041 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3042 */ 3043 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3044 3045 /** 3046 * @hide 3047 * 3048 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3049 * out of the public fields to keep the undefined bits out of the developer's way. 3050 * 3051 * Flag to hide only the clock. You might use this if your activity has 3052 * its own clock making the status bar's clock redundant. 3053 */ 3054 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3055 3056 /** 3057 * @hide 3058 * 3059 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3060 * out of the public fields to keep the undefined bits out of the developer's way. 3061 * 3062 * Flag to hide only the recent apps button. Don't use this 3063 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3064 */ 3065 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3066 3067 /** 3068 * @hide 3069 * 3070 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3071 * out of the public fields to keep the undefined bits out of the developer's way. 3072 * 3073 * Flag to disable the global search gesture. Don't use this 3074 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3075 */ 3076 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3077 3078 /** 3079 * @hide 3080 * 3081 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3082 * out of the public fields to keep the undefined bits out of the developer's way. 3083 * 3084 * Flag to specify that the status bar is displayed in transient mode. 3085 */ 3086 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3087 3088 /** 3089 * @hide 3090 * 3091 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3092 * out of the public fields to keep the undefined bits out of the developer's way. 3093 * 3094 * Flag to specify that the navigation bar is displayed in transient mode. 3095 */ 3096 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3097 3098 /** 3099 * @hide 3100 * 3101 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3102 * out of the public fields to keep the undefined bits out of the developer's way. 3103 * 3104 * Flag to specify that the hidden status bar would like to be shown. 3105 */ 3106 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3107 3108 /** 3109 * @hide 3110 * 3111 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3112 * out of the public fields to keep the undefined bits out of the developer's way. 3113 * 3114 * Flag to specify that the hidden navigation bar would like to be shown. 3115 */ 3116 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3117 3118 /** 3119 * @hide 3120 * 3121 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3122 * out of the public fields to keep the undefined bits out of the developer's way. 3123 * 3124 * Flag to specify that the status bar is displayed in translucent mode. 3125 */ 3126 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3127 3128 /** 3129 * @hide 3130 * 3131 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3132 * out of the public fields to keep the undefined bits out of the developer's way. 3133 * 3134 * Flag to specify that the navigation bar is displayed in translucent mode. 3135 */ 3136 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3137 3138 /** 3139 * @hide 3140 * 3141 * Makes navigation bar transparent (but not the status bar). 3142 */ 3143 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3144 3145 /** 3146 * @hide 3147 * 3148 * Makes status bar transparent (but not the navigation bar). 3149 */ 3150 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3151 3152 /** 3153 * @hide 3154 * 3155 * Makes both status bar and navigation bar transparent. 3156 */ 3157 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3158 | STATUS_BAR_TRANSPARENT; 3159 3160 /** 3161 * @hide 3162 */ 3163 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3164 3165 /** 3166 * These are the system UI flags that can be cleared by events outside 3167 * of an application. Currently this is just the ability to tap on the 3168 * screen while hiding the navigation bar to have it return. 3169 * @hide 3170 */ 3171 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3172 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3173 | SYSTEM_UI_FLAG_FULLSCREEN; 3174 3175 /** 3176 * Flags that can impact the layout in relation to system UI. 3177 */ 3178 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3179 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3180 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3181 3182 /** @hide */ 3183 @IntDef(flag = true, 3184 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3185 @Retention(RetentionPolicy.SOURCE) 3186 public @interface FindViewFlags {} 3187 3188 /** 3189 * Find views that render the specified text. 3190 * 3191 * @see #findViewsWithText(ArrayList, CharSequence, int) 3192 */ 3193 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3194 3195 /** 3196 * Find find views that contain the specified content description. 3197 * 3198 * @see #findViewsWithText(ArrayList, CharSequence, int) 3199 */ 3200 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3201 3202 /** 3203 * Find views that contain {@link AccessibilityNodeProvider}. Such 3204 * a View is a root of virtual view hierarchy and may contain the searched 3205 * text. If this flag is set Views with providers are automatically 3206 * added and it is a responsibility of the client to call the APIs of 3207 * the provider to determine whether the virtual tree rooted at this View 3208 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3209 * representing the virtual views with this text. 3210 * 3211 * @see #findViewsWithText(ArrayList, CharSequence, int) 3212 * 3213 * @hide 3214 */ 3215 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3216 3217 /** 3218 * The undefined cursor position. 3219 * 3220 * @hide 3221 */ 3222 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3223 3224 /** 3225 * Indicates that the screen has changed state and is now off. 3226 * 3227 * @see #onScreenStateChanged(int) 3228 */ 3229 public static final int SCREEN_STATE_OFF = 0x0; 3230 3231 /** 3232 * Indicates that the screen has changed state and is now on. 3233 * 3234 * @see #onScreenStateChanged(int) 3235 */ 3236 public static final int SCREEN_STATE_ON = 0x1; 3237 3238 /** 3239 * Indicates no axis of view scrolling. 3240 */ 3241 public static final int SCROLL_AXIS_NONE = 0; 3242 3243 /** 3244 * Indicates scrolling along the horizontal axis. 3245 */ 3246 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3247 3248 /** 3249 * Indicates scrolling along the vertical axis. 3250 */ 3251 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3252 3253 /** 3254 * Controls the over-scroll mode for this view. 3255 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3256 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3257 * and {@link #OVER_SCROLL_NEVER}. 3258 */ 3259 private int mOverScrollMode; 3260 3261 /** 3262 * The parent this view is attached to. 3263 * {@hide} 3264 * 3265 * @see #getParent() 3266 */ 3267 protected ViewParent mParent; 3268 3269 /** 3270 * {@hide} 3271 */ 3272 AttachInfo mAttachInfo; 3273 3274 /** 3275 * {@hide} 3276 */ 3277 @ViewDebug.ExportedProperty(flagMapping = { 3278 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3279 name = "FORCE_LAYOUT"), 3280 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3281 name = "LAYOUT_REQUIRED"), 3282 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3283 name = "DRAWING_CACHE_INVALID", outputIf = false), 3284 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3285 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3286 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3287 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3288 }, formatToHexString = true) 3289 int mPrivateFlags; 3290 int mPrivateFlags2; 3291 int mPrivateFlags3; 3292 3293 /** 3294 * This view's request for the visibility of the status bar. 3295 * @hide 3296 */ 3297 @ViewDebug.ExportedProperty(flagMapping = { 3298 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3299 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3300 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3301 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3302 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3303 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3304 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3305 equals = SYSTEM_UI_FLAG_VISIBLE, 3306 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3307 }, formatToHexString = true) 3308 int mSystemUiVisibility; 3309 3310 /** 3311 * Reference count for transient state. 3312 * @see #setHasTransientState(boolean) 3313 */ 3314 int mTransientStateCount = 0; 3315 3316 /** 3317 * Count of how many windows this view has been attached to. 3318 */ 3319 int mWindowAttachCount; 3320 3321 /** 3322 * The layout parameters associated with this view and used by the parent 3323 * {@link android.view.ViewGroup} to determine how this view should be 3324 * laid out. 3325 * {@hide} 3326 */ 3327 protected ViewGroup.LayoutParams mLayoutParams; 3328 3329 /** 3330 * The view flags hold various views states. 3331 * {@hide} 3332 */ 3333 @ViewDebug.ExportedProperty(formatToHexString = true) 3334 int mViewFlags; 3335 3336 static class TransformationInfo { 3337 /** 3338 * The transform matrix for the View. This transform is calculated internally 3339 * based on the translation, rotation, and scale properties. 3340 * 3341 * Do *not* use this variable directly; instead call getMatrix(), which will 3342 * load the value from the View's RenderNode. 3343 */ 3344 private final Matrix mMatrix = new Matrix(); 3345 3346 /** 3347 * The inverse transform matrix for the View. This transform is calculated 3348 * internally based on the translation, rotation, and scale properties. 3349 * 3350 * Do *not* use this variable directly; instead call getInverseMatrix(), 3351 * which will load the value from the View's RenderNode. 3352 */ 3353 private Matrix mInverseMatrix; 3354 3355 /** 3356 * The opacity of the View. This is a value from 0 to 1, where 0 means 3357 * completely transparent and 1 means completely opaque. 3358 */ 3359 @ViewDebug.ExportedProperty 3360 float mAlpha = 1f; 3361 3362 /** 3363 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3364 * property only used by transitions, which is composited with the other alpha 3365 * values to calculate the final visual alpha value. 3366 */ 3367 float mTransitionAlpha = 1f; 3368 } 3369 3370 TransformationInfo mTransformationInfo; 3371 3372 /** 3373 * Current clip bounds. to which all drawing of this view are constrained. 3374 */ 3375 Rect mClipBounds = null; 3376 3377 private boolean mLastIsOpaque; 3378 3379 /** 3380 * The distance in pixels from the left edge of this view's parent 3381 * to the left edge of this view. 3382 * {@hide} 3383 */ 3384 @ViewDebug.ExportedProperty(category = "layout") 3385 protected int mLeft; 3386 /** 3387 * The distance in pixels from the left edge of this view's parent 3388 * to the right edge of this view. 3389 * {@hide} 3390 */ 3391 @ViewDebug.ExportedProperty(category = "layout") 3392 protected int mRight; 3393 /** 3394 * The distance in pixels from the top edge of this view's parent 3395 * to the top edge of this view. 3396 * {@hide} 3397 */ 3398 @ViewDebug.ExportedProperty(category = "layout") 3399 protected int mTop; 3400 /** 3401 * The distance in pixels from the top edge of this view's parent 3402 * to the bottom edge of this view. 3403 * {@hide} 3404 */ 3405 @ViewDebug.ExportedProperty(category = "layout") 3406 protected int mBottom; 3407 3408 /** 3409 * The offset, in pixels, by which the content of this view is scrolled 3410 * horizontally. 3411 * {@hide} 3412 */ 3413 @ViewDebug.ExportedProperty(category = "scrolling") 3414 protected int mScrollX; 3415 /** 3416 * The offset, in pixels, by which the content of this view is scrolled 3417 * vertically. 3418 * {@hide} 3419 */ 3420 @ViewDebug.ExportedProperty(category = "scrolling") 3421 protected int mScrollY; 3422 3423 /** 3424 * The left padding in pixels, that is the distance in pixels between the 3425 * left edge of this view and the left edge of its content. 3426 * {@hide} 3427 */ 3428 @ViewDebug.ExportedProperty(category = "padding") 3429 protected int mPaddingLeft = 0; 3430 /** 3431 * The right padding in pixels, that is the distance in pixels between the 3432 * right edge of this view and the right edge of its content. 3433 * {@hide} 3434 */ 3435 @ViewDebug.ExportedProperty(category = "padding") 3436 protected int mPaddingRight = 0; 3437 /** 3438 * The top padding in pixels, that is the distance in pixels between the 3439 * top edge of this view and the top edge of its content. 3440 * {@hide} 3441 */ 3442 @ViewDebug.ExportedProperty(category = "padding") 3443 protected int mPaddingTop; 3444 /** 3445 * The bottom padding in pixels, that is the distance in pixels between the 3446 * bottom edge of this view and the bottom edge of its content. 3447 * {@hide} 3448 */ 3449 @ViewDebug.ExportedProperty(category = "padding") 3450 protected int mPaddingBottom; 3451 3452 /** 3453 * The layout insets in pixels, that is the distance in pixels between the 3454 * visible edges of this view its bounds. 3455 */ 3456 private Insets mLayoutInsets; 3457 3458 /** 3459 * Briefly describes the view and is primarily used for accessibility support. 3460 */ 3461 private CharSequence mContentDescription; 3462 3463 /** 3464 * Specifies the id of a view for which this view serves as a label for 3465 * accessibility purposes. 3466 */ 3467 private int mLabelForId = View.NO_ID; 3468 3469 /** 3470 * Predicate for matching labeled view id with its label for 3471 * accessibility purposes. 3472 */ 3473 private MatchLabelForPredicate mMatchLabelForPredicate; 3474 3475 /** 3476 * Specifies a view before which this one is visited in accessibility traversal. 3477 */ 3478 private int mAccessibilityTraversalBeforeId = NO_ID; 3479 3480 /** 3481 * Specifies a view after which this one is visited in accessibility traversal. 3482 */ 3483 private int mAccessibilityTraversalAfterId = NO_ID; 3484 3485 /** 3486 * Predicate for matching a view by its id. 3487 */ 3488 private MatchIdPredicate mMatchIdPredicate; 3489 3490 /** 3491 * Cache the paddingRight set by the user to append to the scrollbar's size. 3492 * 3493 * @hide 3494 */ 3495 @ViewDebug.ExportedProperty(category = "padding") 3496 protected int mUserPaddingRight; 3497 3498 /** 3499 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3500 * 3501 * @hide 3502 */ 3503 @ViewDebug.ExportedProperty(category = "padding") 3504 protected int mUserPaddingBottom; 3505 3506 /** 3507 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3508 * 3509 * @hide 3510 */ 3511 @ViewDebug.ExportedProperty(category = "padding") 3512 protected int mUserPaddingLeft; 3513 3514 /** 3515 * Cache the paddingStart set by the user to append to the scrollbar's size. 3516 * 3517 */ 3518 @ViewDebug.ExportedProperty(category = "padding") 3519 int mUserPaddingStart; 3520 3521 /** 3522 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3523 * 3524 */ 3525 @ViewDebug.ExportedProperty(category = "padding") 3526 int mUserPaddingEnd; 3527 3528 /** 3529 * Cache initial left padding. 3530 * 3531 * @hide 3532 */ 3533 int mUserPaddingLeftInitial; 3534 3535 /** 3536 * Cache initial right padding. 3537 * 3538 * @hide 3539 */ 3540 int mUserPaddingRightInitial; 3541 3542 /** 3543 * Default undefined padding 3544 */ 3545 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3546 3547 /** 3548 * Cache if a left padding has been defined 3549 */ 3550 private boolean mLeftPaddingDefined = false; 3551 3552 /** 3553 * Cache if a right padding has been defined 3554 */ 3555 private boolean mRightPaddingDefined = false; 3556 3557 /** 3558 * @hide 3559 */ 3560 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3561 /** 3562 * @hide 3563 */ 3564 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3565 3566 private LongSparseLongArray mMeasureCache; 3567 3568 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3569 private Drawable mBackground; 3570 private TintInfo mBackgroundTint; 3571 3572 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3573 private ForegroundInfo mForegroundInfo; 3574 3575 private Drawable mScrollIndicatorDrawable; 3576 3577 /** 3578 * RenderNode used for backgrounds. 3579 * <p> 3580 * When non-null and valid, this is expected to contain an up-to-date copy 3581 * of the background drawable. It is cleared on temporary detach, and reset 3582 * on cleanup. 3583 */ 3584 private RenderNode mBackgroundRenderNode; 3585 3586 private int mBackgroundResource; 3587 private boolean mBackgroundSizeChanged; 3588 3589 private String mTransitionName; 3590 3591 static class TintInfo { 3592 ColorStateList mTintList; 3593 PorterDuff.Mode mTintMode; 3594 boolean mHasTintMode; 3595 boolean mHasTintList; 3596 } 3597 3598 private static class ForegroundInfo { 3599 private Drawable mDrawable; 3600 private TintInfo mTintInfo; 3601 private int mGravity = Gravity.FILL; 3602 private boolean mInsidePadding = true; 3603 private boolean mBoundsChanged = true; 3604 private final Rect mSelfBounds = new Rect(); 3605 private final Rect mOverlayBounds = new Rect(); 3606 } 3607 3608 static class ListenerInfo { 3609 /** 3610 * Listener used to dispatch focus change events. 3611 * This field should be made private, so it is hidden from the SDK. 3612 * {@hide} 3613 */ 3614 protected OnFocusChangeListener mOnFocusChangeListener; 3615 3616 /** 3617 * Listeners for layout change events. 3618 */ 3619 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 3620 3621 protected OnScrollChangeListener mOnScrollChangeListener; 3622 3623 /** 3624 * Listeners for attach events. 3625 */ 3626 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 3627 3628 /** 3629 * Listener used to dispatch click events. 3630 * This field should be made private, so it is hidden from the SDK. 3631 * {@hide} 3632 */ 3633 public OnClickListener mOnClickListener; 3634 3635 /** 3636 * Listener used to dispatch long click events. 3637 * This field should be made private, so it is hidden from the SDK. 3638 * {@hide} 3639 */ 3640 protected OnLongClickListener mOnLongClickListener; 3641 3642 /** 3643 * Listener used to dispatch context click events. This field should be made private, so it 3644 * is hidden from the SDK. 3645 * {@hide} 3646 */ 3647 protected OnContextClickListener mOnContextClickListener; 3648 3649 /** 3650 * Listener used to build the context menu. 3651 * This field should be made private, so it is hidden from the SDK. 3652 * {@hide} 3653 */ 3654 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 3655 3656 private OnKeyListener mOnKeyListener; 3657 3658 private OnTouchListener mOnTouchListener; 3659 3660 private OnHoverListener mOnHoverListener; 3661 3662 private OnGenericMotionListener mOnGenericMotionListener; 3663 3664 private OnDragListener mOnDragListener; 3665 3666 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 3667 3668 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 3669 } 3670 3671 ListenerInfo mListenerInfo; 3672 3673 private static class TooltipInfo { 3674 /** 3675 * Text to be displayed in a tooltip popup. 3676 */ 3677 @Nullable 3678 CharSequence mTooltip; 3679 3680 /** 3681 * View-relative position of the tooltip anchor point. 3682 */ 3683 int mAnchorX; 3684 int mAnchorY; 3685 3686 /** 3687 * The tooltip popup. 3688 */ 3689 @Nullable 3690 TooltipPopup mTooltipPopup; 3691 3692 /** 3693 * Set to true if the tooltip was shown as a result of a long click. 3694 */ 3695 boolean mTooltipFromLongClick; 3696 3697 /** 3698 * Keep these Runnables so that they can be used to reschedule. 3699 */ 3700 Runnable mShowTooltipRunnable; 3701 Runnable mHideTooltipRunnable; 3702 } 3703 3704 TooltipInfo mTooltipInfo; 3705 3706 // Temporary values used to hold (x,y) coordinates when delegating from the 3707 // two-arg performLongClick() method to the legacy no-arg version. 3708 private float mLongClickX = Float.NaN; 3709 private float mLongClickY = Float.NaN; 3710 3711 /** 3712 * The application environment this view lives in. 3713 * This field should be made private, so it is hidden from the SDK. 3714 * {@hide} 3715 */ 3716 @ViewDebug.ExportedProperty(deepExport = true) 3717 protected Context mContext; 3718 3719 private final Resources mResources; 3720 3721 private ScrollabilityCache mScrollCache; 3722 3723 private int[] mDrawableState = null; 3724 3725 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 3726 3727 /** 3728 * Animator that automatically runs based on state changes. 3729 */ 3730 private StateListAnimator mStateListAnimator; 3731 3732 /** 3733 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 3734 * the user may specify which view to go to next. 3735 */ 3736 private int mNextFocusLeftId = View.NO_ID; 3737 3738 /** 3739 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 3740 * the user may specify which view to go to next. 3741 */ 3742 private int mNextFocusRightId = View.NO_ID; 3743 3744 /** 3745 * When this view has focus and the next focus is {@link #FOCUS_UP}, 3746 * the user may specify which view to go to next. 3747 */ 3748 private int mNextFocusUpId = View.NO_ID; 3749 3750 /** 3751 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 3752 * the user may specify which view to go to next. 3753 */ 3754 private int mNextFocusDownId = View.NO_ID; 3755 3756 /** 3757 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 3758 * the user may specify which view to go to next. 3759 */ 3760 int mNextFocusForwardId = View.NO_ID; 3761 3762 /** 3763 * User-specified next keyboard navigation cluster. 3764 */ 3765 int mNextClusterForwardId = View.NO_ID; 3766 3767 /** 3768 * User-specified next keyboard navigation section. 3769 */ 3770 int mNextSectionForwardId = View.NO_ID; 3771 3772 private CheckForLongPress mPendingCheckForLongPress; 3773 private CheckForTap mPendingCheckForTap = null; 3774 private PerformClick mPerformClick; 3775 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 3776 3777 private UnsetPressedState mUnsetPressedState; 3778 3779 /** 3780 * Whether the long press's action has been invoked. The tap's action is invoked on the 3781 * up event while a long press is invoked as soon as the long press duration is reached, so 3782 * a long press could be performed before the tap is checked, in which case the tap's action 3783 * should not be invoked. 3784 */ 3785 private boolean mHasPerformedLongPress; 3786 3787 /** 3788 * Whether a context click button is currently pressed down. This is true when the stylus is 3789 * touching the screen and the primary button has been pressed, or if a mouse's right button is 3790 * pressed. This is false once the button is released or if the stylus has been lifted. 3791 */ 3792 private boolean mInContextButtonPress; 3793 3794 /** 3795 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 3796 * true after a stylus button press has occured, when the next up event should not be recognized 3797 * as a tap. 3798 */ 3799 private boolean mIgnoreNextUpEvent; 3800 3801 /** 3802 * The minimum height of the view. We'll try our best to have the height 3803 * of this view to at least this amount. 3804 */ 3805 @ViewDebug.ExportedProperty(category = "measurement") 3806 private int mMinHeight; 3807 3808 /** 3809 * The minimum width of the view. We'll try our best to have the width 3810 * of this view to at least this amount. 3811 */ 3812 @ViewDebug.ExportedProperty(category = "measurement") 3813 private int mMinWidth; 3814 3815 /** 3816 * The delegate to handle touch events that are physically in this view 3817 * but should be handled by another view. 3818 */ 3819 private TouchDelegate mTouchDelegate = null; 3820 3821 /** 3822 * Solid color to use as a background when creating the drawing cache. Enables 3823 * the cache to use 16 bit bitmaps instead of 32 bit. 3824 */ 3825 private int mDrawingCacheBackgroundColor = 0; 3826 3827 /** 3828 * Special tree observer used when mAttachInfo is null. 3829 */ 3830 private ViewTreeObserver mFloatingTreeObserver; 3831 3832 /** 3833 * Cache the touch slop from the context that created the view. 3834 */ 3835 private int mTouchSlop; 3836 3837 /** 3838 * Object that handles automatic animation of view properties. 3839 */ 3840 private ViewPropertyAnimator mAnimator = null; 3841 3842 /** 3843 * List of registered FrameMetricsObservers. 3844 */ 3845 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 3846 3847 /** 3848 * Flag indicating that a drag can cross window boundaries. When 3849 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3850 * with this flag set, all visible applications with targetSdkVersion >= 3851 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 3852 * in the drag operation and receive the dragged content. 3853 * 3854 * <p>If this is the only flag set, then the drag recipient will only have access to text data 3855 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 3856 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 3857 */ 3858 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 3859 3860 /** 3861 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3862 * request read access to the content URI(s) contained in the {@link ClipData} object. 3863 * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION 3864 */ 3865 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 3866 3867 /** 3868 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3869 * request write access to the content URI(s) contained in the {@link ClipData} object. 3870 * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION 3871 */ 3872 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 3873 3874 /** 3875 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3876 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 3877 * reboots until explicitly revoked with 3878 * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}. 3879 * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION 3880 */ 3881 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 3882 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 3883 3884 /** 3885 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3886 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 3887 * match against the original granted URI. 3888 * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION 3889 */ 3890 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 3891 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 3892 3893 /** 3894 * Flag indicating that the drag shadow will be opaque. When 3895 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3896 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 3897 */ 3898 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 3899 3900 /** 3901 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 3902 */ 3903 private float mVerticalScrollFactor; 3904 3905 /** 3906 * Position of the vertical scroll bar. 3907 */ 3908 private int mVerticalScrollbarPosition; 3909 3910 /** 3911 * Position the scroll bar at the default position as determined by the system. 3912 */ 3913 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 3914 3915 /** 3916 * Position the scroll bar along the left edge. 3917 */ 3918 public static final int SCROLLBAR_POSITION_LEFT = 1; 3919 3920 /** 3921 * Position the scroll bar along the right edge. 3922 */ 3923 public static final int SCROLLBAR_POSITION_RIGHT = 2; 3924 3925 /** 3926 * Indicates that the view does not have a layer. 3927 * 3928 * @see #getLayerType() 3929 * @see #setLayerType(int, android.graphics.Paint) 3930 * @see #LAYER_TYPE_SOFTWARE 3931 * @see #LAYER_TYPE_HARDWARE 3932 */ 3933 public static final int LAYER_TYPE_NONE = 0; 3934 3935 /** 3936 * <p>Indicates that the view has a software layer. A software layer is backed 3937 * by a bitmap and causes the view to be rendered using Android's software 3938 * rendering pipeline, even if hardware acceleration is enabled.</p> 3939 * 3940 * <p>Software layers have various usages:</p> 3941 * <p>When the application is not using hardware acceleration, a software layer 3942 * is useful to apply a specific color filter and/or blending mode and/or 3943 * translucency to a view and all its children.</p> 3944 * <p>When the application is using hardware acceleration, a software layer 3945 * is useful to render drawing primitives not supported by the hardware 3946 * accelerated pipeline. It can also be used to cache a complex view tree 3947 * into a texture and reduce the complexity of drawing operations. For instance, 3948 * when animating a complex view tree with a translation, a software layer can 3949 * be used to render the view tree only once.</p> 3950 * <p>Software layers should be avoided when the affected view tree updates 3951 * often. Every update will require to re-render the software layer, which can 3952 * potentially be slow (particularly when hardware acceleration is turned on 3953 * since the layer will have to be uploaded into a hardware texture after every 3954 * update.)</p> 3955 * 3956 * @see #getLayerType() 3957 * @see #setLayerType(int, android.graphics.Paint) 3958 * @see #LAYER_TYPE_NONE 3959 * @see #LAYER_TYPE_HARDWARE 3960 */ 3961 public static final int LAYER_TYPE_SOFTWARE = 1; 3962 3963 /** 3964 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 3965 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 3966 * OpenGL hardware) and causes the view to be rendered using Android's hardware 3967 * rendering pipeline, but only if hardware acceleration is turned on for the 3968 * view hierarchy. When hardware acceleration is turned off, hardware layers 3969 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 3970 * 3971 * <p>A hardware layer is useful to apply a specific color filter and/or 3972 * blending mode and/or translucency to a view and all its children.</p> 3973 * <p>A hardware layer can be used to cache a complex view tree into a 3974 * texture and reduce the complexity of drawing operations. For instance, 3975 * when animating a complex view tree with a translation, a hardware layer can 3976 * be used to render the view tree only once.</p> 3977 * <p>A hardware layer can also be used to increase the rendering quality when 3978 * rotation transformations are applied on a view. It can also be used to 3979 * prevent potential clipping issues when applying 3D transforms on a view.</p> 3980 * 3981 * @see #getLayerType() 3982 * @see #setLayerType(int, android.graphics.Paint) 3983 * @see #LAYER_TYPE_NONE 3984 * @see #LAYER_TYPE_SOFTWARE 3985 */ 3986 public static final int LAYER_TYPE_HARDWARE = 2; 3987 3988 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 3989 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 3990 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 3991 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 3992 }) 3993 int mLayerType = LAYER_TYPE_NONE; 3994 Paint mLayerPaint; 3995 3996 3997 /** 3998 * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should not contain 3999 * PII (Personally Identifiable Information). 4000 */ 4001 // TODO(b/33197203) (b/33269702): improve documentation: mention all cases, show examples, etc. 4002 public static final int ASSIST_FLAG_SANITIZED_TEXT = 0x1; 4003 4004 /** 4005 * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should contain all 4006 * type of data, even sensitive PII (Personally Identifiable Information) like passwords or 4007 * credit card numbers. 4008 */ 4009 public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 0x2; 4010 4011 /** 4012 * Set to true when drawing cache is enabled and cannot be created. 4013 * 4014 * @hide 4015 */ 4016 public boolean mCachingFailed; 4017 private Bitmap mDrawingCache; 4018 private Bitmap mUnscaledDrawingCache; 4019 4020 /** 4021 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4022 * <p> 4023 * When non-null and valid, this is expected to contain an up-to-date copy 4024 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4025 * cleanup. 4026 */ 4027 final RenderNode mRenderNode; 4028 4029 /** 4030 * Set to true when the view is sending hover accessibility events because it 4031 * is the innermost hovered view. 4032 */ 4033 private boolean mSendingHoverAccessibilityEvents; 4034 4035 /** 4036 * Delegate for injecting accessibility functionality. 4037 */ 4038 AccessibilityDelegate mAccessibilityDelegate; 4039 4040 /** 4041 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4042 * and add/remove objects to/from the overlay directly through the Overlay methods. 4043 */ 4044 ViewOverlay mOverlay; 4045 4046 /** 4047 * The currently active parent view for receiving delegated nested scrolling events. 4048 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4049 * by {@link #stopNestedScroll()} at the same point where we clear 4050 * requestDisallowInterceptTouchEvent. 4051 */ 4052 private ViewParent mNestedScrollingParent; 4053 4054 /** 4055 * Consistency verifier for debugging purposes. 4056 * @hide 4057 */ 4058 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4059 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4060 new InputEventConsistencyVerifier(this, 0) : null; 4061 4062 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4063 4064 private int[] mTempNestedScrollConsumed; 4065 4066 /** 4067 * An overlay is going to draw this View instead of being drawn as part of this 4068 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4069 * when this view is invalidated. 4070 */ 4071 GhostView mGhostView; 4072 4073 /** 4074 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4075 * @hide 4076 */ 4077 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4078 public String[] mAttributes; 4079 4080 /** 4081 * Maps a Resource id to its name. 4082 */ 4083 private static SparseArray<String> mAttributeMap; 4084 4085 /** 4086 * Queue of pending runnables. Used to postpone calls to post() until this 4087 * view is attached and has a handler. 4088 */ 4089 private HandlerActionQueue mRunQueue; 4090 4091 /** 4092 * The pointer icon when the mouse hovers on this view. The default is null. 4093 */ 4094 private PointerIcon mPointerIcon; 4095 4096 /** 4097 * @hide 4098 */ 4099 String mStartActivityRequestWho; 4100 4101 @Nullable 4102 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4103 4104 /** 4105 * Simple constructor to use when creating a view from code. 4106 * 4107 * @param context The Context the view is running in, through which it can 4108 * access the current theme, resources, etc. 4109 */ 4110 public View(Context context) { 4111 mContext = context; 4112 mResources = context != null ? context.getResources() : null; 4113 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED; 4114 // Set some flags defaults 4115 mPrivateFlags2 = 4116 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4117 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4118 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4119 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4120 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4121 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4122 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4123 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4124 mUserPaddingStart = UNDEFINED_PADDING; 4125 mUserPaddingEnd = UNDEFINED_PADDING; 4126 mRenderNode = RenderNode.create(getClass().getName(), this); 4127 4128 if (!sCompatibilityDone && context != null) { 4129 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4130 4131 // Older apps may need this compatibility hack for measurement. 4132 sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1; 4133 4134 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4135 // of whether a layout was requested on that View. 4136 sIgnoreMeasureCache = targetSdkVersion < KITKAT; 4137 4138 Canvas.sCompatibilityRestore = targetSdkVersion < M; 4139 4140 // In M and newer, our widgets can pass a "hint" value in the size 4141 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4142 // know what the expected parent size is going to be, so e.g. list items can size 4143 // themselves at 1/3 the size of their container. It breaks older apps though, 4144 // specifically apps that use some popular open source libraries. 4145 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < M; 4146 4147 // Old versions of the platform would give different results from 4148 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4149 // modes, so we always need to run an additional EXACTLY pass. 4150 sAlwaysRemeasureExactly = targetSdkVersion <= M; 4151 4152 // Prior to N, layout params could change without requiring a 4153 // subsequent call to setLayoutParams() and they would usually 4154 // work. Partial layout breaks this assumption. 4155 sLayoutParamsAlwaysChanged = targetSdkVersion <= M; 4156 4157 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4158 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4159 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M; 4160 4161 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4162 // in apps so we target check it to avoid breaking existing apps. 4163 sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N; 4164 4165 sCascadedDragDrop = targetSdkVersion < N; 4166 4167 sCompatibilityDone = true; 4168 } 4169 } 4170 4171 /** 4172 * Constructor that is called when inflating a view from XML. This is called 4173 * when a view is being constructed from an XML file, supplying attributes 4174 * that were specified in the XML file. This version uses a default style of 4175 * 0, so the only attribute values applied are those in the Context's Theme 4176 * and the given AttributeSet. 4177 * 4178 * <p> 4179 * The method onFinishInflate() will be called after all children have been 4180 * added. 4181 * 4182 * @param context The Context the view is running in, through which it can 4183 * access the current theme, resources, etc. 4184 * @param attrs The attributes of the XML tag that is inflating the view. 4185 * @see #View(Context, AttributeSet, int) 4186 */ 4187 public View(Context context, @Nullable AttributeSet attrs) { 4188 this(context, attrs, 0); 4189 } 4190 4191 /** 4192 * Perform inflation from XML and apply a class-specific base style from a 4193 * theme attribute. This constructor of View allows subclasses to use their 4194 * own base style when they are inflating. For example, a Button class's 4195 * constructor would call this version of the super class constructor and 4196 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4197 * allows the theme's button style to modify all of the base view attributes 4198 * (in particular its background) as well as the Button class's attributes. 4199 * 4200 * @param context The Context the view is running in, through which it can 4201 * access the current theme, resources, etc. 4202 * @param attrs The attributes of the XML tag that is inflating the view. 4203 * @param defStyleAttr An attribute in the current theme that contains a 4204 * reference to a style resource that supplies default values for 4205 * the view. Can be 0 to not look for defaults. 4206 * @see #View(Context, AttributeSet) 4207 */ 4208 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4209 this(context, attrs, defStyleAttr, 0); 4210 } 4211 4212 /** 4213 * Perform inflation from XML and apply a class-specific base style from a 4214 * theme attribute or style resource. This constructor of View allows 4215 * subclasses to use their own base style when they are inflating. 4216 * <p> 4217 * When determining the final value of a particular attribute, there are 4218 * four inputs that come into play: 4219 * <ol> 4220 * <li>Any attribute values in the given AttributeSet. 4221 * <li>The style resource specified in the AttributeSet (named "style"). 4222 * <li>The default style specified by <var>defStyleAttr</var>. 4223 * <li>The default style specified by <var>defStyleRes</var>. 4224 * <li>The base values in this theme. 4225 * </ol> 4226 * <p> 4227 * Each of these inputs is considered in-order, with the first listed taking 4228 * precedence over the following ones. In other words, if in the 4229 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4230 * , then the button's text will <em>always</em> be black, regardless of 4231 * what is specified in any of the styles. 4232 * 4233 * @param context The Context the view is running in, through which it can 4234 * access the current theme, resources, etc. 4235 * @param attrs The attributes of the XML tag that is inflating the view. 4236 * @param defStyleAttr An attribute in the current theme that contains a 4237 * reference to a style resource that supplies default values for 4238 * the view. Can be 0 to not look for defaults. 4239 * @param defStyleRes A resource identifier of a style resource that 4240 * supplies default values for the view, used only if 4241 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4242 * to not look for defaults. 4243 * @see #View(Context, AttributeSet, int) 4244 */ 4245 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4246 this(context); 4247 4248 final TypedArray a = context.obtainStyledAttributes( 4249 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4250 4251 if (mDebugViewAttributes) { 4252 saveAttributeData(attrs, a); 4253 } 4254 4255 Drawable background = null; 4256 4257 int leftPadding = -1; 4258 int topPadding = -1; 4259 int rightPadding = -1; 4260 int bottomPadding = -1; 4261 int startPadding = UNDEFINED_PADDING; 4262 int endPadding = UNDEFINED_PADDING; 4263 4264 int padding = -1; 4265 int paddingHorizontal = -1; 4266 int paddingVertical = -1; 4267 4268 int viewFlagValues = 0; 4269 int viewFlagMasks = 0; 4270 4271 boolean setScrollContainer = false; 4272 4273 int x = 0; 4274 int y = 0; 4275 4276 float tx = 0; 4277 float ty = 0; 4278 float tz = 0; 4279 float elevation = 0; 4280 float rotation = 0; 4281 float rotationX = 0; 4282 float rotationY = 0; 4283 float sx = 1f; 4284 float sy = 1f; 4285 boolean transformSet = false; 4286 4287 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4288 int overScrollMode = mOverScrollMode; 4289 boolean initializeScrollbars = false; 4290 boolean initializeScrollIndicators = false; 4291 4292 boolean startPaddingDefined = false; 4293 boolean endPaddingDefined = false; 4294 boolean leftPaddingDefined = false; 4295 boolean rightPaddingDefined = false; 4296 4297 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4298 4299 final int N = a.getIndexCount(); 4300 for (int i = 0; i < N; i++) { 4301 int attr = a.getIndex(i); 4302 switch (attr) { 4303 case com.android.internal.R.styleable.View_background: 4304 background = a.getDrawable(attr); 4305 break; 4306 case com.android.internal.R.styleable.View_padding: 4307 padding = a.getDimensionPixelSize(attr, -1); 4308 mUserPaddingLeftInitial = padding; 4309 mUserPaddingRightInitial = padding; 4310 leftPaddingDefined = true; 4311 rightPaddingDefined = true; 4312 break; 4313 case com.android.internal.R.styleable.View_paddingHorizontal: 4314 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4315 mUserPaddingLeftInitial = paddingHorizontal; 4316 mUserPaddingRightInitial = paddingHorizontal; 4317 leftPaddingDefined = true; 4318 rightPaddingDefined = true; 4319 break; 4320 case com.android.internal.R.styleable.View_paddingVertical: 4321 paddingVertical = a.getDimensionPixelSize(attr, -1); 4322 break; 4323 case com.android.internal.R.styleable.View_paddingLeft: 4324 leftPadding = a.getDimensionPixelSize(attr, -1); 4325 mUserPaddingLeftInitial = leftPadding; 4326 leftPaddingDefined = true; 4327 break; 4328 case com.android.internal.R.styleable.View_paddingTop: 4329 topPadding = a.getDimensionPixelSize(attr, -1); 4330 break; 4331 case com.android.internal.R.styleable.View_paddingRight: 4332 rightPadding = a.getDimensionPixelSize(attr, -1); 4333 mUserPaddingRightInitial = rightPadding; 4334 rightPaddingDefined = true; 4335 break; 4336 case com.android.internal.R.styleable.View_paddingBottom: 4337 bottomPadding = a.getDimensionPixelSize(attr, -1); 4338 break; 4339 case com.android.internal.R.styleable.View_paddingStart: 4340 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4341 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4342 break; 4343 case com.android.internal.R.styleable.View_paddingEnd: 4344 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4345 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4346 break; 4347 case com.android.internal.R.styleable.View_scrollX: 4348 x = a.getDimensionPixelOffset(attr, 0); 4349 break; 4350 case com.android.internal.R.styleable.View_scrollY: 4351 y = a.getDimensionPixelOffset(attr, 0); 4352 break; 4353 case com.android.internal.R.styleable.View_alpha: 4354 setAlpha(a.getFloat(attr, 1f)); 4355 break; 4356 case com.android.internal.R.styleable.View_transformPivotX: 4357 setPivotX(a.getDimension(attr, 0)); 4358 break; 4359 case com.android.internal.R.styleable.View_transformPivotY: 4360 setPivotY(a.getDimension(attr, 0)); 4361 break; 4362 case com.android.internal.R.styleable.View_translationX: 4363 tx = a.getDimension(attr, 0); 4364 transformSet = true; 4365 break; 4366 case com.android.internal.R.styleable.View_translationY: 4367 ty = a.getDimension(attr, 0); 4368 transformSet = true; 4369 break; 4370 case com.android.internal.R.styleable.View_translationZ: 4371 tz = a.getDimension(attr, 0); 4372 transformSet = true; 4373 break; 4374 case com.android.internal.R.styleable.View_elevation: 4375 elevation = a.getDimension(attr, 0); 4376 transformSet = true; 4377 break; 4378 case com.android.internal.R.styleable.View_rotation: 4379 rotation = a.getFloat(attr, 0); 4380 transformSet = true; 4381 break; 4382 case com.android.internal.R.styleable.View_rotationX: 4383 rotationX = a.getFloat(attr, 0); 4384 transformSet = true; 4385 break; 4386 case com.android.internal.R.styleable.View_rotationY: 4387 rotationY = a.getFloat(attr, 0); 4388 transformSet = true; 4389 break; 4390 case com.android.internal.R.styleable.View_scaleX: 4391 sx = a.getFloat(attr, 1f); 4392 transformSet = true; 4393 break; 4394 case com.android.internal.R.styleable.View_scaleY: 4395 sy = a.getFloat(attr, 1f); 4396 transformSet = true; 4397 break; 4398 case com.android.internal.R.styleable.View_id: 4399 mID = a.getResourceId(attr, NO_ID); 4400 break; 4401 case com.android.internal.R.styleable.View_tag: 4402 mTag = a.getText(attr); 4403 break; 4404 case com.android.internal.R.styleable.View_fitsSystemWindows: 4405 if (a.getBoolean(attr, false)) { 4406 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4407 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4408 } 4409 break; 4410 case com.android.internal.R.styleable.View_focusable: 4411 if (a.getBoolean(attr, false)) { 4412 viewFlagValues |= FOCUSABLE; 4413 viewFlagMasks |= FOCUSABLE_MASK; 4414 } 4415 break; 4416 case com.android.internal.R.styleable.View_focusableInTouchMode: 4417 if (a.getBoolean(attr, false)) { 4418 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4419 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4420 } 4421 break; 4422 case com.android.internal.R.styleable.View_clickable: 4423 if (a.getBoolean(attr, false)) { 4424 viewFlagValues |= CLICKABLE; 4425 viewFlagMasks |= CLICKABLE; 4426 } 4427 break; 4428 case com.android.internal.R.styleable.View_longClickable: 4429 if (a.getBoolean(attr, false)) { 4430 viewFlagValues |= LONG_CLICKABLE; 4431 viewFlagMasks |= LONG_CLICKABLE; 4432 } 4433 break; 4434 case com.android.internal.R.styleable.View_contextClickable: 4435 if (a.getBoolean(attr, false)) { 4436 viewFlagValues |= CONTEXT_CLICKABLE; 4437 viewFlagMasks |= CONTEXT_CLICKABLE; 4438 } 4439 break; 4440 case com.android.internal.R.styleable.View_saveEnabled: 4441 if (!a.getBoolean(attr, true)) { 4442 viewFlagValues |= SAVE_DISABLED; 4443 viewFlagMasks |= SAVE_DISABLED_MASK; 4444 } 4445 break; 4446 case com.android.internal.R.styleable.View_duplicateParentState: 4447 if (a.getBoolean(attr, false)) { 4448 viewFlagValues |= DUPLICATE_PARENT_STATE; 4449 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4450 } 4451 break; 4452 case com.android.internal.R.styleable.View_visibility: 4453 final int visibility = a.getInt(attr, 0); 4454 if (visibility != 0) { 4455 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4456 viewFlagMasks |= VISIBILITY_MASK; 4457 } 4458 break; 4459 case com.android.internal.R.styleable.View_layoutDirection: 4460 // Clear any layout direction flags (included resolved bits) already set 4461 mPrivateFlags2 &= 4462 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4463 // Set the layout direction flags depending on the value of the attribute 4464 final int layoutDirection = a.getInt(attr, -1); 4465 final int value = (layoutDirection != -1) ? 4466 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4467 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4468 break; 4469 case com.android.internal.R.styleable.View_drawingCacheQuality: 4470 final int cacheQuality = a.getInt(attr, 0); 4471 if (cacheQuality != 0) { 4472 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4473 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4474 } 4475 break; 4476 case com.android.internal.R.styleable.View_contentDescription: 4477 setContentDescription(a.getString(attr)); 4478 break; 4479 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4480 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4481 break; 4482 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4483 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4484 break; 4485 case com.android.internal.R.styleable.View_labelFor: 4486 setLabelFor(a.getResourceId(attr, NO_ID)); 4487 break; 4488 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4489 if (!a.getBoolean(attr, true)) { 4490 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4491 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4492 } 4493 break; 4494 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4495 if (!a.getBoolean(attr, true)) { 4496 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4497 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4498 } 4499 break; 4500 case R.styleable.View_scrollbars: 4501 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4502 if (scrollbars != SCROLLBARS_NONE) { 4503 viewFlagValues |= scrollbars; 4504 viewFlagMasks |= SCROLLBARS_MASK; 4505 initializeScrollbars = true; 4506 } 4507 break; 4508 //noinspection deprecation 4509 case R.styleable.View_fadingEdge: 4510 if (targetSdkVersion >= ICE_CREAM_SANDWICH) { 4511 // Ignore the attribute starting with ICS 4512 break; 4513 } 4514 // With builds < ICS, fall through and apply fading edges 4515 case R.styleable.View_requiresFadingEdge: 4516 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4517 if (fadingEdge != FADING_EDGE_NONE) { 4518 viewFlagValues |= fadingEdge; 4519 viewFlagMasks |= FADING_EDGE_MASK; 4520 initializeFadingEdgeInternal(a); 4521 } 4522 break; 4523 case R.styleable.View_scrollbarStyle: 4524 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4525 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4526 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4527 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4528 } 4529 break; 4530 case R.styleable.View_isScrollContainer: 4531 setScrollContainer = true; 4532 if (a.getBoolean(attr, false)) { 4533 setScrollContainer(true); 4534 } 4535 break; 4536 case com.android.internal.R.styleable.View_keepScreenOn: 4537 if (a.getBoolean(attr, false)) { 4538 viewFlagValues |= KEEP_SCREEN_ON; 4539 viewFlagMasks |= KEEP_SCREEN_ON; 4540 } 4541 break; 4542 case R.styleable.View_filterTouchesWhenObscured: 4543 if (a.getBoolean(attr, false)) { 4544 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4545 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4546 } 4547 break; 4548 case R.styleable.View_nextFocusLeft: 4549 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4550 break; 4551 case R.styleable.View_nextFocusRight: 4552 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4553 break; 4554 case R.styleable.View_nextFocusUp: 4555 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4556 break; 4557 case R.styleable.View_nextFocusDown: 4558 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4559 break; 4560 case R.styleable.View_nextFocusForward: 4561 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4562 break; 4563 case R.styleable.View_nextClusterForward: 4564 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 4565 break; 4566 case R.styleable.View_nextSectionForward: 4567 mNextSectionForwardId = a.getResourceId(attr, View.NO_ID); 4568 break; 4569 case R.styleable.View_minWidth: 4570 mMinWidth = a.getDimensionPixelSize(attr, 0); 4571 break; 4572 case R.styleable.View_minHeight: 4573 mMinHeight = a.getDimensionPixelSize(attr, 0); 4574 break; 4575 case R.styleable.View_onClick: 4576 if (context.isRestricted()) { 4577 throw new IllegalStateException("The android:onClick attribute cannot " 4578 + "be used within a restricted context"); 4579 } 4580 4581 final String handlerName = a.getString(attr); 4582 if (handlerName != null) { 4583 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 4584 } 4585 break; 4586 case R.styleable.View_overScrollMode: 4587 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 4588 break; 4589 case R.styleable.View_verticalScrollbarPosition: 4590 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 4591 break; 4592 case R.styleable.View_layerType: 4593 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 4594 break; 4595 case R.styleable.View_textDirection: 4596 // Clear any text direction flag already set 4597 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 4598 // Set the text direction flags depending on the value of the attribute 4599 final int textDirection = a.getInt(attr, -1); 4600 if (textDirection != -1) { 4601 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 4602 } 4603 break; 4604 case R.styleable.View_textAlignment: 4605 // Clear any text alignment flag already set 4606 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 4607 // Set the text alignment flag depending on the value of the attribute 4608 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 4609 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 4610 break; 4611 case R.styleable.View_importantForAccessibility: 4612 setImportantForAccessibility(a.getInt(attr, 4613 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 4614 break; 4615 case R.styleable.View_accessibilityLiveRegion: 4616 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 4617 break; 4618 case R.styleable.View_transitionName: 4619 setTransitionName(a.getString(attr)); 4620 break; 4621 case R.styleable.View_nestedScrollingEnabled: 4622 setNestedScrollingEnabled(a.getBoolean(attr, false)); 4623 break; 4624 case R.styleable.View_stateListAnimator: 4625 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 4626 a.getResourceId(attr, 0))); 4627 break; 4628 case R.styleable.View_backgroundTint: 4629 // This will get applied later during setBackground(). 4630 if (mBackgroundTint == null) { 4631 mBackgroundTint = new TintInfo(); 4632 } 4633 mBackgroundTint.mTintList = a.getColorStateList( 4634 R.styleable.View_backgroundTint); 4635 mBackgroundTint.mHasTintList = true; 4636 break; 4637 case R.styleable.View_backgroundTintMode: 4638 // This will get applied later during setBackground(). 4639 if (mBackgroundTint == null) { 4640 mBackgroundTint = new TintInfo(); 4641 } 4642 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 4643 R.styleable.View_backgroundTintMode, -1), null); 4644 mBackgroundTint.mHasTintMode = true; 4645 break; 4646 case R.styleable.View_outlineProvider: 4647 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 4648 PROVIDER_BACKGROUND)); 4649 break; 4650 case R.styleable.View_foreground: 4651 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4652 setForeground(a.getDrawable(attr)); 4653 } 4654 break; 4655 case R.styleable.View_foregroundGravity: 4656 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4657 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 4658 } 4659 break; 4660 case R.styleable.View_foregroundTintMode: 4661 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4662 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 4663 } 4664 break; 4665 case R.styleable.View_foregroundTint: 4666 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4667 setForegroundTintList(a.getColorStateList(attr)); 4668 } 4669 break; 4670 case R.styleable.View_foregroundInsidePadding: 4671 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4672 if (mForegroundInfo == null) { 4673 mForegroundInfo = new ForegroundInfo(); 4674 } 4675 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 4676 mForegroundInfo.mInsidePadding); 4677 } 4678 break; 4679 case R.styleable.View_scrollIndicators: 4680 final int scrollIndicators = 4681 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 4682 & SCROLL_INDICATORS_PFLAG3_MASK; 4683 if (scrollIndicators != 0) { 4684 mPrivateFlags3 |= scrollIndicators; 4685 initializeScrollIndicators = true; 4686 } 4687 break; 4688 case R.styleable.View_pointerIcon: 4689 final int resourceId = a.getResourceId(attr, 0); 4690 if (resourceId != 0) { 4691 setPointerIcon(PointerIcon.load( 4692 context.getResources(), resourceId)); 4693 } else { 4694 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 4695 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 4696 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 4697 } 4698 } 4699 break; 4700 case R.styleable.View_forceHasOverlappingRendering: 4701 if (a.peekValue(attr) != null) { 4702 forceHasOverlappingRendering(a.getBoolean(attr, true)); 4703 } 4704 break; 4705 case R.styleable.View_tooltip: 4706 setTooltip(a.getText(attr)); 4707 break; 4708 case R.styleable.View_keyboardNavigationCluster: 4709 if (a.peekValue(attr) != null) { 4710 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 4711 } 4712 break; 4713 case R.styleable.View_keyboardNavigationSection: 4714 if (a.peekValue(attr) != null) { 4715 setKeyboardNavigationSection(a.getBoolean(attr, true)); 4716 } 4717 break; 4718 } 4719 } 4720 4721 setOverScrollMode(overScrollMode); 4722 4723 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 4724 // the resolved layout direction). Those cached values will be used later during padding 4725 // resolution. 4726 mUserPaddingStart = startPadding; 4727 mUserPaddingEnd = endPadding; 4728 4729 if (background != null) { 4730 setBackground(background); 4731 } 4732 4733 // setBackground above will record that padding is currently provided by the background. 4734 // If we have padding specified via xml, record that here instead and use it. 4735 mLeftPaddingDefined = leftPaddingDefined; 4736 mRightPaddingDefined = rightPaddingDefined; 4737 4738 if (padding >= 0) { 4739 leftPadding = padding; 4740 topPadding = padding; 4741 rightPadding = padding; 4742 bottomPadding = padding; 4743 mUserPaddingLeftInitial = padding; 4744 mUserPaddingRightInitial = padding; 4745 } else { 4746 if (paddingHorizontal >= 0) { 4747 leftPadding = paddingHorizontal; 4748 rightPadding = paddingHorizontal; 4749 mUserPaddingLeftInitial = paddingHorizontal; 4750 mUserPaddingRightInitial = paddingHorizontal; 4751 } 4752 if (paddingVertical >= 0) { 4753 topPadding = paddingVertical; 4754 bottomPadding = paddingVertical; 4755 } 4756 } 4757 4758 if (isRtlCompatibilityMode()) { 4759 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 4760 // left / right padding are used if defined (meaning here nothing to do). If they are not 4761 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 4762 // start / end and resolve them as left / right (layout direction is not taken into account). 4763 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4764 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4765 // defined. 4766 if (!mLeftPaddingDefined && startPaddingDefined) { 4767 leftPadding = startPadding; 4768 } 4769 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 4770 if (!mRightPaddingDefined && endPaddingDefined) { 4771 rightPadding = endPadding; 4772 } 4773 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 4774 } else { 4775 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 4776 // values defined. Otherwise, left /right values are used. 4777 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4778 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4779 // defined. 4780 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 4781 4782 if (mLeftPaddingDefined && !hasRelativePadding) { 4783 mUserPaddingLeftInitial = leftPadding; 4784 } 4785 if (mRightPaddingDefined && !hasRelativePadding) { 4786 mUserPaddingRightInitial = rightPadding; 4787 } 4788 } 4789 4790 internalSetPadding( 4791 mUserPaddingLeftInitial, 4792 topPadding >= 0 ? topPadding : mPaddingTop, 4793 mUserPaddingRightInitial, 4794 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 4795 4796 if (viewFlagMasks != 0) { 4797 setFlags(viewFlagValues, viewFlagMasks); 4798 } 4799 4800 if (initializeScrollbars) { 4801 initializeScrollbarsInternal(a); 4802 } 4803 4804 if (initializeScrollIndicators) { 4805 initializeScrollIndicatorsInternal(); 4806 } 4807 4808 a.recycle(); 4809 4810 // Needs to be called after mViewFlags is set 4811 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4812 recomputePadding(); 4813 } 4814 4815 if (x != 0 || y != 0) { 4816 scrollTo(x, y); 4817 } 4818 4819 if (transformSet) { 4820 setTranslationX(tx); 4821 setTranslationY(ty); 4822 setTranslationZ(tz); 4823 setElevation(elevation); 4824 setRotation(rotation); 4825 setRotationX(rotationX); 4826 setRotationY(rotationY); 4827 setScaleX(sx); 4828 setScaleY(sy); 4829 } 4830 4831 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 4832 setScrollContainer(true); 4833 } 4834 4835 computeOpaqueFlags(); 4836 } 4837 4838 /** 4839 * An implementation of OnClickListener that attempts to lazily load a 4840 * named click handling method from a parent or ancestor context. 4841 */ 4842 private static class DeclaredOnClickListener implements OnClickListener { 4843 private final View mHostView; 4844 private final String mMethodName; 4845 4846 private Method mResolvedMethod; 4847 private Context mResolvedContext; 4848 4849 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 4850 mHostView = hostView; 4851 mMethodName = methodName; 4852 } 4853 4854 @Override 4855 public void onClick(@NonNull View v) { 4856 if (mResolvedMethod == null) { 4857 resolveMethod(mHostView.getContext(), mMethodName); 4858 } 4859 4860 try { 4861 mResolvedMethod.invoke(mResolvedContext, v); 4862 } catch (IllegalAccessException e) { 4863 throw new IllegalStateException( 4864 "Could not execute non-public method for android:onClick", e); 4865 } catch (InvocationTargetException e) { 4866 throw new IllegalStateException( 4867 "Could not execute method for android:onClick", e); 4868 } 4869 } 4870 4871 @NonNull 4872 private void resolveMethod(@Nullable Context context, @NonNull String name) { 4873 while (context != null) { 4874 try { 4875 if (!context.isRestricted()) { 4876 final Method method = context.getClass().getMethod(mMethodName, View.class); 4877 if (method != null) { 4878 mResolvedMethod = method; 4879 mResolvedContext = context; 4880 return; 4881 } 4882 } 4883 } catch (NoSuchMethodException e) { 4884 // Failed to find method, keep searching up the hierarchy. 4885 } 4886 4887 if (context instanceof ContextWrapper) { 4888 context = ((ContextWrapper) context).getBaseContext(); 4889 } else { 4890 // Can't search up the hierarchy, null out and fail. 4891 context = null; 4892 } 4893 } 4894 4895 final int id = mHostView.getId(); 4896 final String idText = id == NO_ID ? "" : " with id '" 4897 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 4898 throw new IllegalStateException("Could not find method " + mMethodName 4899 + "(View) in a parent or ancestor Context for android:onClick " 4900 + "attribute defined on view " + mHostView.getClass() + idText); 4901 } 4902 } 4903 4904 /** 4905 * Non-public constructor for use in testing 4906 */ 4907 View() { 4908 mResources = null; 4909 mRenderNode = RenderNode.create(getClass().getName(), this); 4910 } 4911 4912 final boolean debugDraw() { 4913 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 4914 } 4915 4916 private static SparseArray<String> getAttributeMap() { 4917 if (mAttributeMap == null) { 4918 mAttributeMap = new SparseArray<>(); 4919 } 4920 return mAttributeMap; 4921 } 4922 4923 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 4924 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 4925 final int indexCount = t.getIndexCount(); 4926 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 4927 4928 int i = 0; 4929 4930 // Store raw XML attributes. 4931 for (int j = 0; j < attrsCount; ++j) { 4932 attributes[i] = attrs.getAttributeName(j); 4933 attributes[i + 1] = attrs.getAttributeValue(j); 4934 i += 2; 4935 } 4936 4937 // Store resolved styleable attributes. 4938 final Resources res = t.getResources(); 4939 final SparseArray<String> attributeMap = getAttributeMap(); 4940 for (int j = 0; j < indexCount; ++j) { 4941 final int index = t.getIndex(j); 4942 if (!t.hasValueOrEmpty(index)) { 4943 // Value is undefined. Skip it. 4944 continue; 4945 } 4946 4947 final int resourceId = t.getResourceId(index, 0); 4948 if (resourceId == 0) { 4949 // Value is not a reference. Skip it. 4950 continue; 4951 } 4952 4953 String resourceName = attributeMap.get(resourceId); 4954 if (resourceName == null) { 4955 try { 4956 resourceName = res.getResourceName(resourceId); 4957 } catch (Resources.NotFoundException e) { 4958 resourceName = "0x" + Integer.toHexString(resourceId); 4959 } 4960 attributeMap.put(resourceId, resourceName); 4961 } 4962 4963 attributes[i] = resourceName; 4964 attributes[i + 1] = t.getString(index); 4965 i += 2; 4966 } 4967 4968 // Trim to fit contents. 4969 final String[] trimmed = new String[i]; 4970 System.arraycopy(attributes, 0, trimmed, 0, i); 4971 mAttributes = trimmed; 4972 } 4973 4974 public String toString() { 4975 StringBuilder out = new StringBuilder(128); 4976 out.append(getClass().getName()); 4977 out.append('{'); 4978 out.append(Integer.toHexString(System.identityHashCode(this))); 4979 out.append(' '); 4980 switch (mViewFlags&VISIBILITY_MASK) { 4981 case VISIBLE: out.append('V'); break; 4982 case INVISIBLE: out.append('I'); break; 4983 case GONE: out.append('G'); break; 4984 default: out.append('.'); break; 4985 } 4986 out.append((mViewFlags&FOCUSABLE_MASK) == FOCUSABLE ? 'F' : '.'); 4987 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 4988 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 4989 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 4990 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 4991 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 4992 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 4993 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 4994 out.append(' '); 4995 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 4996 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 4997 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 4998 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 4999 out.append('p'); 5000 } else { 5001 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5002 } 5003 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5004 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5005 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5006 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5007 out.append(' '); 5008 out.append(mLeft); 5009 out.append(','); 5010 out.append(mTop); 5011 out.append('-'); 5012 out.append(mRight); 5013 out.append(','); 5014 out.append(mBottom); 5015 final int id = getId(); 5016 if (id != NO_ID) { 5017 out.append(" #"); 5018 out.append(Integer.toHexString(id)); 5019 final Resources r = mResources; 5020 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5021 try { 5022 String pkgname; 5023 switch (id&0xff000000) { 5024 case 0x7f000000: 5025 pkgname="app"; 5026 break; 5027 case 0x01000000: 5028 pkgname="android"; 5029 break; 5030 default: 5031 pkgname = r.getResourcePackageName(id); 5032 break; 5033 } 5034 String typename = r.getResourceTypeName(id); 5035 String entryname = r.getResourceEntryName(id); 5036 out.append(" "); 5037 out.append(pkgname); 5038 out.append(":"); 5039 out.append(typename); 5040 out.append("/"); 5041 out.append(entryname); 5042 } catch (Resources.NotFoundException e) { 5043 } 5044 } 5045 } 5046 out.append("}"); 5047 return out.toString(); 5048 } 5049 5050 /** 5051 * <p> 5052 * Initializes the fading edges from a given set of styled attributes. This 5053 * method should be called by subclasses that need fading edges and when an 5054 * instance of these subclasses is created programmatically rather than 5055 * being inflated from XML. This method is automatically called when the XML 5056 * is inflated. 5057 * </p> 5058 * 5059 * @param a the styled attributes set to initialize the fading edges from 5060 * 5061 * @removed 5062 */ 5063 protected void initializeFadingEdge(TypedArray a) { 5064 // This method probably shouldn't have been included in the SDK to begin with. 5065 // It relies on 'a' having been initialized using an attribute filter array that is 5066 // not publicly available to the SDK. The old method has been renamed 5067 // to initializeFadingEdgeInternal and hidden for framework use only; 5068 // this one initializes using defaults to make it safe to call for apps. 5069 5070 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5071 5072 initializeFadingEdgeInternal(arr); 5073 5074 arr.recycle(); 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 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5088 */ 5089 protected void initializeFadingEdgeInternal(TypedArray a) { 5090 initScrollCache(); 5091 5092 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5093 R.styleable.View_fadingEdgeLength, 5094 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5095 } 5096 5097 /** 5098 * Returns the size of the vertical faded edges used to indicate that more 5099 * content in this view is visible. 5100 * 5101 * @return The size in pixels of the vertical faded edge or 0 if vertical 5102 * faded edges are not enabled for this view. 5103 * @attr ref android.R.styleable#View_fadingEdgeLength 5104 */ 5105 public int getVerticalFadingEdgeLength() { 5106 if (isVerticalFadingEdgeEnabled()) { 5107 ScrollabilityCache cache = mScrollCache; 5108 if (cache != null) { 5109 return cache.fadingEdgeLength; 5110 } 5111 } 5112 return 0; 5113 } 5114 5115 /** 5116 * Set the size of the faded edge used to indicate that more content in this 5117 * view is available. Will not change whether the fading edge is enabled; use 5118 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5119 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5120 * for the vertical or horizontal fading edges. 5121 * 5122 * @param length The size in pixels of the faded edge used to indicate that more 5123 * content in this view is visible. 5124 */ 5125 public void setFadingEdgeLength(int length) { 5126 initScrollCache(); 5127 mScrollCache.fadingEdgeLength = length; 5128 } 5129 5130 /** 5131 * Returns the size of the horizontal faded edges used to indicate that more 5132 * content in this view is visible. 5133 * 5134 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5135 * faded edges are not enabled for this view. 5136 * @attr ref android.R.styleable#View_fadingEdgeLength 5137 */ 5138 public int getHorizontalFadingEdgeLength() { 5139 if (isHorizontalFadingEdgeEnabled()) { 5140 ScrollabilityCache cache = mScrollCache; 5141 if (cache != null) { 5142 return cache.fadingEdgeLength; 5143 } 5144 } 5145 return 0; 5146 } 5147 5148 /** 5149 * Returns the width of the vertical scrollbar. 5150 * 5151 * @return The width in pixels of the vertical scrollbar or 0 if there 5152 * is no vertical scrollbar. 5153 */ 5154 public int getVerticalScrollbarWidth() { 5155 ScrollabilityCache cache = mScrollCache; 5156 if (cache != null) { 5157 ScrollBarDrawable scrollBar = cache.scrollBar; 5158 if (scrollBar != null) { 5159 int size = scrollBar.getSize(true); 5160 if (size <= 0) { 5161 size = cache.scrollBarSize; 5162 } 5163 return size; 5164 } 5165 return 0; 5166 } 5167 return 0; 5168 } 5169 5170 /** 5171 * Returns the height of the horizontal scrollbar. 5172 * 5173 * @return The height in pixels of the horizontal scrollbar or 0 if 5174 * there is no horizontal scrollbar. 5175 */ 5176 protected int getHorizontalScrollbarHeight() { 5177 ScrollabilityCache cache = mScrollCache; 5178 if (cache != null) { 5179 ScrollBarDrawable scrollBar = cache.scrollBar; 5180 if (scrollBar != null) { 5181 int size = scrollBar.getSize(false); 5182 if (size <= 0) { 5183 size = cache.scrollBarSize; 5184 } 5185 return size; 5186 } 5187 return 0; 5188 } 5189 return 0; 5190 } 5191 5192 /** 5193 * <p> 5194 * Initializes the scrollbars from a given set of styled attributes. This 5195 * method should be called by subclasses that need scrollbars and when an 5196 * instance of these subclasses is created programmatically rather than 5197 * being inflated from XML. This method is automatically called when the XML 5198 * is inflated. 5199 * </p> 5200 * 5201 * @param a the styled attributes set to initialize the scrollbars from 5202 * 5203 * @removed 5204 */ 5205 protected void initializeScrollbars(TypedArray a) { 5206 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5207 // using the View filter array which is not available to the SDK. As such, internal 5208 // framework usage now uses initializeScrollbarsInternal and we grab a default 5209 // TypedArray with the right filter instead here. 5210 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5211 5212 initializeScrollbarsInternal(arr); 5213 5214 // We ignored the method parameter. Recycle the one we actually did use. 5215 arr.recycle(); 5216 } 5217 5218 /** 5219 * <p> 5220 * Initializes the scrollbars from a given set of styled attributes. This 5221 * method should be called by subclasses that need scrollbars and when an 5222 * instance of these subclasses is created programmatically rather than 5223 * being inflated from XML. This method is automatically called when the XML 5224 * is inflated. 5225 * </p> 5226 * 5227 * @param a the styled attributes set to initialize the scrollbars from 5228 * @hide 5229 */ 5230 protected void initializeScrollbarsInternal(TypedArray a) { 5231 initScrollCache(); 5232 5233 final ScrollabilityCache scrollabilityCache = mScrollCache; 5234 5235 if (scrollabilityCache.scrollBar == null) { 5236 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5237 scrollabilityCache.scrollBar.setState(getDrawableState()); 5238 scrollabilityCache.scrollBar.setCallback(this); 5239 } 5240 5241 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5242 5243 if (!fadeScrollbars) { 5244 scrollabilityCache.state = ScrollabilityCache.ON; 5245 } 5246 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5247 5248 5249 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5250 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5251 .getScrollBarFadeDuration()); 5252 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5253 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5254 ViewConfiguration.getScrollDefaultDelay()); 5255 5256 5257 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5258 com.android.internal.R.styleable.View_scrollbarSize, 5259 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5260 5261 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5262 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5263 5264 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5265 if (thumb != null) { 5266 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5267 } 5268 5269 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5270 false); 5271 if (alwaysDraw) { 5272 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5273 } 5274 5275 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5276 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5277 5278 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5279 if (thumb != null) { 5280 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5281 } 5282 5283 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5284 false); 5285 if (alwaysDraw) { 5286 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5287 } 5288 5289 // Apply layout direction to the new Drawables if needed 5290 final int layoutDirection = getLayoutDirection(); 5291 if (track != null) { 5292 track.setLayoutDirection(layoutDirection); 5293 } 5294 if (thumb != null) { 5295 thumb.setLayoutDirection(layoutDirection); 5296 } 5297 5298 // Re-apply user/background padding so that scrollbar(s) get added 5299 resolvePadding(); 5300 } 5301 5302 private void initializeScrollIndicatorsInternal() { 5303 // Some day maybe we'll break this into top/left/start/etc. and let the 5304 // client control it. Until then, you can have any scroll indicator you 5305 // want as long as it's a 1dp foreground-colored rectangle. 5306 if (mScrollIndicatorDrawable == null) { 5307 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5308 } 5309 } 5310 5311 /** 5312 * <p> 5313 * Initalizes the scrollability cache if necessary. 5314 * </p> 5315 */ 5316 private void initScrollCache() { 5317 if (mScrollCache == null) { 5318 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5319 } 5320 } 5321 5322 private ScrollabilityCache getScrollCache() { 5323 initScrollCache(); 5324 return mScrollCache; 5325 } 5326 5327 /** 5328 * Set the position of the vertical scroll bar. Should be one of 5329 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5330 * {@link #SCROLLBAR_POSITION_RIGHT}. 5331 * 5332 * @param position Where the vertical scroll bar should be positioned. 5333 */ 5334 public void setVerticalScrollbarPosition(int position) { 5335 if (mVerticalScrollbarPosition != position) { 5336 mVerticalScrollbarPosition = position; 5337 computeOpaqueFlags(); 5338 resolvePadding(); 5339 } 5340 } 5341 5342 /** 5343 * @return The position where the vertical scroll bar will show, if applicable. 5344 * @see #setVerticalScrollbarPosition(int) 5345 */ 5346 public int getVerticalScrollbarPosition() { 5347 return mVerticalScrollbarPosition; 5348 } 5349 5350 boolean isOnScrollbar(float x, float y) { 5351 if (mScrollCache == null) { 5352 return false; 5353 } 5354 x += getScrollX(); 5355 y += getScrollY(); 5356 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5357 final Rect bounds = mScrollCache.mScrollBarBounds; 5358 getVerticalScrollBarBounds(bounds); 5359 if (bounds.contains((int)x, (int)y)) { 5360 return true; 5361 } 5362 } 5363 if (isHorizontalScrollBarEnabled()) { 5364 final Rect bounds = mScrollCache.mScrollBarBounds; 5365 getHorizontalScrollBarBounds(bounds); 5366 if (bounds.contains((int)x, (int)y)) { 5367 return true; 5368 } 5369 } 5370 return false; 5371 } 5372 5373 boolean isOnScrollbarThumb(float x, float y) { 5374 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5375 } 5376 5377 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5378 if (mScrollCache == null) { 5379 return false; 5380 } 5381 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5382 x += getScrollX(); 5383 y += getScrollY(); 5384 final Rect bounds = mScrollCache.mScrollBarBounds; 5385 getVerticalScrollBarBounds(bounds); 5386 final int range = computeVerticalScrollRange(); 5387 final int offset = computeVerticalScrollOffset(); 5388 final int extent = computeVerticalScrollExtent(); 5389 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5390 extent, range); 5391 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5392 extent, range, offset); 5393 final int thumbTop = bounds.top + thumbOffset; 5394 if (x >= bounds.left && x <= bounds.right && y >= thumbTop 5395 && y <= thumbTop + thumbLength) { 5396 return true; 5397 } 5398 } 5399 return false; 5400 } 5401 5402 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5403 if (mScrollCache == null) { 5404 return false; 5405 } 5406 if (isHorizontalScrollBarEnabled()) { 5407 x += getScrollX(); 5408 y += getScrollY(); 5409 final Rect bounds = mScrollCache.mScrollBarBounds; 5410 getHorizontalScrollBarBounds(bounds); 5411 final int range = computeHorizontalScrollRange(); 5412 final int offset = computeHorizontalScrollOffset(); 5413 final int extent = computeHorizontalScrollExtent(); 5414 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5415 extent, range); 5416 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5417 extent, range, offset); 5418 final int thumbLeft = bounds.left + thumbOffset; 5419 if (x >= thumbLeft && x <= thumbLeft + thumbLength && y >= bounds.top 5420 && y <= bounds.bottom) { 5421 return true; 5422 } 5423 } 5424 return false; 5425 } 5426 5427 boolean isDraggingScrollBar() { 5428 return mScrollCache != null 5429 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5430 } 5431 5432 /** 5433 * Sets the state of all scroll indicators. 5434 * <p> 5435 * See {@link #setScrollIndicators(int, int)} for usage information. 5436 * 5437 * @param indicators a bitmask of indicators that should be enabled, or 5438 * {@code 0} to disable all indicators 5439 * @see #setScrollIndicators(int, int) 5440 * @see #getScrollIndicators() 5441 * @attr ref android.R.styleable#View_scrollIndicators 5442 */ 5443 public void setScrollIndicators(@ScrollIndicators int indicators) { 5444 setScrollIndicators(indicators, 5445 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5446 } 5447 5448 /** 5449 * Sets the state of the scroll indicators specified by the mask. To change 5450 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5451 * <p> 5452 * When a scroll indicator is enabled, it will be displayed if the view 5453 * can scroll in the direction of the indicator. 5454 * <p> 5455 * Multiple indicator types may be enabled or disabled by passing the 5456 * logical OR of the desired types. If multiple types are specified, they 5457 * will all be set to the same enabled state. 5458 * <p> 5459 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5460 * 5461 * @param indicators the indicator direction, or the logical OR of multiple 5462 * indicator directions. One or more of: 5463 * <ul> 5464 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5465 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5466 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5467 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5468 * <li>{@link #SCROLL_INDICATOR_START}</li> 5469 * <li>{@link #SCROLL_INDICATOR_END}</li> 5470 * </ul> 5471 * @see #setScrollIndicators(int) 5472 * @see #getScrollIndicators() 5473 * @attr ref android.R.styleable#View_scrollIndicators 5474 */ 5475 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5476 // Shift and sanitize mask. 5477 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5478 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5479 5480 // Shift and mask indicators. 5481 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5482 indicators &= mask; 5483 5484 // Merge with non-masked flags. 5485 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5486 5487 if (mPrivateFlags3 != updatedFlags) { 5488 mPrivateFlags3 = updatedFlags; 5489 5490 if (indicators != 0) { 5491 initializeScrollIndicatorsInternal(); 5492 } 5493 invalidate(); 5494 } 5495 } 5496 5497 /** 5498 * Returns a bitmask representing the enabled scroll indicators. 5499 * <p> 5500 * For example, if the top and left scroll indicators are enabled and all 5501 * other indicators are disabled, the return value will be 5502 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5503 * <p> 5504 * To check whether the bottom scroll indicator is enabled, use the value 5505 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5506 * 5507 * @return a bitmask representing the enabled scroll indicators 5508 */ 5509 @ScrollIndicators 5510 public int getScrollIndicators() { 5511 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5512 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5513 } 5514 5515 ListenerInfo getListenerInfo() { 5516 if (mListenerInfo != null) { 5517 return mListenerInfo; 5518 } 5519 mListenerInfo = new ListenerInfo(); 5520 return mListenerInfo; 5521 } 5522 5523 /** 5524 * Register a callback to be invoked when the scroll X or Y positions of 5525 * this view change. 5526 * <p> 5527 * <b>Note:</b> Some views handle scrolling independently from View and may 5528 * have their own separate listeners for scroll-type events. For example, 5529 * {@link android.widget.ListView ListView} allows clients to register an 5530 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 5531 * to listen for changes in list scroll position. 5532 * 5533 * @param l The listener to notify when the scroll X or Y position changes. 5534 * @see android.view.View#getScrollX() 5535 * @see android.view.View#getScrollY() 5536 */ 5537 public void setOnScrollChangeListener(OnScrollChangeListener l) { 5538 getListenerInfo().mOnScrollChangeListener = l; 5539 } 5540 5541 /** 5542 * Register a callback to be invoked when focus of this view changed. 5543 * 5544 * @param l The callback that will run. 5545 */ 5546 public void setOnFocusChangeListener(OnFocusChangeListener l) { 5547 getListenerInfo().mOnFocusChangeListener = l; 5548 } 5549 5550 /** 5551 * Add a listener that will be called when the bounds of the view change due to 5552 * layout processing. 5553 * 5554 * @param listener The listener that will be called when layout bounds change. 5555 */ 5556 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 5557 ListenerInfo li = getListenerInfo(); 5558 if (li.mOnLayoutChangeListeners == null) { 5559 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 5560 } 5561 if (!li.mOnLayoutChangeListeners.contains(listener)) { 5562 li.mOnLayoutChangeListeners.add(listener); 5563 } 5564 } 5565 5566 /** 5567 * Remove a listener for layout changes. 5568 * 5569 * @param listener The listener for layout bounds change. 5570 */ 5571 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 5572 ListenerInfo li = mListenerInfo; 5573 if (li == null || li.mOnLayoutChangeListeners == null) { 5574 return; 5575 } 5576 li.mOnLayoutChangeListeners.remove(listener); 5577 } 5578 5579 /** 5580 * Add a listener for attach state changes. 5581 * 5582 * This listener will be called whenever this view is attached or detached 5583 * from a window. Remove the listener using 5584 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 5585 * 5586 * @param listener Listener to attach 5587 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 5588 */ 5589 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5590 ListenerInfo li = getListenerInfo(); 5591 if (li.mOnAttachStateChangeListeners == null) { 5592 li.mOnAttachStateChangeListeners 5593 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 5594 } 5595 li.mOnAttachStateChangeListeners.add(listener); 5596 } 5597 5598 /** 5599 * Remove a listener for attach state changes. The listener will receive no further 5600 * notification of window attach/detach events. 5601 * 5602 * @param listener Listener to remove 5603 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 5604 */ 5605 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5606 ListenerInfo li = mListenerInfo; 5607 if (li == null || li.mOnAttachStateChangeListeners == null) { 5608 return; 5609 } 5610 li.mOnAttachStateChangeListeners.remove(listener); 5611 } 5612 5613 /** 5614 * Returns the focus-change callback registered for this view. 5615 * 5616 * @return The callback, or null if one is not registered. 5617 */ 5618 public OnFocusChangeListener getOnFocusChangeListener() { 5619 ListenerInfo li = mListenerInfo; 5620 return li != null ? li.mOnFocusChangeListener : null; 5621 } 5622 5623 /** 5624 * Register a callback to be invoked when this view is clicked. If this view is not 5625 * clickable, it becomes clickable. 5626 * 5627 * @param l The callback that will run 5628 * 5629 * @see #setClickable(boolean) 5630 */ 5631 public void setOnClickListener(@Nullable OnClickListener l) { 5632 if (!isClickable()) { 5633 setClickable(true); 5634 } 5635 getListenerInfo().mOnClickListener = l; 5636 } 5637 5638 /** 5639 * Return whether this view has an attached OnClickListener. Returns 5640 * true if there is a listener, false if there is none. 5641 */ 5642 public boolean hasOnClickListeners() { 5643 ListenerInfo li = mListenerInfo; 5644 return (li != null && li.mOnClickListener != null); 5645 } 5646 5647 /** 5648 * Register a callback to be invoked when this view is clicked and held. If this view is not 5649 * long clickable, it becomes long clickable. 5650 * 5651 * @param l The callback that will run 5652 * 5653 * @see #setLongClickable(boolean) 5654 */ 5655 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 5656 if (!isLongClickable()) { 5657 setLongClickable(true); 5658 } 5659 getListenerInfo().mOnLongClickListener = l; 5660 } 5661 5662 /** 5663 * Register a callback to be invoked when this view is context clicked. If the view is not 5664 * context clickable, it becomes context clickable. 5665 * 5666 * @param l The callback that will run 5667 * @see #setContextClickable(boolean) 5668 */ 5669 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 5670 if (!isContextClickable()) { 5671 setContextClickable(true); 5672 } 5673 getListenerInfo().mOnContextClickListener = l; 5674 } 5675 5676 /** 5677 * Register a callback to be invoked when the context menu for this view is 5678 * being built. If this view is not long clickable, it becomes long clickable. 5679 * 5680 * @param l The callback that will run 5681 * 5682 */ 5683 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 5684 if (!isLongClickable()) { 5685 setLongClickable(true); 5686 } 5687 getListenerInfo().mOnCreateContextMenuListener = l; 5688 } 5689 5690 /** 5691 * Set an observer to collect stats for each frame rendered for this view. 5692 * 5693 * @hide 5694 */ 5695 public void addFrameMetricsListener(Window window, 5696 Window.OnFrameMetricsAvailableListener listener, 5697 Handler handler) { 5698 if (mAttachInfo != null) { 5699 if (mAttachInfo.mThreadedRenderer != null) { 5700 if (mFrameMetricsObservers == null) { 5701 mFrameMetricsObservers = new ArrayList<>(); 5702 } 5703 5704 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5705 handler.getLooper(), listener); 5706 mFrameMetricsObservers.add(fmo); 5707 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 5708 } else { 5709 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5710 } 5711 } else { 5712 if (mFrameMetricsObservers == null) { 5713 mFrameMetricsObservers = new ArrayList<>(); 5714 } 5715 5716 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5717 handler.getLooper(), listener); 5718 mFrameMetricsObservers.add(fmo); 5719 } 5720 } 5721 5722 /** 5723 * Remove observer configured to collect frame stats for this view. 5724 * 5725 * @hide 5726 */ 5727 public void removeFrameMetricsListener( 5728 Window.OnFrameMetricsAvailableListener listener) { 5729 ThreadedRenderer renderer = getThreadedRenderer(); 5730 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 5731 if (fmo == null) { 5732 throw new IllegalArgumentException( 5733 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 5734 } 5735 5736 if (mFrameMetricsObservers != null) { 5737 mFrameMetricsObservers.remove(fmo); 5738 if (renderer != null) { 5739 renderer.removeFrameMetricsObserver(fmo); 5740 } 5741 } 5742 } 5743 5744 private void registerPendingFrameMetricsObservers() { 5745 if (mFrameMetricsObservers != null) { 5746 ThreadedRenderer renderer = getThreadedRenderer(); 5747 if (renderer != null) { 5748 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 5749 renderer.addFrameMetricsObserver(fmo); 5750 } 5751 } else { 5752 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5753 } 5754 } 5755 } 5756 5757 private FrameMetricsObserver findFrameMetricsObserver( 5758 Window.OnFrameMetricsAvailableListener listener) { 5759 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 5760 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 5761 if (observer.mListener == listener) { 5762 return observer; 5763 } 5764 } 5765 5766 return null; 5767 } 5768 5769 /** 5770 * Call this view's OnClickListener, if it is defined. Performs all normal 5771 * actions associated with clicking: reporting accessibility event, playing 5772 * a sound, etc. 5773 * 5774 * @return True there was an assigned OnClickListener that was called, false 5775 * otherwise is returned. 5776 */ 5777 public boolean performClick() { 5778 final boolean result; 5779 final ListenerInfo li = mListenerInfo; 5780 if (li != null && li.mOnClickListener != null) { 5781 playSoundEffect(SoundEffectConstants.CLICK); 5782 li.mOnClickListener.onClick(this); 5783 result = true; 5784 } else { 5785 result = false; 5786 } 5787 5788 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 5789 return result; 5790 } 5791 5792 /** 5793 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 5794 * this only calls the listener, and does not do any associated clicking 5795 * actions like reporting an accessibility event. 5796 * 5797 * @return True there was an assigned OnClickListener that was called, false 5798 * otherwise is returned. 5799 */ 5800 public boolean callOnClick() { 5801 ListenerInfo li = mListenerInfo; 5802 if (li != null && li.mOnClickListener != null) { 5803 li.mOnClickListener.onClick(this); 5804 return true; 5805 } 5806 return false; 5807 } 5808 5809 /** 5810 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5811 * context menu if the OnLongClickListener did not consume the event. 5812 * 5813 * @return {@code true} if one of the above receivers consumed the event, 5814 * {@code false} otherwise 5815 */ 5816 public boolean performLongClick() { 5817 return performLongClickInternal(mLongClickX, mLongClickY); 5818 } 5819 5820 /** 5821 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5822 * context menu if the OnLongClickListener did not consume the event, 5823 * anchoring it to an (x,y) coordinate. 5824 * 5825 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5826 * to disable anchoring 5827 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5828 * to disable anchoring 5829 * @return {@code true} if one of the above receivers consumed the event, 5830 * {@code false} otherwise 5831 */ 5832 public boolean performLongClick(float x, float y) { 5833 mLongClickX = x; 5834 mLongClickY = y; 5835 final boolean handled = performLongClick(); 5836 mLongClickX = Float.NaN; 5837 mLongClickY = Float.NaN; 5838 return handled; 5839 } 5840 5841 /** 5842 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5843 * context menu if the OnLongClickListener did not consume the event, 5844 * optionally anchoring it to an (x,y) coordinate. 5845 * 5846 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5847 * to disable anchoring 5848 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5849 * to disable anchoring 5850 * @return {@code true} if one of the above receivers consumed the event, 5851 * {@code false} otherwise 5852 */ 5853 private boolean performLongClickInternal(float x, float y) { 5854 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 5855 5856 boolean handled = false; 5857 final ListenerInfo li = mListenerInfo; 5858 if (li != null && li.mOnLongClickListener != null) { 5859 handled = li.mOnLongClickListener.onLongClick(View.this); 5860 } 5861 if (!handled) { 5862 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 5863 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 5864 } 5865 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 5866 if (!handled) { 5867 handled = showLongClickTooltip((int) x, (int) y); 5868 } 5869 } 5870 if (handled) { 5871 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 5872 } 5873 return handled; 5874 } 5875 5876 /** 5877 * Call this view's OnContextClickListener, if it is defined. 5878 * 5879 * @param x the x coordinate of the context click 5880 * @param y the y coordinate of the context click 5881 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5882 * otherwise. 5883 */ 5884 public boolean performContextClick(float x, float y) { 5885 return performContextClick(); 5886 } 5887 5888 /** 5889 * Call this view's OnContextClickListener, if it is defined. 5890 * 5891 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5892 * otherwise. 5893 */ 5894 public boolean performContextClick() { 5895 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 5896 5897 boolean handled = false; 5898 ListenerInfo li = mListenerInfo; 5899 if (li != null && li.mOnContextClickListener != null) { 5900 handled = li.mOnContextClickListener.onContextClick(View.this); 5901 } 5902 if (handled) { 5903 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 5904 } 5905 return handled; 5906 } 5907 5908 /** 5909 * Performs button-related actions during a touch down event. 5910 * 5911 * @param event The event. 5912 * @return True if the down was consumed. 5913 * 5914 * @hide 5915 */ 5916 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 5917 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 5918 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 5919 showContextMenu(event.getX(), event.getY()); 5920 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 5921 return true; 5922 } 5923 return false; 5924 } 5925 5926 /** 5927 * Shows the context menu for this view. 5928 * 5929 * @return {@code true} if the context menu was shown, {@code false} 5930 * otherwise 5931 * @see #showContextMenu(float, float) 5932 */ 5933 public boolean showContextMenu() { 5934 return getParent().showContextMenuForChild(this); 5935 } 5936 5937 /** 5938 * Shows the context menu for this view anchored to the specified 5939 * view-relative coordinate. 5940 * 5941 * @param x the X coordinate in pixels relative to the view to which the 5942 * menu should be anchored, or {@link Float#NaN} to disable anchoring 5943 * @param y the Y coordinate in pixels relative to the view to which the 5944 * menu should be anchored, or {@link Float#NaN} to disable anchoring 5945 * @return {@code true} if the context menu was shown, {@code false} 5946 * otherwise 5947 */ 5948 public boolean showContextMenu(float x, float y) { 5949 return getParent().showContextMenuForChild(this, x, y); 5950 } 5951 5952 /** 5953 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 5954 * 5955 * @param callback Callback that will control the lifecycle of the action mode 5956 * @return The new action mode if it is started, null otherwise 5957 * 5958 * @see ActionMode 5959 * @see #startActionMode(android.view.ActionMode.Callback, int) 5960 */ 5961 public ActionMode startActionMode(ActionMode.Callback callback) { 5962 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 5963 } 5964 5965 /** 5966 * Start an action mode with the given type. 5967 * 5968 * @param callback Callback that will control the lifecycle of the action mode 5969 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 5970 * @return The new action mode if it is started, null otherwise 5971 * 5972 * @see ActionMode 5973 */ 5974 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 5975 ViewParent parent = getParent(); 5976 if (parent == null) return null; 5977 try { 5978 return parent.startActionModeForChild(this, callback, type); 5979 } catch (AbstractMethodError ame) { 5980 // Older implementations of custom views might not implement this. 5981 return parent.startActionModeForChild(this, callback); 5982 } 5983 } 5984 5985 /** 5986 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 5987 * Context, creating a unique View identifier to retrieve the result. 5988 * 5989 * @param intent The Intent to be started. 5990 * @param requestCode The request code to use. 5991 * @hide 5992 */ 5993 public void startActivityForResult(Intent intent, int requestCode) { 5994 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 5995 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 5996 } 5997 5998 /** 5999 * If this View corresponds to the calling who, dispatches the activity result. 6000 * @param who The identifier for the targeted View to receive the result. 6001 * @param requestCode The integer request code originally supplied to 6002 * startActivityForResult(), allowing you to identify who this 6003 * result came from. 6004 * @param resultCode The integer result code returned by the child activity 6005 * through its setResult(). 6006 * @param data An Intent, which can return result data to the caller 6007 * (various data can be attached to Intent "extras"). 6008 * @return {@code true} if the activity result was dispatched. 6009 * @hide 6010 */ 6011 public boolean dispatchActivityResult( 6012 String who, int requestCode, int resultCode, Intent data) { 6013 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6014 onActivityResult(requestCode, resultCode, data); 6015 mStartActivityRequestWho = null; 6016 return true; 6017 } 6018 return false; 6019 } 6020 6021 /** 6022 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6023 * 6024 * @param requestCode The integer request code originally supplied to 6025 * startActivityForResult(), allowing you to identify who this 6026 * result came from. 6027 * @param resultCode The integer result code returned by the child activity 6028 * through its setResult(). 6029 * @param data An Intent, which can return result data to the caller 6030 * (various data can be attached to Intent "extras"). 6031 * @hide 6032 */ 6033 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6034 // Do nothing. 6035 } 6036 6037 /** 6038 * Register a callback to be invoked when a hardware key is pressed in this view. 6039 * Key presses in software input methods will generally not trigger the methods of 6040 * this listener. 6041 * @param l the key listener to attach to this view 6042 */ 6043 public void setOnKeyListener(OnKeyListener l) { 6044 getListenerInfo().mOnKeyListener = l; 6045 } 6046 6047 /** 6048 * Register a callback to be invoked when a touch event is sent to this view. 6049 * @param l the touch listener to attach to this view 6050 */ 6051 public void setOnTouchListener(OnTouchListener l) { 6052 getListenerInfo().mOnTouchListener = l; 6053 } 6054 6055 /** 6056 * Register a callback to be invoked when a generic motion event is sent to this view. 6057 * @param l the generic motion listener to attach to this view 6058 */ 6059 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6060 getListenerInfo().mOnGenericMotionListener = l; 6061 } 6062 6063 /** 6064 * Register a callback to be invoked when a hover event is sent to this view. 6065 * @param l the hover listener to attach to this view 6066 */ 6067 public void setOnHoverListener(OnHoverListener l) { 6068 getListenerInfo().mOnHoverListener = l; 6069 } 6070 6071 /** 6072 * Register a drag event listener callback object for this View. The parameter is 6073 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6074 * View, the system calls the 6075 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6076 * @param l An implementation of {@link android.view.View.OnDragListener}. 6077 */ 6078 public void setOnDragListener(OnDragListener l) { 6079 getListenerInfo().mOnDragListener = l; 6080 } 6081 6082 /** 6083 * Give this view focus. This will cause 6084 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6085 * 6086 * Note: this does not check whether this {@link View} should get focus, it just 6087 * gives it focus no matter what. It should only be called internally by framework 6088 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6089 * 6090 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6091 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6092 * focus moved when requestFocus() is called. It may not always 6093 * apply, in which case use the default View.FOCUS_DOWN. 6094 * @param previouslyFocusedRect The rectangle of the view that had focus 6095 * prior in this View's coordinate system. 6096 */ 6097 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6098 if (DBG) { 6099 System.out.println(this + " requestFocus()"); 6100 } 6101 6102 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6103 mPrivateFlags |= PFLAG_FOCUSED; 6104 6105 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6106 6107 if (mParent != null) { 6108 mParent.requestChildFocus(this, this); 6109 } 6110 6111 if (mAttachInfo != null) { 6112 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6113 } 6114 6115 onFocusChanged(true, direction, previouslyFocusedRect); 6116 refreshDrawableState(); 6117 } 6118 } 6119 6120 /** 6121 * Sets this view's preference for reveal behavior when it gains focus. 6122 * 6123 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6124 * this view would prefer to be brought fully into view when it gains focus. 6125 * For example, a text field that a user is meant to type into. Other views such 6126 * as scrolling containers may prefer to opt-out of this behavior.</p> 6127 * 6128 * <p>The default value for views is true, though subclasses may change this 6129 * based on their preferred behavior.</p> 6130 * 6131 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6132 * 6133 * @see #getRevealOnFocusHint() 6134 */ 6135 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6136 if (revealOnFocus) { 6137 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6138 } else { 6139 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6140 } 6141 } 6142 6143 /** 6144 * Returns this view's preference for reveal behavior when it gains focus. 6145 * 6146 * <p>When this method returns true for a child view requesting focus, ancestor 6147 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6148 * should make a best effort to make the newly focused child fully visible to the user. 6149 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6150 * other properties affecting visibility to the user as part of the focus change.</p> 6151 * 6152 * @return true if this view would prefer to become fully visible when it gains focus, 6153 * false if it would prefer not to disrupt scroll positioning 6154 * 6155 * @see #setRevealOnFocusHint(boolean) 6156 */ 6157 public final boolean getRevealOnFocusHint() { 6158 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6159 } 6160 6161 /** 6162 * Populates <code>outRect</code> with the hotspot bounds. By default, 6163 * the hotspot bounds are identical to the screen bounds. 6164 * 6165 * @param outRect rect to populate with hotspot bounds 6166 * @hide Only for internal use by views and widgets. 6167 */ 6168 public void getHotspotBounds(Rect outRect) { 6169 final Drawable background = getBackground(); 6170 if (background != null) { 6171 background.getHotspotBounds(outRect); 6172 } else { 6173 getBoundsOnScreen(outRect); 6174 } 6175 } 6176 6177 /** 6178 * Request that a rectangle of this view be visible on the screen, 6179 * scrolling if necessary just enough. 6180 * 6181 * <p>A View should call this if it maintains some notion of which part 6182 * of its content is interesting. For example, a text editing view 6183 * should call this when its cursor moves. 6184 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6185 * It should not be affected by which part of the View is currently visible or its scroll 6186 * position. 6187 * 6188 * @param rectangle The rectangle in the View's content coordinate space 6189 * @return Whether any parent scrolled. 6190 */ 6191 public boolean requestRectangleOnScreen(Rect rectangle) { 6192 return requestRectangleOnScreen(rectangle, false); 6193 } 6194 6195 /** 6196 * Request that a rectangle of this view be visible on the screen, 6197 * scrolling if necessary just enough. 6198 * 6199 * <p>A View should call this if it maintains some notion of which part 6200 * of its content is interesting. For example, a text editing view 6201 * should call this when its cursor moves. 6202 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6203 * It should not be affected by which part of the View is currently visible or its scroll 6204 * position. 6205 * <p>When <code>immediate</code> is set to true, scrolling will not be 6206 * animated. 6207 * 6208 * @param rectangle The rectangle in the View's content coordinate space 6209 * @param immediate True to forbid animated scrolling, false otherwise 6210 * @return Whether any parent scrolled. 6211 */ 6212 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6213 if (mParent == null) { 6214 return false; 6215 } 6216 6217 View child = this; 6218 6219 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6220 position.set(rectangle); 6221 6222 ViewParent parent = mParent; 6223 boolean scrolled = false; 6224 while (parent != null) { 6225 rectangle.set((int) position.left, (int) position.top, 6226 (int) position.right, (int) position.bottom); 6227 6228 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6229 6230 if (!(parent instanceof View)) { 6231 break; 6232 } 6233 6234 // move it from child's content coordinate space to parent's content coordinate space 6235 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6236 6237 child = (View) parent; 6238 parent = child.getParent(); 6239 } 6240 6241 return scrolled; 6242 } 6243 6244 /** 6245 * Called when this view wants to give up focus. If focus is cleared 6246 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6247 * <p> 6248 * <strong>Note:</strong> When a View clears focus the framework is trying 6249 * to give focus to the first focusable View from the top. Hence, if this 6250 * View is the first from the top that can take focus, then all callbacks 6251 * related to clearing focus will be invoked after which the framework will 6252 * give focus to this view. 6253 * </p> 6254 */ 6255 public void clearFocus() { 6256 if (DBG) { 6257 System.out.println(this + " clearFocus()"); 6258 } 6259 6260 clearFocusInternal(null, true, true); 6261 } 6262 6263 /** 6264 * Clears focus from the view, optionally propagating the change up through 6265 * the parent hierarchy and requesting that the root view place new focus. 6266 * 6267 * @param propagate whether to propagate the change up through the parent 6268 * hierarchy 6269 * @param refocus when propagate is true, specifies whether to request the 6270 * root view place new focus 6271 */ 6272 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6273 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6274 mPrivateFlags &= ~PFLAG_FOCUSED; 6275 6276 if (propagate && mParent != null) { 6277 mParent.clearChildFocus(this); 6278 } 6279 6280 onFocusChanged(false, 0, null); 6281 refreshDrawableState(); 6282 6283 if (propagate && (!refocus || !rootViewRequestFocus())) { 6284 notifyGlobalFocusCleared(this); 6285 } 6286 } 6287 } 6288 6289 void notifyGlobalFocusCleared(View oldFocus) { 6290 if (oldFocus != null && mAttachInfo != null) { 6291 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6292 } 6293 } 6294 6295 boolean rootViewRequestFocus() { 6296 final View root = getRootView(); 6297 return root != null && root.requestFocus(); 6298 } 6299 6300 /** 6301 * Called internally by the view system when a new view is getting focus. 6302 * This is what clears the old focus. 6303 * <p> 6304 * <b>NOTE:</b> The parent view's focused child must be updated manually 6305 * after calling this method. Otherwise, the view hierarchy may be left in 6306 * an inconstent state. 6307 */ 6308 void unFocus(View focused) { 6309 if (DBG) { 6310 System.out.println(this + " unFocus()"); 6311 } 6312 6313 clearFocusInternal(focused, false, false); 6314 } 6315 6316 /** 6317 * Returns true if this view has focus itself, or is the ancestor of the 6318 * view that has focus. 6319 * 6320 * @return True if this view has or contains focus, false otherwise. 6321 */ 6322 @ViewDebug.ExportedProperty(category = "focus") 6323 public boolean hasFocus() { 6324 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6325 } 6326 6327 /** 6328 * Returns true if this view is focusable or if it contains a reachable View 6329 * for which {@link #hasFocusable()} returns true. A "reachable hasFocusable()" 6330 * is a View whose parents do not block descendants focus. 6331 * 6332 * Only {@link #VISIBLE} views are considered focusable. 6333 * 6334 * @return True if the view is focusable or if the view contains a focusable 6335 * View, false otherwise. 6336 * 6337 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6338 * @see ViewGroup#getTouchscreenBlocksFocus() 6339 */ 6340 public boolean hasFocusable() { 6341 if (!isFocusableInTouchMode()) { 6342 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6343 final ViewGroup g = (ViewGroup) p; 6344 if (g.shouldBlockFocusForTouchscreen()) { 6345 return false; 6346 } 6347 } 6348 } 6349 return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable(); 6350 } 6351 6352 /** 6353 * Called by the view system when the focus state of this view changes. 6354 * When the focus change event is caused by directional navigation, direction 6355 * and previouslyFocusedRect provide insight into where the focus is coming from. 6356 * When overriding, be sure to call up through to the super class so that 6357 * the standard focus handling will occur. 6358 * 6359 * @param gainFocus True if the View has focus; false otherwise. 6360 * @param direction The direction focus has moved when requestFocus() 6361 * is called to give this view focus. Values are 6362 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6363 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6364 * It may not always apply, in which case use the default. 6365 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6366 * system, of the previously focused view. If applicable, this will be 6367 * passed in as finer grained information about where the focus is coming 6368 * from (in addition to direction). Will be <code>null</code> otherwise. 6369 */ 6370 @CallSuper 6371 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6372 @Nullable Rect previouslyFocusedRect) { 6373 if (gainFocus) { 6374 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6375 } else { 6376 notifyViewAccessibilityStateChangedIfNeeded( 6377 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6378 } 6379 6380 InputMethodManager imm = InputMethodManager.peekInstance(); 6381 if (!gainFocus) { 6382 if (isPressed()) { 6383 setPressed(false); 6384 } 6385 if (imm != null && mAttachInfo != null 6386 && mAttachInfo.mHasWindowFocus) { 6387 imm.focusOut(this); 6388 } 6389 onFocusLost(); 6390 } else if (imm != null && mAttachInfo != null 6391 && mAttachInfo.mHasWindowFocus) { 6392 imm.focusIn(this); 6393 } 6394 6395 invalidate(true); 6396 ListenerInfo li = mListenerInfo; 6397 if (li != null && li.mOnFocusChangeListener != null) { 6398 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6399 } 6400 6401 if (mAttachInfo != null) { 6402 mAttachInfo.mKeyDispatchState.reset(this); 6403 } 6404 } 6405 6406 /** 6407 * Sends an accessibility event of the given type. If accessibility is 6408 * not enabled this method has no effect. The default implementation calls 6409 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6410 * to populate information about the event source (this View), then calls 6411 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6412 * populate the text content of the event source including its descendants, 6413 * and last calls 6414 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6415 * on its parent to request sending of the event to interested parties. 6416 * <p> 6417 * If an {@link AccessibilityDelegate} has been specified via calling 6418 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6419 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6420 * responsible for handling this call. 6421 * </p> 6422 * 6423 * @param eventType The type of the event to send, as defined by several types from 6424 * {@link android.view.accessibility.AccessibilityEvent}, such as 6425 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6426 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6427 * 6428 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6429 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6430 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6431 * @see AccessibilityDelegate 6432 */ 6433 public void sendAccessibilityEvent(int eventType) { 6434 if (mAccessibilityDelegate != null) { 6435 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6436 } else { 6437 sendAccessibilityEventInternal(eventType); 6438 } 6439 } 6440 6441 /** 6442 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6443 * {@link AccessibilityEvent} to make an announcement which is related to some 6444 * sort of a context change for which none of the events representing UI transitions 6445 * is a good fit. For example, announcing a new page in a book. If accessibility 6446 * is not enabled this method does nothing. 6447 * 6448 * @param text The announcement text. 6449 */ 6450 public void announceForAccessibility(CharSequence text) { 6451 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6452 AccessibilityEvent event = AccessibilityEvent.obtain( 6453 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6454 onInitializeAccessibilityEvent(event); 6455 event.getText().add(text); 6456 event.setContentDescription(null); 6457 mParent.requestSendAccessibilityEvent(this, event); 6458 } 6459 } 6460 6461 /** 6462 * @see #sendAccessibilityEvent(int) 6463 * 6464 * Note: Called from the default {@link AccessibilityDelegate}. 6465 * 6466 * @hide 6467 */ 6468 public void sendAccessibilityEventInternal(int eventType) { 6469 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 6470 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 6471 } 6472 } 6473 6474 /** 6475 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 6476 * takes as an argument an empty {@link AccessibilityEvent} and does not 6477 * perform a check whether accessibility is enabled. 6478 * <p> 6479 * If an {@link AccessibilityDelegate} has been specified via calling 6480 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6481 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 6482 * is responsible for handling this call. 6483 * </p> 6484 * 6485 * @param event The event to send. 6486 * 6487 * @see #sendAccessibilityEvent(int) 6488 */ 6489 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 6490 if (mAccessibilityDelegate != null) { 6491 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 6492 } else { 6493 sendAccessibilityEventUncheckedInternal(event); 6494 } 6495 } 6496 6497 /** 6498 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 6499 * 6500 * Note: Called from the default {@link AccessibilityDelegate}. 6501 * 6502 * @hide 6503 */ 6504 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 6505 if (!isShown()) { 6506 return; 6507 } 6508 onInitializeAccessibilityEvent(event); 6509 // Only a subset of accessibility events populates text content. 6510 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 6511 dispatchPopulateAccessibilityEvent(event); 6512 } 6513 // In the beginning we called #isShown(), so we know that getParent() is not null. 6514 getParent().requestSendAccessibilityEvent(this, event); 6515 } 6516 6517 /** 6518 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 6519 * to its children for adding their text content to the event. Note that the 6520 * event text is populated in a separate dispatch path since we add to the 6521 * event not only the text of the source but also the text of all its descendants. 6522 * A typical implementation will call 6523 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 6524 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6525 * on each child. Override this method if custom population of the event text 6526 * content is required. 6527 * <p> 6528 * If an {@link AccessibilityDelegate} has been specified via calling 6529 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6530 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 6531 * is responsible for handling this call. 6532 * </p> 6533 * <p> 6534 * <em>Note:</em> Accessibility events of certain types are not dispatched for 6535 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 6536 * </p> 6537 * 6538 * @param event The event. 6539 * 6540 * @return True if the event population was completed. 6541 */ 6542 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 6543 if (mAccessibilityDelegate != null) { 6544 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 6545 } else { 6546 return dispatchPopulateAccessibilityEventInternal(event); 6547 } 6548 } 6549 6550 /** 6551 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6552 * 6553 * Note: Called from the default {@link AccessibilityDelegate}. 6554 * 6555 * @hide 6556 */ 6557 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6558 onPopulateAccessibilityEvent(event); 6559 return false; 6560 } 6561 6562 /** 6563 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6564 * giving a chance to this View to populate the accessibility event with its 6565 * text content. While this method is free to modify event 6566 * attributes other than text content, doing so should normally be performed in 6567 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 6568 * <p> 6569 * Example: Adding formatted date string to an accessibility event in addition 6570 * to the text added by the super implementation: 6571 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6572 * super.onPopulateAccessibilityEvent(event); 6573 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 6574 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 6575 * mCurrentDate.getTimeInMillis(), flags); 6576 * event.getText().add(selectedDateUtterance); 6577 * }</pre> 6578 * <p> 6579 * If an {@link AccessibilityDelegate} has been specified via calling 6580 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6581 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 6582 * is responsible for handling this call. 6583 * </p> 6584 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6585 * information to the event, in case the default implementation has basic information to add. 6586 * </p> 6587 * 6588 * @param event The accessibility event which to populate. 6589 * 6590 * @see #sendAccessibilityEvent(int) 6591 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6592 */ 6593 @CallSuper 6594 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6595 if (mAccessibilityDelegate != null) { 6596 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 6597 } else { 6598 onPopulateAccessibilityEventInternal(event); 6599 } 6600 } 6601 6602 /** 6603 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 6604 * 6605 * Note: Called from the default {@link AccessibilityDelegate}. 6606 * 6607 * @hide 6608 */ 6609 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6610 } 6611 6612 /** 6613 * Initializes an {@link AccessibilityEvent} with information about 6614 * this View which is the event source. In other words, the source of 6615 * an accessibility event is the view whose state change triggered firing 6616 * the event. 6617 * <p> 6618 * Example: Setting the password property of an event in addition 6619 * to properties set by the super implementation: 6620 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6621 * super.onInitializeAccessibilityEvent(event); 6622 * event.setPassword(true); 6623 * }</pre> 6624 * <p> 6625 * If an {@link AccessibilityDelegate} has been specified via calling 6626 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6627 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 6628 * is responsible for handling this call. 6629 * </p> 6630 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6631 * information to the event, in case the default implementation has basic information to add. 6632 * </p> 6633 * @param event The event to initialize. 6634 * 6635 * @see #sendAccessibilityEvent(int) 6636 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6637 */ 6638 @CallSuper 6639 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6640 if (mAccessibilityDelegate != null) { 6641 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 6642 } else { 6643 onInitializeAccessibilityEventInternal(event); 6644 } 6645 } 6646 6647 /** 6648 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6649 * 6650 * Note: Called from the default {@link AccessibilityDelegate}. 6651 * 6652 * @hide 6653 */ 6654 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 6655 event.setSource(this); 6656 event.setClassName(getAccessibilityClassName()); 6657 event.setPackageName(getContext().getPackageName()); 6658 event.setEnabled(isEnabled()); 6659 event.setContentDescription(mContentDescription); 6660 6661 switch (event.getEventType()) { 6662 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 6663 ArrayList<View> focusablesTempList = (mAttachInfo != null) 6664 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 6665 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 6666 event.setItemCount(focusablesTempList.size()); 6667 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 6668 if (mAttachInfo != null) { 6669 focusablesTempList.clear(); 6670 } 6671 } break; 6672 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 6673 CharSequence text = getIterableTextForAccessibility(); 6674 if (text != null && text.length() > 0) { 6675 event.setFromIndex(getAccessibilitySelectionStart()); 6676 event.setToIndex(getAccessibilitySelectionEnd()); 6677 event.setItemCount(text.length()); 6678 } 6679 } break; 6680 } 6681 } 6682 6683 /** 6684 * Returns an {@link AccessibilityNodeInfo} representing this view from the 6685 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 6686 * This method is responsible for obtaining an accessibility node info from a 6687 * pool of reusable instances and calling 6688 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 6689 * initialize the former. 6690 * <p> 6691 * Note: The client is responsible for recycling the obtained instance by calling 6692 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 6693 * </p> 6694 * 6695 * @return A populated {@link AccessibilityNodeInfo}. 6696 * 6697 * @see AccessibilityNodeInfo 6698 */ 6699 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 6700 if (mAccessibilityDelegate != null) { 6701 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 6702 } else { 6703 return createAccessibilityNodeInfoInternal(); 6704 } 6705 } 6706 6707 /** 6708 * @see #createAccessibilityNodeInfo() 6709 * 6710 * @hide 6711 */ 6712 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 6713 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 6714 if (provider != null) { 6715 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 6716 } else { 6717 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 6718 onInitializeAccessibilityNodeInfo(info); 6719 return info; 6720 } 6721 } 6722 6723 /** 6724 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 6725 * The base implementation sets: 6726 * <ul> 6727 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 6728 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 6729 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 6730 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 6731 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 6732 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 6733 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 6734 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 6735 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 6736 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 6737 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 6738 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 6739 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 6740 * </ul> 6741 * <p> 6742 * Subclasses should override this method, call the super implementation, 6743 * and set additional attributes. 6744 * </p> 6745 * <p> 6746 * If an {@link AccessibilityDelegate} has been specified via calling 6747 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6748 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 6749 * is responsible for handling this call. 6750 * </p> 6751 * 6752 * @param info The instance to initialize. 6753 */ 6754 @CallSuper 6755 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 6756 if (mAccessibilityDelegate != null) { 6757 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 6758 } else { 6759 onInitializeAccessibilityNodeInfoInternal(info); 6760 } 6761 } 6762 6763 /** 6764 * Gets the location of this view in screen coordinates. 6765 * 6766 * @param outRect The output location 6767 * @hide 6768 */ 6769 public void getBoundsOnScreen(Rect outRect) { 6770 getBoundsOnScreen(outRect, false); 6771 } 6772 6773 /** 6774 * Gets the location of this view in screen coordinates. 6775 * 6776 * @param outRect The output location 6777 * @param clipToParent Whether to clip child bounds to the parent ones. 6778 * @hide 6779 */ 6780 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 6781 if (mAttachInfo == null) { 6782 return; 6783 } 6784 6785 RectF position = mAttachInfo.mTmpTransformRect; 6786 position.set(0, 0, mRight - mLeft, mBottom - mTop); 6787 6788 if (!hasIdentityMatrix()) { 6789 getMatrix().mapRect(position); 6790 } 6791 6792 position.offset(mLeft, mTop); 6793 6794 ViewParent parent = mParent; 6795 while (parent instanceof View) { 6796 View parentView = (View) parent; 6797 6798 position.offset(-parentView.mScrollX, -parentView.mScrollY); 6799 6800 if (clipToParent) { 6801 position.left = Math.max(position.left, 0); 6802 position.top = Math.max(position.top, 0); 6803 position.right = Math.min(position.right, parentView.getWidth()); 6804 position.bottom = Math.min(position.bottom, parentView.getHeight()); 6805 } 6806 6807 if (!parentView.hasIdentityMatrix()) { 6808 parentView.getMatrix().mapRect(position); 6809 } 6810 6811 position.offset(parentView.mLeft, parentView.mTop); 6812 6813 parent = parentView.mParent; 6814 } 6815 6816 if (parent instanceof ViewRootImpl) { 6817 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 6818 position.offset(0, -viewRootImpl.mCurScrollY); 6819 } 6820 6821 position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 6822 6823 outRect.set(Math.round(position.left), Math.round(position.top), 6824 Math.round(position.right), Math.round(position.bottom)); 6825 } 6826 6827 /** 6828 * Return the class name of this object to be used for accessibility purposes. 6829 * Subclasses should only override this if they are implementing something that 6830 * should be seen as a completely new class of view when used by accessibility, 6831 * unrelated to the class it is deriving from. This is used to fill in 6832 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 6833 */ 6834 public CharSequence getAccessibilityClassName() { 6835 return View.class.getName(); 6836 } 6837 6838 /** 6839 * Called when assist structure is being retrieved from a view as part of 6840 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 6841 * @param structure Fill in with structured view data. The default implementation 6842 * fills in all data that can be inferred from the view itself. 6843 * 6844 * @deprecated As of API O sub-classes should override 6845 * {@link #onProvideStructure(ViewStructure, int)} instead. 6846 */ 6847 // TODO(b/33197203): set proper API above 6848 @Deprecated 6849 public void onProvideStructure(ViewStructure structure) { 6850 onProvideStructure(structure, 0); 6851 } 6852 6853 /** 6854 * Called when assist structure is being retrieved from a view as part of 6855 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} or as part 6856 * of an auto-fill request. 6857 * 6858 * <p>The default implementation fills in all data that can be inferred from the view itself. 6859 * 6860 * <p>The structure must be filled according to the request type, which is set in the 6861 * {@code flags} parameter - see the documentation on each flag for more details. 6862 * 6863 * @param structure Fill in with structured view data. The default implementation 6864 * fills in all data that can be inferred from the view itself. 6865 * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and 6866 * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info). 6867 */ 6868 public void onProvideStructure(ViewStructure structure, int flags) { 6869 boolean forAutoFill = (flags 6870 & (View.ASSIST_FLAG_SANITIZED_TEXT 6871 | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0; 6872 final int id = mID; 6873 if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0 6874 && (id&0x0000ffff) != 0) { 6875 String pkg, type, entry; 6876 try { 6877 final Resources res = getResources(); 6878 entry = res.getResourceEntryName(id); 6879 type = res.getResourceTypeName(id); 6880 pkg = res.getResourcePackageName(id); 6881 } catch (Resources.NotFoundException e) { 6882 entry = type = pkg = null; 6883 } 6884 structure.setId(id, pkg, type, entry); 6885 } else { 6886 structure.setId(id, null, null, null); 6887 } 6888 6889 if (forAutoFill) { 6890 // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to 6891 // reuse the accessibility id to save space. 6892 structure.setAutoFillId(getAccessibilityViewId()); 6893 } 6894 6895 structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop); 6896 if (!hasIdentityMatrix()) { 6897 structure.setTransformation(getMatrix()); 6898 } 6899 structure.setElevation(getZ()); 6900 structure.setVisibility(getVisibility()); 6901 structure.setEnabled(isEnabled()); 6902 if (isClickable()) { 6903 structure.setClickable(true); 6904 } 6905 if (isFocusable()) { 6906 structure.setFocusable(true); 6907 } 6908 if (isFocused()) { 6909 structure.setFocused(true); 6910 } 6911 if (isAccessibilityFocused()) { 6912 structure.setAccessibilityFocused(true); 6913 } 6914 if (isSelected()) { 6915 structure.setSelected(true); 6916 } 6917 if (isActivated()) { 6918 structure.setActivated(true); 6919 } 6920 if (isLongClickable()) { 6921 structure.setLongClickable(true); 6922 } 6923 if (this instanceof Checkable) { 6924 structure.setCheckable(true); 6925 if (((Checkable)this).isChecked()) { 6926 structure.setChecked(true); 6927 } 6928 } 6929 if (isContextClickable()) { 6930 structure.setContextClickable(true); 6931 } 6932 structure.setClassName(getAccessibilityClassName().toString()); 6933 structure.setContentDescription(getContentDescription()); 6934 } 6935 6936 /** 6937 * Called when assist structure is being retrieved from a view as part of 6938 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 6939 * generate additional virtual structure under this view. The defaullt implementation 6940 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 6941 * view's virtual accessibility nodes, if any. You can override this for a more 6942 * optimal implementation providing this data. 6943 * 6944 * @deprecated As of API O, sub-classes should override 6945 * {@link #onProvideVirtualStructure(ViewStructure, int)} instead. 6946 */ 6947 // TODO(b/33197203): set proper API above 6948 @Deprecated 6949 public void onProvideVirtualStructure(ViewStructure structure) { 6950 onProvideVirtualStructure(structure, 0); 6951 } 6952 6953 /** 6954 * Called when assist structure is being retrieved from a view as part of 6955 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} or as part 6956 * of an auto-fill request to generate additional virtual structure under this view. 6957 * 6958 * <p>The defaullt implementation uses {@link #getAccessibilityNodeProvider()} to try to 6959 * generate this from the view's virtual accessibility nodes, if any. You can override this 6960 * for a more optimal implementation providing this data. 6961 * 6962 * <p>The structure must be filled according to the request type, which is set in the 6963 * {@code flags} parameter - see the documentation on each flag for more details. 6964 * 6965 * @param structure Fill in with structured view data. 6966 * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and 6967 * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info). 6968 */ 6969 public void onProvideVirtualStructure(ViewStructure structure, int flags) { 6970 boolean sanitize = (flags & View.ASSIST_FLAG_SANITIZED_TEXT) != 0; 6971 6972 if (sanitize) { 6973 // TODO(b/33197203): change populateVirtualStructure so it sanitizes data in this case. 6974 return; 6975 } 6976 6977 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 6978 if (provider != null) { 6979 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 6980 structure.setChildCount(1); 6981 ViewStructure root = structure.newChild(0); 6982 populateVirtualStructure(root, provider, info, flags); 6983 info.recycle(); 6984 } 6985 } 6986 6987 private void populateVirtualStructure(ViewStructure structure, 6988 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, int flags) { 6989 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 6990 null, null, null); 6991 Rect rect = structure.getTempRect(); 6992 info.getBoundsInParent(rect); 6993 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 6994 structure.setVisibility(VISIBLE); 6995 structure.setEnabled(info.isEnabled()); 6996 if (info.isClickable()) { 6997 structure.setClickable(true); 6998 } 6999 if (info.isFocusable()) { 7000 structure.setFocusable(true); 7001 } 7002 if (info.isFocused()) { 7003 structure.setFocused(true); 7004 } 7005 if (info.isAccessibilityFocused()) { 7006 structure.setAccessibilityFocused(true); 7007 } 7008 if (info.isSelected()) { 7009 structure.setSelected(true); 7010 } 7011 if (info.isLongClickable()) { 7012 structure.setLongClickable(true); 7013 } 7014 if (info.isCheckable()) { 7015 structure.setCheckable(true); 7016 if (info.isChecked()) { 7017 structure.setChecked(true); 7018 } 7019 } 7020 if (info.isContextClickable()) { 7021 structure.setContextClickable(true); 7022 } 7023 CharSequence cname = info.getClassName(); 7024 structure.setClassName(cname != null ? cname.toString() : null); 7025 structure.setContentDescription(info.getContentDescription()); 7026 if (info.getText() != null || info.getError() != null) { 7027 structure.setText(info.getText(), info.getTextSelectionStart(), 7028 info.getTextSelectionEnd()); 7029 } 7030 final int NCHILDREN = info.getChildCount(); 7031 if (NCHILDREN > 0) { 7032 structure.setChildCount(NCHILDREN); 7033 for (int i=0; i<NCHILDREN; i++) { 7034 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 7035 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 7036 ViewStructure child = structure.newChild(i); 7037 populateVirtualStructure(child, provider, cinfo, flags); 7038 cinfo.recycle(); 7039 } 7040 } 7041 } 7042 7043 /** 7044 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 7045 * implementation calls {@link #onProvideStructure} and 7046 * {@link #onProvideVirtualStructure}. 7047 * 7048 * @deprecated As of API O, sub-classes should override 7049 * {@link #dispatchProvideStructure(ViewStructure, int)} instead. 7050 */ 7051 // TODO(b/33197203): set proper API above 7052 @Deprecated 7053 public void dispatchProvideStructure(ViewStructure structure) { 7054 dispatchProvideStructure(structure, 0); 7055 } 7056 7057 /** 7058 * Dispatch creation of {@link ViewStructure} down the hierarchy. 7059 * 7060 * <p>The structure must be filled according to the request type, which is set in the 7061 * {@code flags} parameter - see the documentation on each flag for more details. 7062 * 7063 * <p>The default implementation calls {@link #onProvideStructure(ViewStructure, int)} and 7064 * {@link #onProvideVirtualStructure(ViewStructure, int)}. 7065 * 7066 * @param structure Fill in with structured view data. 7067 * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and 7068 * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info). 7069 */ 7070 public void dispatchProvideStructure(ViewStructure structure, int flags) { 7071 boolean forAutoFill = (flags 7072 & (View.ASSIST_FLAG_SANITIZED_TEXT 7073 | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0; 7074 7075 boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked(); 7076 if (!blocked) { 7077 onProvideStructure(structure, flags); 7078 onProvideVirtualStructure(structure, flags); 7079 } else { 7080 structure.setClassName(getAccessibilityClassName().toString()); 7081 structure.setAssistBlocked(true); 7082 } 7083 } 7084 7085 /** 7086 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 7087 * 7088 * Note: Called from the default {@link AccessibilityDelegate}. 7089 * 7090 * @hide 7091 */ 7092 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 7093 if (mAttachInfo == null) { 7094 return; 7095 } 7096 7097 Rect bounds = mAttachInfo.mTmpInvalRect; 7098 7099 getDrawingRect(bounds); 7100 info.setBoundsInParent(bounds); 7101 7102 getBoundsOnScreen(bounds, true); 7103 info.setBoundsInScreen(bounds); 7104 7105 ViewParent parent = getParentForAccessibility(); 7106 if (parent instanceof View) { 7107 info.setParent((View) parent); 7108 } 7109 7110 if (mID != View.NO_ID) { 7111 View rootView = getRootView(); 7112 if (rootView == null) { 7113 rootView = this; 7114 } 7115 7116 View label = rootView.findLabelForView(this, mID); 7117 if (label != null) { 7118 info.setLabeledBy(label); 7119 } 7120 7121 if ((mAttachInfo.mAccessibilityFetchFlags 7122 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 7123 && Resources.resourceHasPackage(mID)) { 7124 try { 7125 String viewId = getResources().getResourceName(mID); 7126 info.setViewIdResourceName(viewId); 7127 } catch (Resources.NotFoundException nfe) { 7128 /* ignore */ 7129 } 7130 } 7131 } 7132 7133 if (mLabelForId != View.NO_ID) { 7134 View rootView = getRootView(); 7135 if (rootView == null) { 7136 rootView = this; 7137 } 7138 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 7139 if (labeled != null) { 7140 info.setLabelFor(labeled); 7141 } 7142 } 7143 7144 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 7145 View rootView = getRootView(); 7146 if (rootView == null) { 7147 rootView = this; 7148 } 7149 View next = rootView.findViewInsideOutShouldExist(this, 7150 mAccessibilityTraversalBeforeId); 7151 if (next != null && next.includeForAccessibility()) { 7152 info.setTraversalBefore(next); 7153 } 7154 } 7155 7156 if (mAccessibilityTraversalAfterId != View.NO_ID) { 7157 View rootView = getRootView(); 7158 if (rootView == null) { 7159 rootView = this; 7160 } 7161 View next = rootView.findViewInsideOutShouldExist(this, 7162 mAccessibilityTraversalAfterId); 7163 if (next != null && next.includeForAccessibility()) { 7164 info.setTraversalAfter(next); 7165 } 7166 } 7167 7168 info.setVisibleToUser(isVisibleToUser()); 7169 7170 info.setImportantForAccessibility(isImportantForAccessibility()); 7171 info.setPackageName(mContext.getPackageName()); 7172 info.setClassName(getAccessibilityClassName()); 7173 info.setContentDescription(getContentDescription()); 7174 7175 info.setEnabled(isEnabled()); 7176 info.setClickable(isClickable()); 7177 info.setFocusable(isFocusable()); 7178 info.setFocused(isFocused()); 7179 info.setAccessibilityFocused(isAccessibilityFocused()); 7180 info.setSelected(isSelected()); 7181 info.setLongClickable(isLongClickable()); 7182 info.setContextClickable(isContextClickable()); 7183 info.setLiveRegion(getAccessibilityLiveRegion()); 7184 7185 // TODO: These make sense only if we are in an AdapterView but all 7186 // views can be selected. Maybe from accessibility perspective 7187 // we should report as selectable view in an AdapterView. 7188 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 7189 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 7190 7191 if (isFocusable()) { 7192 if (isFocused()) { 7193 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 7194 } else { 7195 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 7196 } 7197 } 7198 7199 if (!isAccessibilityFocused()) { 7200 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 7201 } else { 7202 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 7203 } 7204 7205 if (isClickable() && isEnabled()) { 7206 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 7207 } 7208 7209 if (isLongClickable() && isEnabled()) { 7210 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 7211 } 7212 7213 if (isContextClickable() && isEnabled()) { 7214 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 7215 } 7216 7217 CharSequence text = getIterableTextForAccessibility(); 7218 if (text != null && text.length() > 0) { 7219 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 7220 7221 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 7222 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 7223 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 7224 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 7225 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 7226 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 7227 } 7228 7229 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 7230 populateAccessibilityNodeInfoDrawingOrderInParent(info); 7231 } 7232 7233 /** 7234 * Determine the order in which this view will be drawn relative to its siblings for a11y 7235 * 7236 * @param info The info whose drawing order should be populated 7237 */ 7238 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 7239 /* 7240 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 7241 * drawing order may not be well-defined, and some Views with custom drawing order may 7242 * not be initialized sufficiently to respond properly getChildDrawingOrder. 7243 */ 7244 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 7245 info.setDrawingOrder(0); 7246 return; 7247 } 7248 int drawingOrderInParent = 1; 7249 // Iterate up the hierarchy if parents are not important for a11y 7250 View viewAtDrawingLevel = this; 7251 final ViewParent parent = getParentForAccessibility(); 7252 while (viewAtDrawingLevel != parent) { 7253 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 7254 if (!(currentParent instanceof ViewGroup)) { 7255 // Should only happen for the Decor 7256 drawingOrderInParent = 0; 7257 break; 7258 } else { 7259 final ViewGroup parentGroup = (ViewGroup) currentParent; 7260 final int childCount = parentGroup.getChildCount(); 7261 if (childCount > 1) { 7262 List<View> preorderedList = parentGroup.buildOrderedChildList(); 7263 if (preorderedList != null) { 7264 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 7265 for (int i = 0; i < childDrawIndex; i++) { 7266 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 7267 } 7268 } else { 7269 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 7270 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 7271 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 7272 .getChildDrawingOrder(childCount, childIndex) : childIndex; 7273 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 7274 if (childDrawIndex != 0) { 7275 for (int i = 0; i < numChildrenToIterate; i++) { 7276 final int otherDrawIndex = (customOrder ? 7277 parentGroup.getChildDrawingOrder(childCount, i) : i); 7278 if (otherDrawIndex < childDrawIndex) { 7279 drawingOrderInParent += 7280 numViewsForAccessibility(parentGroup.getChildAt(i)); 7281 } 7282 } 7283 } 7284 } 7285 } 7286 } 7287 viewAtDrawingLevel = (View) currentParent; 7288 } 7289 info.setDrawingOrder(drawingOrderInParent); 7290 } 7291 7292 private static int numViewsForAccessibility(View view) { 7293 if (view != null) { 7294 if (view.includeForAccessibility()) { 7295 return 1; 7296 } else if (view instanceof ViewGroup) { 7297 return ((ViewGroup) view).getNumChildrenForAccessibility(); 7298 } 7299 } 7300 return 0; 7301 } 7302 7303 private View findLabelForView(View view, int labeledId) { 7304 if (mMatchLabelForPredicate == null) { 7305 mMatchLabelForPredicate = new MatchLabelForPredicate(); 7306 } 7307 mMatchLabelForPredicate.mLabeledId = labeledId; 7308 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 7309 } 7310 7311 /** 7312 * Computes whether this view is visible to the user. Such a view is 7313 * attached, visible, all its predecessors are visible, it is not clipped 7314 * entirely by its predecessors, and has an alpha greater than zero. 7315 * 7316 * @return Whether the view is visible on the screen. 7317 * 7318 * @hide 7319 */ 7320 protected boolean isVisibleToUser() { 7321 return isVisibleToUser(null); 7322 } 7323 7324 /** 7325 * Computes whether the given portion of this view is visible to the user. 7326 * Such a view is attached, visible, all its predecessors are visible, 7327 * has an alpha greater than zero, and the specified portion is not 7328 * clipped entirely by its predecessors. 7329 * 7330 * @param boundInView the portion of the view to test; coordinates should be relative; may be 7331 * <code>null</code>, and the entire view will be tested in this case. 7332 * When <code>true</code> is returned by the function, the actual visible 7333 * region will be stored in this parameter; that is, if boundInView is fully 7334 * contained within the view, no modification will be made, otherwise regions 7335 * outside of the visible area of the view will be clipped. 7336 * 7337 * @return Whether the specified portion of the view is visible on the screen. 7338 * 7339 * @hide 7340 */ 7341 protected boolean isVisibleToUser(Rect boundInView) { 7342 if (mAttachInfo != null) { 7343 // Attached to invisible window means this view is not visible. 7344 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 7345 return false; 7346 } 7347 // An invisible predecessor or one with alpha zero means 7348 // that this view is not visible to the user. 7349 Object current = this; 7350 while (current instanceof View) { 7351 View view = (View) current; 7352 // We have attach info so this view is attached and there is no 7353 // need to check whether we reach to ViewRootImpl on the way up. 7354 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 7355 view.getVisibility() != VISIBLE) { 7356 return false; 7357 } 7358 current = view.mParent; 7359 } 7360 // Check if the view is entirely covered by its predecessors. 7361 Rect visibleRect = mAttachInfo.mTmpInvalRect; 7362 Point offset = mAttachInfo.mPoint; 7363 if (!getGlobalVisibleRect(visibleRect, offset)) { 7364 return false; 7365 } 7366 // Check if the visible portion intersects the rectangle of interest. 7367 if (boundInView != null) { 7368 visibleRect.offset(-offset.x, -offset.y); 7369 return boundInView.intersect(visibleRect); 7370 } 7371 return true; 7372 } 7373 return false; 7374 } 7375 7376 /** 7377 * Returns the delegate for implementing accessibility support via 7378 * composition. For more details see {@link AccessibilityDelegate}. 7379 * 7380 * @return The delegate, or null if none set. 7381 * 7382 * @hide 7383 */ 7384 public AccessibilityDelegate getAccessibilityDelegate() { 7385 return mAccessibilityDelegate; 7386 } 7387 7388 /** 7389 * Sets a delegate for implementing accessibility support via composition 7390 * (as opposed to inheritance). For more details, see 7391 * {@link AccessibilityDelegate}. 7392 * <p> 7393 * <strong>Note:</strong> On platform versions prior to 7394 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 7395 * views in the {@code android.widget.*} package are called <i>before</i> 7396 * host methods. This prevents certain properties such as class name from 7397 * being modified by overriding 7398 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 7399 * as any changes will be overwritten by the host class. 7400 * <p> 7401 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 7402 * methods are called <i>after</i> host methods, which all properties to be 7403 * modified without being overwritten by the host class. 7404 * 7405 * @param delegate the object to which accessibility method calls should be 7406 * delegated 7407 * @see AccessibilityDelegate 7408 */ 7409 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 7410 mAccessibilityDelegate = delegate; 7411 } 7412 7413 /** 7414 * Gets the provider for managing a virtual view hierarchy rooted at this View 7415 * and reported to {@link android.accessibilityservice.AccessibilityService}s 7416 * that explore the window content. 7417 * <p> 7418 * If this method returns an instance, this instance is responsible for managing 7419 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 7420 * View including the one representing the View itself. Similarly the returned 7421 * instance is responsible for performing accessibility actions on any virtual 7422 * view or the root view itself. 7423 * </p> 7424 * <p> 7425 * If an {@link AccessibilityDelegate} has been specified via calling 7426 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7427 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 7428 * is responsible for handling this call. 7429 * </p> 7430 * 7431 * @return The provider. 7432 * 7433 * @see AccessibilityNodeProvider 7434 */ 7435 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 7436 if (mAccessibilityDelegate != null) { 7437 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 7438 } else { 7439 return null; 7440 } 7441 } 7442 7443 /** 7444 * Gets the unique identifier of this view on the screen for accessibility purposes. 7445 * 7446 * @return The view accessibility id. 7447 * 7448 * @hide 7449 */ 7450 public int getAccessibilityViewId() { 7451 if (mAccessibilityViewId == NO_ID) { 7452 mAccessibilityViewId = sNextAccessibilityViewId++; 7453 } 7454 return mAccessibilityViewId; 7455 } 7456 7457 /** 7458 * Gets the unique identifier of the window in which this View reseides. 7459 * 7460 * @return The window accessibility id. 7461 * 7462 * @hide 7463 */ 7464 public int getAccessibilityWindowId() { 7465 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 7466 : AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 7467 } 7468 7469 /** 7470 * Returns the {@link View}'s content description. 7471 * <p> 7472 * <strong>Note:</strong> Do not override this method, as it will have no 7473 * effect on the content description presented to accessibility services. 7474 * You must call {@link #setContentDescription(CharSequence)} to modify the 7475 * content description. 7476 * 7477 * @return the content description 7478 * @see #setContentDescription(CharSequence) 7479 * @attr ref android.R.styleable#View_contentDescription 7480 */ 7481 @ViewDebug.ExportedProperty(category = "accessibility") 7482 public CharSequence getContentDescription() { 7483 return mContentDescription; 7484 } 7485 7486 /** 7487 * Sets the {@link View}'s content description. 7488 * <p> 7489 * A content description briefly describes the view and is primarily used 7490 * for accessibility support to determine how a view should be presented to 7491 * the user. In the case of a view with no textual representation, such as 7492 * {@link android.widget.ImageButton}, a useful content description 7493 * explains what the view does. For example, an image button with a phone 7494 * icon that is used to place a call may use "Call" as its content 7495 * description. An image of a floppy disk that is used to save a file may 7496 * use "Save". 7497 * 7498 * @param contentDescription The content description. 7499 * @see #getContentDescription() 7500 * @attr ref android.R.styleable#View_contentDescription 7501 */ 7502 @RemotableViewMethod 7503 public void setContentDescription(CharSequence contentDescription) { 7504 if (mContentDescription == null) { 7505 if (contentDescription == null) { 7506 return; 7507 } 7508 } else if (mContentDescription.equals(contentDescription)) { 7509 return; 7510 } 7511 mContentDescription = contentDescription; 7512 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 7513 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 7514 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 7515 notifySubtreeAccessibilityStateChangedIfNeeded(); 7516 } else { 7517 notifyViewAccessibilityStateChangedIfNeeded( 7518 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 7519 } 7520 } 7521 7522 /** 7523 * Sets the id of a view before which this one is visited in accessibility traversal. 7524 * A screen-reader must visit the content of this view before the content of the one 7525 * it precedes. For example, if view B is set to be before view A, then a screen-reader 7526 * will traverse the entire content of B before traversing the entire content of A, 7527 * regardles of what traversal strategy it is using. 7528 * <p> 7529 * Views that do not have specified before/after relationships are traversed in order 7530 * determined by the screen-reader. 7531 * </p> 7532 * <p> 7533 * Setting that this view is before a view that is not important for accessibility 7534 * or if this view is not important for accessibility will have no effect as the 7535 * screen-reader is not aware of unimportant views. 7536 * </p> 7537 * 7538 * @param beforeId The id of a view this one precedes in accessibility traversal. 7539 * 7540 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 7541 * 7542 * @see #setImportantForAccessibility(int) 7543 */ 7544 @RemotableViewMethod 7545 public void setAccessibilityTraversalBefore(int beforeId) { 7546 if (mAccessibilityTraversalBeforeId == beforeId) { 7547 return; 7548 } 7549 mAccessibilityTraversalBeforeId = beforeId; 7550 notifyViewAccessibilityStateChangedIfNeeded( 7551 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7552 } 7553 7554 /** 7555 * Gets the id of a view before which this one is visited in accessibility traversal. 7556 * 7557 * @return The id of a view this one precedes in accessibility traversal if 7558 * specified, otherwise {@link #NO_ID}. 7559 * 7560 * @see #setAccessibilityTraversalBefore(int) 7561 */ 7562 public int getAccessibilityTraversalBefore() { 7563 return mAccessibilityTraversalBeforeId; 7564 } 7565 7566 /** 7567 * Sets the id of a view after which this one is visited in accessibility traversal. 7568 * A screen-reader must visit the content of the other view before the content of this 7569 * one. For example, if view B is set to be after view A, then a screen-reader 7570 * will traverse the entire content of A before traversing the entire content of B, 7571 * regardles of what traversal strategy it is using. 7572 * <p> 7573 * Views that do not have specified before/after relationships are traversed in order 7574 * determined by the screen-reader. 7575 * </p> 7576 * <p> 7577 * Setting that this view is after a view that is not important for accessibility 7578 * or if this view is not important for accessibility will have no effect as the 7579 * screen-reader is not aware of unimportant views. 7580 * </p> 7581 * 7582 * @param afterId The id of a view this one succedees in accessibility traversal. 7583 * 7584 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 7585 * 7586 * @see #setImportantForAccessibility(int) 7587 */ 7588 @RemotableViewMethod 7589 public void setAccessibilityTraversalAfter(int afterId) { 7590 if (mAccessibilityTraversalAfterId == afterId) { 7591 return; 7592 } 7593 mAccessibilityTraversalAfterId = afterId; 7594 notifyViewAccessibilityStateChangedIfNeeded( 7595 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7596 } 7597 7598 /** 7599 * Gets the id of a view after which this one is visited in accessibility traversal. 7600 * 7601 * @return The id of a view this one succeedes in accessibility traversal if 7602 * specified, otherwise {@link #NO_ID}. 7603 * 7604 * @see #setAccessibilityTraversalAfter(int) 7605 */ 7606 public int getAccessibilityTraversalAfter() { 7607 return mAccessibilityTraversalAfterId; 7608 } 7609 7610 /** 7611 * Gets the id of a view for which this view serves as a label for 7612 * accessibility purposes. 7613 * 7614 * @return The labeled view id. 7615 */ 7616 @ViewDebug.ExportedProperty(category = "accessibility") 7617 public int getLabelFor() { 7618 return mLabelForId; 7619 } 7620 7621 /** 7622 * Sets the id of a view for which this view serves as a label for 7623 * accessibility purposes. 7624 * 7625 * @param id The labeled view id. 7626 */ 7627 @RemotableViewMethod 7628 public void setLabelFor(@IdRes int id) { 7629 if (mLabelForId == id) { 7630 return; 7631 } 7632 mLabelForId = id; 7633 if (mLabelForId != View.NO_ID 7634 && mID == View.NO_ID) { 7635 mID = generateViewId(); 7636 } 7637 notifyViewAccessibilityStateChangedIfNeeded( 7638 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7639 } 7640 7641 /** 7642 * Invoked whenever this view loses focus, either by losing window focus or by losing 7643 * focus within its window. This method can be used to clear any state tied to the 7644 * focus. For instance, if a button is held pressed with the trackball and the window 7645 * loses focus, this method can be used to cancel the press. 7646 * 7647 * Subclasses of View overriding this method should always call super.onFocusLost(). 7648 * 7649 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 7650 * @see #onWindowFocusChanged(boolean) 7651 * 7652 * @hide pending API council approval 7653 */ 7654 @CallSuper 7655 protected void onFocusLost() { 7656 resetPressedState(); 7657 } 7658 7659 private void resetPressedState() { 7660 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 7661 return; 7662 } 7663 7664 if (isPressed()) { 7665 setPressed(false); 7666 7667 if (!mHasPerformedLongPress) { 7668 removeLongPressCallback(); 7669 } 7670 } 7671 } 7672 7673 /** 7674 * Returns true if this view has focus 7675 * 7676 * @return True if this view has focus, false otherwise. 7677 */ 7678 @ViewDebug.ExportedProperty(category = "focus") 7679 public boolean isFocused() { 7680 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 7681 } 7682 7683 /** 7684 * Find the view in the hierarchy rooted at this view that currently has 7685 * focus. 7686 * 7687 * @return The view that currently has focus, or null if no focused view can 7688 * be found. 7689 */ 7690 public View findFocus() { 7691 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 7692 } 7693 7694 /** 7695 * Indicates whether this view is one of the set of scrollable containers in 7696 * its window. 7697 * 7698 * @return whether this view is one of the set of scrollable containers in 7699 * its window 7700 * 7701 * @attr ref android.R.styleable#View_isScrollContainer 7702 */ 7703 public boolean isScrollContainer() { 7704 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 7705 } 7706 7707 /** 7708 * Change whether this view is one of the set of scrollable containers in 7709 * its window. This will be used to determine whether the window can 7710 * resize or must pan when a soft input area is open -- scrollable 7711 * containers allow the window to use resize mode since the container 7712 * will appropriately shrink. 7713 * 7714 * @attr ref android.R.styleable#View_isScrollContainer 7715 */ 7716 public void setScrollContainer(boolean isScrollContainer) { 7717 if (isScrollContainer) { 7718 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 7719 mAttachInfo.mScrollContainers.add(this); 7720 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 7721 } 7722 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 7723 } else { 7724 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 7725 mAttachInfo.mScrollContainers.remove(this); 7726 } 7727 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 7728 } 7729 } 7730 7731 /** 7732 * Returns the quality of the drawing cache. 7733 * 7734 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 7735 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 7736 * 7737 * @see #setDrawingCacheQuality(int) 7738 * @see #setDrawingCacheEnabled(boolean) 7739 * @see #isDrawingCacheEnabled() 7740 * 7741 * @attr ref android.R.styleable#View_drawingCacheQuality 7742 */ 7743 @DrawingCacheQuality 7744 public int getDrawingCacheQuality() { 7745 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 7746 } 7747 7748 /** 7749 * Set the drawing cache quality of this view. This value is used only when the 7750 * drawing cache is enabled 7751 * 7752 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 7753 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 7754 * 7755 * @see #getDrawingCacheQuality() 7756 * @see #setDrawingCacheEnabled(boolean) 7757 * @see #isDrawingCacheEnabled() 7758 * 7759 * @attr ref android.R.styleable#View_drawingCacheQuality 7760 */ 7761 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 7762 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 7763 } 7764 7765 /** 7766 * Returns whether the screen should remain on, corresponding to the current 7767 * value of {@link #KEEP_SCREEN_ON}. 7768 * 7769 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 7770 * 7771 * @see #setKeepScreenOn(boolean) 7772 * 7773 * @attr ref android.R.styleable#View_keepScreenOn 7774 */ 7775 public boolean getKeepScreenOn() { 7776 return (mViewFlags & KEEP_SCREEN_ON) != 0; 7777 } 7778 7779 /** 7780 * Controls whether the screen should remain on, modifying the 7781 * value of {@link #KEEP_SCREEN_ON}. 7782 * 7783 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 7784 * 7785 * @see #getKeepScreenOn() 7786 * 7787 * @attr ref android.R.styleable#View_keepScreenOn 7788 */ 7789 public void setKeepScreenOn(boolean keepScreenOn) { 7790 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 7791 } 7792 7793 /** 7794 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 7795 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7796 * 7797 * @attr ref android.R.styleable#View_nextFocusLeft 7798 */ 7799 public int getNextFocusLeftId() { 7800 return mNextFocusLeftId; 7801 } 7802 7803 /** 7804 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 7805 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 7806 * decide automatically. 7807 * 7808 * @attr ref android.R.styleable#View_nextFocusLeft 7809 */ 7810 public void setNextFocusLeftId(int nextFocusLeftId) { 7811 mNextFocusLeftId = nextFocusLeftId; 7812 } 7813 7814 /** 7815 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 7816 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7817 * 7818 * @attr ref android.R.styleable#View_nextFocusRight 7819 */ 7820 public int getNextFocusRightId() { 7821 return mNextFocusRightId; 7822 } 7823 7824 /** 7825 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 7826 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 7827 * decide automatically. 7828 * 7829 * @attr ref android.R.styleable#View_nextFocusRight 7830 */ 7831 public void setNextFocusRightId(int nextFocusRightId) { 7832 mNextFocusRightId = nextFocusRightId; 7833 } 7834 7835 /** 7836 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 7837 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7838 * 7839 * @attr ref android.R.styleable#View_nextFocusUp 7840 */ 7841 public int getNextFocusUpId() { 7842 return mNextFocusUpId; 7843 } 7844 7845 /** 7846 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 7847 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 7848 * decide automatically. 7849 * 7850 * @attr ref android.R.styleable#View_nextFocusUp 7851 */ 7852 public void setNextFocusUpId(int nextFocusUpId) { 7853 mNextFocusUpId = nextFocusUpId; 7854 } 7855 7856 /** 7857 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 7858 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7859 * 7860 * @attr ref android.R.styleable#View_nextFocusDown 7861 */ 7862 public int getNextFocusDownId() { 7863 return mNextFocusDownId; 7864 } 7865 7866 /** 7867 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 7868 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 7869 * decide automatically. 7870 * 7871 * @attr ref android.R.styleable#View_nextFocusDown 7872 */ 7873 public void setNextFocusDownId(int nextFocusDownId) { 7874 mNextFocusDownId = nextFocusDownId; 7875 } 7876 7877 /** 7878 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 7879 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7880 * 7881 * @attr ref android.R.styleable#View_nextFocusForward 7882 */ 7883 public int getNextFocusForwardId() { 7884 return mNextFocusForwardId; 7885 } 7886 7887 /** 7888 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 7889 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 7890 * decide automatically. 7891 * 7892 * @attr ref android.R.styleable#View_nextFocusForward 7893 */ 7894 public void setNextFocusForwardId(int nextFocusForwardId) { 7895 mNextFocusForwardId = nextFocusForwardId; 7896 } 7897 7898 /** 7899 * Gets the id of the root of the next keyboard navigation cluster. 7900 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 7901 * decide automatically. 7902 * 7903 * @attr ref android.R.styleable#View_nextClusterForward 7904 */ 7905 public int getNextClusterForwardId() { 7906 return mNextClusterForwardId; 7907 } 7908 7909 /** 7910 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 7911 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 7912 * decide automatically. 7913 * 7914 * @attr ref android.R.styleable#View_nextClusterForward 7915 */ 7916 public void setNextClusterForwardId(int nextClusterForwardId) { 7917 mNextClusterForwardId = nextClusterForwardId; 7918 } 7919 7920 /** 7921 * Gets the id of the root of the next keyboard navigation section. 7922 * @return The next keyboard navigation section ID, or {@link #NO_ID} if the framework should 7923 * decide automatically. 7924 * 7925 * @attr ref android.R.styleable#View_nextSectionForward 7926 */ 7927 public int getNextSectionForwardId() { 7928 return mNextSectionForwardId; 7929 } 7930 7931 /** 7932 * Sets the id of the view to use as the root of the next keyboard navigation section. 7933 * @param nextSectionForwardId The next section ID, or {@link #NO_ID} if the framework should 7934 * decide automatically. 7935 * 7936 * @attr ref android.R.styleable#View_nextSectionForward 7937 */ 7938 public void setNextSectionForwardId(int nextSectionForwardId) { 7939 mNextSectionForwardId = nextSectionForwardId; 7940 } 7941 7942 /** 7943 * Returns the visibility of this view and all of its ancestors 7944 * 7945 * @return True if this view and all of its ancestors are {@link #VISIBLE} 7946 */ 7947 public boolean isShown() { 7948 View current = this; 7949 //noinspection ConstantConditions 7950 do { 7951 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 7952 return false; 7953 } 7954 ViewParent parent = current.mParent; 7955 if (parent == null) { 7956 return false; // We are not attached to the view root 7957 } 7958 if (!(parent instanceof View)) { 7959 return true; 7960 } 7961 current = (View) parent; 7962 } while (current != null); 7963 7964 return false; 7965 } 7966 7967 /** 7968 * Called by the view hierarchy when the content insets for a window have 7969 * changed, to allow it to adjust its content to fit within those windows. 7970 * The content insets tell you the space that the status bar, input method, 7971 * and other system windows infringe on the application's window. 7972 * 7973 * <p>You do not normally need to deal with this function, since the default 7974 * window decoration given to applications takes care of applying it to the 7975 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 7976 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 7977 * and your content can be placed under those system elements. You can then 7978 * use this method within your view hierarchy if you have parts of your UI 7979 * which you would like to ensure are not being covered. 7980 * 7981 * <p>The default implementation of this method simply applies the content 7982 * insets to the view's padding, consuming that content (modifying the 7983 * insets to be 0), and returning true. This behavior is off by default, but can 7984 * be enabled through {@link #setFitsSystemWindows(boolean)}. 7985 * 7986 * <p>This function's traversal down the hierarchy is depth-first. The same content 7987 * insets object is propagated down the hierarchy, so any changes made to it will 7988 * be seen by all following views (including potentially ones above in 7989 * the hierarchy since this is a depth-first traversal). The first view 7990 * that returns true will abort the entire traversal. 7991 * 7992 * <p>The default implementation works well for a situation where it is 7993 * used with a container that covers the entire window, allowing it to 7994 * apply the appropriate insets to its content on all edges. If you need 7995 * a more complicated layout (such as two different views fitting system 7996 * windows, one on the top of the window, and one on the bottom), 7997 * you can override the method and handle the insets however you would like. 7998 * Note that the insets provided by the framework are always relative to the 7999 * far edges of the window, not accounting for the location of the called view 8000 * within that window. (In fact when this method is called you do not yet know 8001 * where the layout will place the view, as it is done before layout happens.) 8002 * 8003 * <p>Note: unlike many View methods, there is no dispatch phase to this 8004 * call. If you are overriding it in a ViewGroup and want to allow the 8005 * call to continue to your children, you must be sure to call the super 8006 * implementation. 8007 * 8008 * <p>Here is a sample layout that makes use of fitting system windows 8009 * to have controls for a video view placed inside of the window decorations 8010 * that it hides and shows. This can be used with code like the second 8011 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 8012 * 8013 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 8014 * 8015 * @param insets Current content insets of the window. Prior to 8016 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 8017 * the insets or else you and Android will be unhappy. 8018 * 8019 * @return {@code true} if this view applied the insets and it should not 8020 * continue propagating further down the hierarchy, {@code false} otherwise. 8021 * @see #getFitsSystemWindows() 8022 * @see #setFitsSystemWindows(boolean) 8023 * @see #setSystemUiVisibility(int) 8024 * 8025 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 8026 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 8027 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 8028 * to implement handling their own insets. 8029 */ 8030 @Deprecated 8031 protected boolean fitSystemWindows(Rect insets) { 8032 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 8033 if (insets == null) { 8034 // Null insets by definition have already been consumed. 8035 // This call cannot apply insets since there are none to apply, 8036 // so return false. 8037 return false; 8038 } 8039 // If we're not in the process of dispatching the newer apply insets call, 8040 // that means we're not in the compatibility path. Dispatch into the newer 8041 // apply insets path and take things from there. 8042 try { 8043 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 8044 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 8045 } finally { 8046 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 8047 } 8048 } else { 8049 // We're being called from the newer apply insets path. 8050 // Perform the standard fallback behavior. 8051 return fitSystemWindowsInt(insets); 8052 } 8053 } 8054 8055 private boolean fitSystemWindowsInt(Rect insets) { 8056 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 8057 mUserPaddingStart = UNDEFINED_PADDING; 8058 mUserPaddingEnd = UNDEFINED_PADDING; 8059 Rect localInsets = sThreadLocal.get(); 8060 if (localInsets == null) { 8061 localInsets = new Rect(); 8062 sThreadLocal.set(localInsets); 8063 } 8064 boolean res = computeFitSystemWindows(insets, localInsets); 8065 mUserPaddingLeftInitial = localInsets.left; 8066 mUserPaddingRightInitial = localInsets.right; 8067 internalSetPadding(localInsets.left, localInsets.top, 8068 localInsets.right, localInsets.bottom); 8069 return res; 8070 } 8071 return false; 8072 } 8073 8074 /** 8075 * Called when the view should apply {@link WindowInsets} according to its internal policy. 8076 * 8077 * <p>This method should be overridden by views that wish to apply a policy different from or 8078 * in addition to the default behavior. Clients that wish to force a view subtree 8079 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 8080 * 8081 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 8082 * it will be called during dispatch instead of this method. The listener may optionally 8083 * call this method from its own implementation if it wishes to apply the view's default 8084 * insets policy in addition to its own.</p> 8085 * 8086 * <p>Implementations of this method should either return the insets parameter unchanged 8087 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 8088 * that this view applied itself. This allows new inset types added in future platform 8089 * versions to pass through existing implementations unchanged without being erroneously 8090 * consumed.</p> 8091 * 8092 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 8093 * property is set then the view will consume the system window insets and apply them 8094 * as padding for the view.</p> 8095 * 8096 * @param insets Insets to apply 8097 * @return The supplied insets with any applied insets consumed 8098 */ 8099 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 8100 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 8101 // We weren't called from within a direct call to fitSystemWindows, 8102 // call into it as a fallback in case we're in a class that overrides it 8103 // and has logic to perform. 8104 if (fitSystemWindows(insets.getSystemWindowInsets())) { 8105 return insets.consumeSystemWindowInsets(); 8106 } 8107 } else { 8108 // We were called from within a direct call to fitSystemWindows. 8109 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 8110 return insets.consumeSystemWindowInsets(); 8111 } 8112 } 8113 return insets; 8114 } 8115 8116 /** 8117 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 8118 * window insets to this view. The listener's 8119 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 8120 * method will be called instead of the view's 8121 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 8122 * 8123 * @param listener Listener to set 8124 * 8125 * @see #onApplyWindowInsets(WindowInsets) 8126 */ 8127 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 8128 getListenerInfo().mOnApplyWindowInsetsListener = listener; 8129 } 8130 8131 /** 8132 * Request to apply the given window insets to this view or another view in its subtree. 8133 * 8134 * <p>This method should be called by clients wishing to apply insets corresponding to areas 8135 * obscured by window decorations or overlays. This can include the status and navigation bars, 8136 * action bars, input methods and more. New inset categories may be added in the future. 8137 * The method returns the insets provided minus any that were applied by this view or its 8138 * children.</p> 8139 * 8140 * <p>Clients wishing to provide custom behavior should override the 8141 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 8142 * {@link OnApplyWindowInsetsListener} via the 8143 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 8144 * method.</p> 8145 * 8146 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 8147 * </p> 8148 * 8149 * @param insets Insets to apply 8150 * @return The provided insets minus the insets that were consumed 8151 */ 8152 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 8153 try { 8154 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 8155 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 8156 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 8157 } else { 8158 return onApplyWindowInsets(insets); 8159 } 8160 } finally { 8161 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 8162 } 8163 } 8164 8165 /** 8166 * Compute the view's coordinate within the surface. 8167 * 8168 * <p>Computes the coordinates of this view in its surface. The argument 8169 * must be an array of two integers. After the method returns, the array 8170 * contains the x and y location in that order.</p> 8171 * @hide 8172 * @param location an array of two integers in which to hold the coordinates 8173 */ 8174 public void getLocationInSurface(@Size(2) int[] location) { 8175 getLocationInWindow(location); 8176 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 8177 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 8178 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 8179 } 8180 } 8181 8182 /** 8183 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 8184 * only available if the view is attached. 8185 * 8186 * @return WindowInsets from the top of the view hierarchy or null if View is detached 8187 */ 8188 public WindowInsets getRootWindowInsets() { 8189 if (mAttachInfo != null) { 8190 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 8191 } 8192 return null; 8193 } 8194 8195 /** 8196 * @hide Compute the insets that should be consumed by this view and the ones 8197 * that should propagate to those under it. 8198 */ 8199 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 8200 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8201 || mAttachInfo == null 8202 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 8203 && !mAttachInfo.mOverscanRequested)) { 8204 outLocalInsets.set(inoutInsets); 8205 inoutInsets.set(0, 0, 0, 0); 8206 return true; 8207 } else { 8208 // The application wants to take care of fitting system window for 8209 // the content... however we still need to take care of any overscan here. 8210 final Rect overscan = mAttachInfo.mOverscanInsets; 8211 outLocalInsets.set(overscan); 8212 inoutInsets.left -= overscan.left; 8213 inoutInsets.top -= overscan.top; 8214 inoutInsets.right -= overscan.right; 8215 inoutInsets.bottom -= overscan.bottom; 8216 return false; 8217 } 8218 } 8219 8220 /** 8221 * Compute insets that should be consumed by this view and the ones that should propagate 8222 * to those under it. 8223 * 8224 * @param in Insets currently being processed by this View, likely received as a parameter 8225 * to {@link #onApplyWindowInsets(WindowInsets)}. 8226 * @param outLocalInsets A Rect that will receive the insets that should be consumed 8227 * by this view 8228 * @return Insets that should be passed along to views under this one 8229 */ 8230 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 8231 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8232 || mAttachInfo == null 8233 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 8234 outLocalInsets.set(in.getSystemWindowInsets()); 8235 return in.consumeSystemWindowInsets(); 8236 } else { 8237 outLocalInsets.set(0, 0, 0, 0); 8238 return in; 8239 } 8240 } 8241 8242 /** 8243 * Sets whether or not this view should account for system screen decorations 8244 * such as the status bar and inset its content; that is, controlling whether 8245 * the default implementation of {@link #fitSystemWindows(Rect)} will be 8246 * executed. See that method for more details. 8247 * 8248 * <p>Note that if you are providing your own implementation of 8249 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 8250 * flag to true -- your implementation will be overriding the default 8251 * implementation that checks this flag. 8252 * 8253 * @param fitSystemWindows If true, then the default implementation of 8254 * {@link #fitSystemWindows(Rect)} will be executed. 8255 * 8256 * @attr ref android.R.styleable#View_fitsSystemWindows 8257 * @see #getFitsSystemWindows() 8258 * @see #fitSystemWindows(Rect) 8259 * @see #setSystemUiVisibility(int) 8260 */ 8261 public void setFitsSystemWindows(boolean fitSystemWindows) { 8262 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 8263 } 8264 8265 /** 8266 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 8267 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 8268 * will be executed. 8269 * 8270 * @return {@code true} if the default implementation of 8271 * {@link #fitSystemWindows(Rect)} will be executed. 8272 * 8273 * @attr ref android.R.styleable#View_fitsSystemWindows 8274 * @see #setFitsSystemWindows(boolean) 8275 * @see #fitSystemWindows(Rect) 8276 * @see #setSystemUiVisibility(int) 8277 */ 8278 @ViewDebug.ExportedProperty 8279 public boolean getFitsSystemWindows() { 8280 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 8281 } 8282 8283 /** @hide */ 8284 public boolean fitsSystemWindows() { 8285 return getFitsSystemWindows(); 8286 } 8287 8288 /** 8289 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 8290 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 8291 */ 8292 @Deprecated 8293 public void requestFitSystemWindows() { 8294 if (mParent != null) { 8295 mParent.requestFitSystemWindows(); 8296 } 8297 } 8298 8299 /** 8300 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 8301 */ 8302 public void requestApplyInsets() { 8303 requestFitSystemWindows(); 8304 } 8305 8306 /** 8307 * For use by PhoneWindow to make its own system window fitting optional. 8308 * @hide 8309 */ 8310 public void makeOptionalFitsSystemWindows() { 8311 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 8312 } 8313 8314 /** 8315 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 8316 * treat them as such. 8317 * @hide 8318 */ 8319 public void getOutsets(Rect outOutsetRect) { 8320 if (mAttachInfo != null) { 8321 outOutsetRect.set(mAttachInfo.mOutsets); 8322 } else { 8323 outOutsetRect.setEmpty(); 8324 } 8325 } 8326 8327 /** 8328 * Returns the visibility status for this view. 8329 * 8330 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8331 * @attr ref android.R.styleable#View_visibility 8332 */ 8333 @ViewDebug.ExportedProperty(mapping = { 8334 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 8335 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 8336 @ViewDebug.IntToString(from = GONE, to = "GONE") 8337 }) 8338 @Visibility 8339 public int getVisibility() { 8340 return mViewFlags & VISIBILITY_MASK; 8341 } 8342 8343 /** 8344 * Set the visibility state of this view. 8345 * 8346 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8347 * @attr ref android.R.styleable#View_visibility 8348 */ 8349 @RemotableViewMethod 8350 public void setVisibility(@Visibility int visibility) { 8351 setFlags(visibility, VISIBILITY_MASK); 8352 } 8353 8354 /** 8355 * Returns the enabled status for this view. The interpretation of the 8356 * enabled state varies by subclass. 8357 * 8358 * @return True if this view is enabled, false otherwise. 8359 */ 8360 @ViewDebug.ExportedProperty 8361 public boolean isEnabled() { 8362 return (mViewFlags & ENABLED_MASK) == ENABLED; 8363 } 8364 8365 /** 8366 * Set the enabled state of this view. The interpretation of the enabled 8367 * state varies by subclass. 8368 * 8369 * @param enabled True if this view is enabled, false otherwise. 8370 */ 8371 @RemotableViewMethod 8372 public void setEnabled(boolean enabled) { 8373 if (enabled == isEnabled()) return; 8374 8375 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 8376 8377 /* 8378 * The View most likely has to change its appearance, so refresh 8379 * the drawable state. 8380 */ 8381 refreshDrawableState(); 8382 8383 // Invalidate too, since the default behavior for views is to be 8384 // be drawn at 50% alpha rather than to change the drawable. 8385 invalidate(true); 8386 8387 if (!enabled) { 8388 cancelPendingInputEvents(); 8389 } 8390 } 8391 8392 /** 8393 * Set whether this view can receive the focus. 8394 * 8395 * Setting this to false will also ensure that this view is not focusable 8396 * in touch mode. 8397 * 8398 * @param focusable If true, this view can receive the focus. 8399 * 8400 * @see #setFocusableInTouchMode(boolean) 8401 * @attr ref android.R.styleable#View_focusable 8402 */ 8403 public void setFocusable(boolean focusable) { 8404 if (!focusable) { 8405 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 8406 } 8407 setFlags(focusable ? FOCUSABLE : NOT_FOCUSABLE, FOCUSABLE_MASK); 8408 } 8409 8410 /** 8411 * Set whether this view can receive focus while in touch mode. 8412 * 8413 * Setting this to true will also ensure that this view is focusable. 8414 * 8415 * @param focusableInTouchMode If true, this view can receive the focus while 8416 * in touch mode. 8417 * 8418 * @see #setFocusable(boolean) 8419 * @attr ref android.R.styleable#View_focusableInTouchMode 8420 */ 8421 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 8422 // Focusable in touch mode should always be set before the focusable flag 8423 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 8424 // which, in touch mode, will not successfully request focus on this view 8425 // because the focusable in touch mode flag is not set 8426 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 8427 if (focusableInTouchMode) { 8428 setFlags(FOCUSABLE, FOCUSABLE_MASK); 8429 } 8430 } 8431 8432 /** 8433 * Set whether this view should have sound effects enabled for events such as 8434 * clicking and touching. 8435 * 8436 * <p>You may wish to disable sound effects for a view if you already play sounds, 8437 * for instance, a dial key that plays dtmf tones. 8438 * 8439 * @param soundEffectsEnabled whether sound effects are enabled for this view. 8440 * @see #isSoundEffectsEnabled() 8441 * @see #playSoundEffect(int) 8442 * @attr ref android.R.styleable#View_soundEffectsEnabled 8443 */ 8444 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 8445 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 8446 } 8447 8448 /** 8449 * @return whether this view should have sound effects enabled for events such as 8450 * clicking and touching. 8451 * 8452 * @see #setSoundEffectsEnabled(boolean) 8453 * @see #playSoundEffect(int) 8454 * @attr ref android.R.styleable#View_soundEffectsEnabled 8455 */ 8456 @ViewDebug.ExportedProperty 8457 public boolean isSoundEffectsEnabled() { 8458 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 8459 } 8460 8461 /** 8462 * Set whether this view should have haptic feedback for events such as 8463 * long presses. 8464 * 8465 * <p>You may wish to disable haptic feedback if your view already controls 8466 * its own haptic feedback. 8467 * 8468 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 8469 * @see #isHapticFeedbackEnabled() 8470 * @see #performHapticFeedback(int) 8471 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8472 */ 8473 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 8474 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 8475 } 8476 8477 /** 8478 * @return whether this view should have haptic feedback enabled for events 8479 * long presses. 8480 * 8481 * @see #setHapticFeedbackEnabled(boolean) 8482 * @see #performHapticFeedback(int) 8483 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8484 */ 8485 @ViewDebug.ExportedProperty 8486 public boolean isHapticFeedbackEnabled() { 8487 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 8488 } 8489 8490 /** 8491 * Returns the layout direction for this view. 8492 * 8493 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 8494 * {@link #LAYOUT_DIRECTION_RTL}, 8495 * {@link #LAYOUT_DIRECTION_INHERIT} or 8496 * {@link #LAYOUT_DIRECTION_LOCALE}. 8497 * 8498 * @attr ref android.R.styleable#View_layoutDirection 8499 * 8500 * @hide 8501 */ 8502 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8503 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 8504 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 8505 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 8506 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 8507 }) 8508 @LayoutDir 8509 public int getRawLayoutDirection() { 8510 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 8511 } 8512 8513 /** 8514 * Set the layout direction for this view. This will propagate a reset of layout direction 8515 * resolution to the view's children and resolve layout direction for this view. 8516 * 8517 * @param layoutDirection the layout direction to set. Should be one of: 8518 * 8519 * {@link #LAYOUT_DIRECTION_LTR}, 8520 * {@link #LAYOUT_DIRECTION_RTL}, 8521 * {@link #LAYOUT_DIRECTION_INHERIT}, 8522 * {@link #LAYOUT_DIRECTION_LOCALE}. 8523 * 8524 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 8525 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 8526 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 8527 * 8528 * @attr ref android.R.styleable#View_layoutDirection 8529 */ 8530 @RemotableViewMethod 8531 public void setLayoutDirection(@LayoutDir int layoutDirection) { 8532 if (getRawLayoutDirection() != layoutDirection) { 8533 // Reset the current layout direction and the resolved one 8534 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 8535 resetRtlProperties(); 8536 // Set the new layout direction (filtered) 8537 mPrivateFlags2 |= 8538 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 8539 // We need to resolve all RTL properties as they all depend on layout direction 8540 resolveRtlPropertiesIfNeeded(); 8541 requestLayout(); 8542 invalidate(true); 8543 } 8544 } 8545 8546 /** 8547 * Returns the resolved layout direction for this view. 8548 * 8549 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 8550 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 8551 * 8552 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 8553 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 8554 * 8555 * @attr ref android.R.styleable#View_layoutDirection 8556 */ 8557 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8558 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 8559 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 8560 }) 8561 @ResolvedLayoutDir 8562 public int getLayoutDirection() { 8563 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 8564 if (targetSdkVersion < JELLY_BEAN_MR1) { 8565 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 8566 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 8567 } 8568 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 8569 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 8570 } 8571 8572 /** 8573 * Indicates whether or not this view's layout is right-to-left. This is resolved from 8574 * layout attribute and/or the inherited value from the parent 8575 * 8576 * @return true if the layout is right-to-left. 8577 * 8578 * @hide 8579 */ 8580 @ViewDebug.ExportedProperty(category = "layout") 8581 public boolean isLayoutRtl() { 8582 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 8583 } 8584 8585 /** 8586 * Indicates whether the view is currently tracking transient state that the 8587 * app should not need to concern itself with saving and restoring, but that 8588 * the framework should take special note to preserve when possible. 8589 * 8590 * <p>A view with transient state cannot be trivially rebound from an external 8591 * data source, such as an adapter binding item views in a list. This may be 8592 * because the view is performing an animation, tracking user selection 8593 * of content, or similar.</p> 8594 * 8595 * @return true if the view has transient state 8596 */ 8597 @ViewDebug.ExportedProperty(category = "layout") 8598 public boolean hasTransientState() { 8599 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 8600 } 8601 8602 /** 8603 * Set whether this view is currently tracking transient state that the 8604 * framework should attempt to preserve when possible. This flag is reference counted, 8605 * so every call to setHasTransientState(true) should be paired with a later call 8606 * to setHasTransientState(false). 8607 * 8608 * <p>A view with transient state cannot be trivially rebound from an external 8609 * data source, such as an adapter binding item views in a list. This may be 8610 * because the view is performing an animation, tracking user selection 8611 * of content, or similar.</p> 8612 * 8613 * @param hasTransientState true if this view has transient state 8614 */ 8615 public void setHasTransientState(boolean hasTransientState) { 8616 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 8617 mTransientStateCount - 1; 8618 if (mTransientStateCount < 0) { 8619 mTransientStateCount = 0; 8620 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 8621 "unmatched pair of setHasTransientState calls"); 8622 } else if ((hasTransientState && mTransientStateCount == 1) || 8623 (!hasTransientState && mTransientStateCount == 0)) { 8624 // update flag if we've just incremented up from 0 or decremented down to 0 8625 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 8626 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 8627 if (mParent != null) { 8628 try { 8629 mParent.childHasTransientStateChanged(this, hasTransientState); 8630 } catch (AbstractMethodError e) { 8631 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 8632 " does not fully implement ViewParent", e); 8633 } 8634 } 8635 } 8636 } 8637 8638 /** 8639 * Returns true if this view is currently attached to a window. 8640 */ 8641 public boolean isAttachedToWindow() { 8642 return mAttachInfo != null; 8643 } 8644 8645 /** 8646 * Returns true if this view has been through at least one layout since it 8647 * was last attached to or detached from a window. 8648 */ 8649 public boolean isLaidOut() { 8650 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 8651 } 8652 8653 /** 8654 * If this view doesn't do any drawing on its own, set this flag to 8655 * allow further optimizations. By default, this flag is not set on 8656 * View, but could be set on some View subclasses such as ViewGroup. 8657 * 8658 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 8659 * you should clear this flag. 8660 * 8661 * @param willNotDraw whether or not this View draw on its own 8662 */ 8663 public void setWillNotDraw(boolean willNotDraw) { 8664 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 8665 } 8666 8667 /** 8668 * Returns whether or not this View draws on its own. 8669 * 8670 * @return true if this view has nothing to draw, false otherwise 8671 */ 8672 @ViewDebug.ExportedProperty(category = "drawing") 8673 public boolean willNotDraw() { 8674 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 8675 } 8676 8677 /** 8678 * When a View's drawing cache is enabled, drawing is redirected to an 8679 * offscreen bitmap. Some views, like an ImageView, must be able to 8680 * bypass this mechanism if they already draw a single bitmap, to avoid 8681 * unnecessary usage of the memory. 8682 * 8683 * @param willNotCacheDrawing true if this view does not cache its 8684 * drawing, false otherwise 8685 */ 8686 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 8687 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 8688 } 8689 8690 /** 8691 * Returns whether or not this View can cache its drawing or not. 8692 * 8693 * @return true if this view does not cache its drawing, false otherwise 8694 */ 8695 @ViewDebug.ExportedProperty(category = "drawing") 8696 public boolean willNotCacheDrawing() { 8697 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 8698 } 8699 8700 /** 8701 * Indicates whether this view reacts to click events or not. 8702 * 8703 * @return true if the view is clickable, false otherwise 8704 * 8705 * @see #setClickable(boolean) 8706 * @attr ref android.R.styleable#View_clickable 8707 */ 8708 @ViewDebug.ExportedProperty 8709 public boolean isClickable() { 8710 return (mViewFlags & CLICKABLE) == CLICKABLE; 8711 } 8712 8713 /** 8714 * Enables or disables click events for this view. When a view 8715 * is clickable it will change its state to "pressed" on every click. 8716 * Subclasses should set the view clickable to visually react to 8717 * user's clicks. 8718 * 8719 * @param clickable true to make the view clickable, false otherwise 8720 * 8721 * @see #isClickable() 8722 * @attr ref android.R.styleable#View_clickable 8723 */ 8724 public void setClickable(boolean clickable) { 8725 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 8726 } 8727 8728 /** 8729 * Indicates whether this view reacts to long click events or not. 8730 * 8731 * @return true if the view is long clickable, false otherwise 8732 * 8733 * @see #setLongClickable(boolean) 8734 * @attr ref android.R.styleable#View_longClickable 8735 */ 8736 public boolean isLongClickable() { 8737 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 8738 } 8739 8740 /** 8741 * Enables or disables long click events for this view. When a view is long 8742 * clickable it reacts to the user holding down the button for a longer 8743 * duration than a tap. This event can either launch the listener or a 8744 * context menu. 8745 * 8746 * @param longClickable true to make the view long clickable, false otherwise 8747 * @see #isLongClickable() 8748 * @attr ref android.R.styleable#View_longClickable 8749 */ 8750 public void setLongClickable(boolean longClickable) { 8751 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 8752 } 8753 8754 /** 8755 * Indicates whether this view reacts to context clicks or not. 8756 * 8757 * @return true if the view is context clickable, false otherwise 8758 * @see #setContextClickable(boolean) 8759 * @attr ref android.R.styleable#View_contextClickable 8760 */ 8761 public boolean isContextClickable() { 8762 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 8763 } 8764 8765 /** 8766 * Enables or disables context clicking for this view. This event can launch the listener. 8767 * 8768 * @param contextClickable true to make the view react to a context click, false otherwise 8769 * @see #isContextClickable() 8770 * @attr ref android.R.styleable#View_contextClickable 8771 */ 8772 public void setContextClickable(boolean contextClickable) { 8773 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 8774 } 8775 8776 /** 8777 * Sets the pressed state for this view and provides a touch coordinate for 8778 * animation hinting. 8779 * 8780 * @param pressed Pass true to set the View's internal state to "pressed", 8781 * or false to reverts the View's internal state from a 8782 * previously set "pressed" state. 8783 * @param x The x coordinate of the touch that caused the press 8784 * @param y The y coordinate of the touch that caused the press 8785 */ 8786 private void setPressed(boolean pressed, float x, float y) { 8787 if (pressed) { 8788 drawableHotspotChanged(x, y); 8789 } 8790 8791 setPressed(pressed); 8792 } 8793 8794 /** 8795 * Sets the pressed state for this view. 8796 * 8797 * @see #isClickable() 8798 * @see #setClickable(boolean) 8799 * 8800 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 8801 * the View's internal state from a previously set "pressed" state. 8802 */ 8803 public void setPressed(boolean pressed) { 8804 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 8805 8806 if (pressed) { 8807 mPrivateFlags |= PFLAG_PRESSED; 8808 } else { 8809 mPrivateFlags &= ~PFLAG_PRESSED; 8810 } 8811 8812 if (needsRefresh) { 8813 refreshDrawableState(); 8814 } 8815 dispatchSetPressed(pressed); 8816 } 8817 8818 /** 8819 * Dispatch setPressed to all of this View's children. 8820 * 8821 * @see #setPressed(boolean) 8822 * 8823 * @param pressed The new pressed state 8824 */ 8825 protected void dispatchSetPressed(boolean pressed) { 8826 } 8827 8828 /** 8829 * Indicates whether the view is currently in pressed state. Unless 8830 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 8831 * the pressed state. 8832 * 8833 * @see #setPressed(boolean) 8834 * @see #isClickable() 8835 * @see #setClickable(boolean) 8836 * 8837 * @return true if the view is currently pressed, false otherwise 8838 */ 8839 @ViewDebug.ExportedProperty 8840 public boolean isPressed() { 8841 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 8842 } 8843 8844 /** 8845 * @hide 8846 * Indicates whether this view will participate in data collection through 8847 * {@link ViewStructure}. If true, it will not provide any data 8848 * for itself or its children. If false, the normal data collection will be allowed. 8849 * 8850 * @return Returns false if assist data collection is not blocked, else true. 8851 * 8852 * @see #setAssistBlocked(boolean) 8853 * @attr ref android.R.styleable#View_assistBlocked 8854 */ 8855 public boolean isAssistBlocked() { 8856 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 8857 } 8858 8859 /** 8860 * @hide 8861 * Indicates whether this view will participate in data collection through 8862 * {@link ViewStructure} for auto-fill purposes. 8863 * 8864 * <p>If {@code true}, it will not provide any data for itself or its children. 8865 * <p>If {@code false}, the normal data collection will be allowed. 8866 * 8867 * @return Returns {@code false} if assist data collection for auto-fill is not blocked, 8868 * else {@code true}. 8869 * 8870 * TODO(b/33197203): update / remove javadoc tags below 8871 * @see #setAssistBlocked(boolean) 8872 * @attr ref android.R.styleable#View_assistBlocked 8873 */ 8874 public boolean isAutoFillBlocked() { 8875 return false; // TODO(b/33197203): properly implement it 8876 } 8877 8878 /** 8879 * @hide 8880 * Controls whether assist data collection from this view and its children is enabled 8881 * (that is, whether {@link #onProvideStructure} and 8882 * {@link #onProvideVirtualStructure} will be called). The default value is false, 8883 * allowing normal assist collection. Setting this to false will disable assist collection. 8884 * 8885 * @param enabled Set to true to <em>disable</em> assist data collection, or false 8886 * (the default) to allow it. 8887 * 8888 * @see #isAssistBlocked() 8889 * @see #onProvideStructure 8890 * @see #onProvideVirtualStructure 8891 * @attr ref android.R.styleable#View_assistBlocked 8892 */ 8893 public void setAssistBlocked(boolean enabled) { 8894 if (enabled) { 8895 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 8896 } else { 8897 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 8898 } 8899 } 8900 8901 /** 8902 * Indicates whether this view will save its state (that is, 8903 * whether its {@link #onSaveInstanceState} method will be called). 8904 * 8905 * @return Returns true if the view state saving is enabled, else false. 8906 * 8907 * @see #setSaveEnabled(boolean) 8908 * @attr ref android.R.styleable#View_saveEnabled 8909 */ 8910 public boolean isSaveEnabled() { 8911 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 8912 } 8913 8914 /** 8915 * Controls whether the saving of this view's state is 8916 * enabled (that is, whether its {@link #onSaveInstanceState} method 8917 * will be called). Note that even if freezing is enabled, the 8918 * view still must have an id assigned to it (via {@link #setId(int)}) 8919 * for its state to be saved. This flag can only disable the 8920 * saving of this view; any child views may still have their state saved. 8921 * 8922 * @param enabled Set to false to <em>disable</em> state saving, or true 8923 * (the default) to allow it. 8924 * 8925 * @see #isSaveEnabled() 8926 * @see #setId(int) 8927 * @see #onSaveInstanceState() 8928 * @attr ref android.R.styleable#View_saveEnabled 8929 */ 8930 public void setSaveEnabled(boolean enabled) { 8931 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 8932 } 8933 8934 /** 8935 * Gets whether the framework should discard touches when the view's 8936 * window is obscured by another visible window. 8937 * Refer to the {@link View} security documentation for more details. 8938 * 8939 * @return True if touch filtering is enabled. 8940 * 8941 * @see #setFilterTouchesWhenObscured(boolean) 8942 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 8943 */ 8944 @ViewDebug.ExportedProperty 8945 public boolean getFilterTouchesWhenObscured() { 8946 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 8947 } 8948 8949 /** 8950 * Sets whether the framework should discard touches when the view's 8951 * window is obscured by another visible window. 8952 * Refer to the {@link View} security documentation for more details. 8953 * 8954 * @param enabled True if touch filtering should be enabled. 8955 * 8956 * @see #getFilterTouchesWhenObscured 8957 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 8958 */ 8959 public void setFilterTouchesWhenObscured(boolean enabled) { 8960 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 8961 FILTER_TOUCHES_WHEN_OBSCURED); 8962 } 8963 8964 /** 8965 * Indicates whether the entire hierarchy under this view will save its 8966 * state when a state saving traversal occurs from its parent. The default 8967 * is true; if false, these views will not be saved unless 8968 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 8969 * 8970 * @return Returns true if the view state saving from parent is enabled, else false. 8971 * 8972 * @see #setSaveFromParentEnabled(boolean) 8973 */ 8974 public boolean isSaveFromParentEnabled() { 8975 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 8976 } 8977 8978 /** 8979 * Controls whether the entire hierarchy under this view will save its 8980 * state when a state saving traversal occurs from its parent. The default 8981 * is true; if false, these views will not be saved unless 8982 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 8983 * 8984 * @param enabled Set to false to <em>disable</em> state saving, or true 8985 * (the default) to allow it. 8986 * 8987 * @see #isSaveFromParentEnabled() 8988 * @see #setId(int) 8989 * @see #onSaveInstanceState() 8990 */ 8991 public void setSaveFromParentEnabled(boolean enabled) { 8992 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 8993 } 8994 8995 8996 /** 8997 * Returns whether this View is able to take focus. 8998 * 8999 * @return True if this view can take focus, or false otherwise. 9000 * @attr ref android.R.styleable#View_focusable 9001 */ 9002 @ViewDebug.ExportedProperty(category = "focus") 9003 public final boolean isFocusable() { 9004 return FOCUSABLE == (mViewFlags & FOCUSABLE_MASK); 9005 } 9006 9007 /** 9008 * When a view is focusable, it may not want to take focus when in touch mode. 9009 * For example, a button would like focus when the user is navigating via a D-pad 9010 * so that the user can click on it, but once the user starts touching the screen, 9011 * the button shouldn't take focus 9012 * @return Whether the view is focusable in touch mode. 9013 * @attr ref android.R.styleable#View_focusableInTouchMode 9014 */ 9015 @ViewDebug.ExportedProperty 9016 public final boolean isFocusableInTouchMode() { 9017 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 9018 } 9019 9020 /** 9021 * Find the nearest view in the specified direction that can take focus. 9022 * This does not actually give focus to that view. 9023 * 9024 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9025 * 9026 * @return The nearest focusable in the specified direction, or null if none 9027 * can be found. 9028 */ 9029 public View focusSearch(@FocusRealDirection int direction) { 9030 if (mParent != null) { 9031 return mParent.focusSearch(this, direction); 9032 } else { 9033 return null; 9034 } 9035 } 9036 9037 /** 9038 * Returns whether this View is a root of a keyboard navigation cluster. 9039 * 9040 * @return True if this view is a root of a cluster, or false otherwise. 9041 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9042 */ 9043 @ViewDebug.ExportedProperty(category = "keyboardNavigationCluster") 9044 public final boolean isKeyboardNavigationCluster() { 9045 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 9046 } 9047 9048 /** 9049 * Set whether this view is a root of a keyboard navigation cluster. 9050 * 9051 * @param isCluster If true, this view is a root of a cluster. 9052 * 9053 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9054 */ 9055 public void setKeyboardNavigationCluster(boolean isCluster) { 9056 if (isCluster) { 9057 mPrivateFlags3 |= PFLAG3_CLUSTER; 9058 } else { 9059 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 9060 } 9061 } 9062 9063 /** 9064 * Returns whether this View is a root of a keyboard navigation section. 9065 * 9066 * @return True if this view is a root of a section, or false otherwise. 9067 * @attr ref android.R.styleable#View_keyboardNavigationSection 9068 */ 9069 @ViewDebug.ExportedProperty(category = "keyboardNavigationSection") 9070 public final boolean isKeyboardNavigationSection() { 9071 return (mPrivateFlags3 & PFLAG3_SECTION) != 0; 9072 } 9073 9074 /** 9075 * Set whether this view is a root of a keyboard navigation section. 9076 * 9077 * @param isSection If true, this view is a root of a section. 9078 * 9079 * @attr ref android.R.styleable#View_keyboardNavigationSection 9080 */ 9081 public void setKeyboardNavigationSection(boolean isSection) { 9082 if (isSection) { 9083 mPrivateFlags3 |= PFLAG3_SECTION; 9084 } else { 9085 mPrivateFlags3 &= ~PFLAG3_SECTION; 9086 } 9087 } 9088 9089 /** 9090 * Find the nearest keyboard navigation cluster in the specified direction. 9091 * This does not actually give focus to that cluster. 9092 * 9093 * @param direction Direction to look 9094 * 9095 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 9096 * can be found 9097 */ 9098 public View keyboardNavigationClusterSearch(int direction) { 9099 if (mParent != null) { 9100 final View currentCluster = isKeyboardNavigationCluster() ? this : null; 9101 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 9102 } else { 9103 return null; 9104 } 9105 } 9106 9107 /** 9108 * This method is the last chance for the focused view and its ancestors to 9109 * respond to an arrow key. This is called when the focused view did not 9110 * consume the key internally, nor could the view system find a new view in 9111 * the requested direction to give focus to. 9112 * 9113 * @param focused The currently focused view. 9114 * @param direction The direction focus wants to move. One of FOCUS_UP, 9115 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 9116 * @return True if the this view consumed this unhandled move. 9117 */ 9118 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 9119 return false; 9120 } 9121 9122 /** 9123 * If a user manually specified the next view id for a particular direction, 9124 * use the root to look up the view. 9125 * @param root The root view of the hierarchy containing this view. 9126 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 9127 * or FOCUS_BACKWARD. 9128 * @return The user specified next view, or null if there is none. 9129 */ 9130 View findUserSetNextFocus(View root, @FocusDirection int direction) { 9131 switch (direction) { 9132 case FOCUS_LEFT: 9133 if (mNextFocusLeftId == View.NO_ID) return null; 9134 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 9135 case FOCUS_RIGHT: 9136 if (mNextFocusRightId == View.NO_ID) return null; 9137 return findViewInsideOutShouldExist(root, mNextFocusRightId); 9138 case FOCUS_UP: 9139 if (mNextFocusUpId == View.NO_ID) return null; 9140 return findViewInsideOutShouldExist(root, mNextFocusUpId); 9141 case FOCUS_DOWN: 9142 if (mNextFocusDownId == View.NO_ID) return null; 9143 return findViewInsideOutShouldExist(root, mNextFocusDownId); 9144 case FOCUS_FORWARD: 9145 if (mNextFocusForwardId == View.NO_ID) return null; 9146 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 9147 case FOCUS_BACKWARD: { 9148 if (mID == View.NO_ID) return null; 9149 final int id = mID; 9150 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 9151 @Override 9152 public boolean apply(View t) { 9153 return t.mNextFocusForwardId == id; 9154 } 9155 }); 9156 } 9157 } 9158 return null; 9159 } 9160 9161 private View findViewInsideOutShouldExist(View root, int id) { 9162 if (mMatchIdPredicate == null) { 9163 mMatchIdPredicate = new MatchIdPredicate(); 9164 } 9165 mMatchIdPredicate.mId = id; 9166 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 9167 if (result == null) { 9168 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 9169 } 9170 return result; 9171 } 9172 9173 /** 9174 * Find and return all focusable views that are descendants of this view, 9175 * possibly including this view if it is focusable itself. 9176 * 9177 * @param direction The direction of the focus 9178 * @return A list of focusable views 9179 */ 9180 public ArrayList<View> getFocusables(@FocusDirection int direction) { 9181 ArrayList<View> result = new ArrayList<View>(24); 9182 addFocusables(result, direction); 9183 return result; 9184 } 9185 9186 /** 9187 * Add any focusable views that are descendants of this view (possibly 9188 * including this view if it is focusable itself) to views. If we are in touch mode, 9189 * only add views that are also focusable in touch mode. 9190 * 9191 * @param views Focusable views found so far 9192 * @param direction The direction of the focus 9193 */ 9194 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 9195 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 9196 } 9197 9198 /** 9199 * Adds any focusable views that are descendants of this view (possibly 9200 * including this view if it is focusable itself) to views. This method 9201 * adds all focusable views regardless if we are in touch mode or 9202 * only views focusable in touch mode if we are in touch mode or 9203 * only views that can take accessibility focus if accessibility is enabled 9204 * depending on the focusable mode parameter. 9205 * 9206 * @param views Focusable views found so far or null if all we are interested is 9207 * the number of focusables. 9208 * @param direction The direction of the focus. 9209 * @param focusableMode The type of focusables to be added. 9210 * 9211 * @see #FOCUSABLES_ALL 9212 * @see #FOCUSABLES_TOUCH_MODE 9213 */ 9214 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 9215 @FocusableMode int focusableMode) { 9216 if (views == null) { 9217 return; 9218 } 9219 if (!isFocusable()) { 9220 return; 9221 } 9222 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 9223 && !isFocusableInTouchMode()) { 9224 return; 9225 } 9226 views.add(this); 9227 } 9228 9229 /** 9230 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 9231 * including this view if it is a cluster root itself) to views. 9232 * 9233 * @param views Cluster roots found so far 9234 * @param direction Direction to look 9235 */ 9236 public void addKeyboardNavigationClusters(@NonNull Collection<View> views, int direction) { 9237 if (!isKeyboardNavigationCluster()) { 9238 return; 9239 } 9240 views.add(this); 9241 } 9242 9243 /** 9244 * Finds the Views that contain given text. The containment is case insensitive. 9245 * The search is performed by either the text that the View renders or the content 9246 * description that describes the view for accessibility purposes and the view does 9247 * not render or both. Clients can specify how the search is to be performed via 9248 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 9249 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 9250 * 9251 * @param outViews The output list of matching Views. 9252 * @param searched The text to match against. 9253 * 9254 * @see #FIND_VIEWS_WITH_TEXT 9255 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 9256 * @see #setContentDescription(CharSequence) 9257 */ 9258 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 9259 @FindViewFlags int flags) { 9260 if (getAccessibilityNodeProvider() != null) { 9261 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 9262 outViews.add(this); 9263 } 9264 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 9265 && (searched != null && searched.length() > 0) 9266 && (mContentDescription != null && mContentDescription.length() > 0)) { 9267 String searchedLowerCase = searched.toString().toLowerCase(); 9268 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 9269 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 9270 outViews.add(this); 9271 } 9272 } 9273 } 9274 9275 /** 9276 * Find and return all touchable views that are descendants of this view, 9277 * possibly including this view if it is touchable itself. 9278 * 9279 * @return A list of touchable views 9280 */ 9281 public ArrayList<View> getTouchables() { 9282 ArrayList<View> result = new ArrayList<View>(); 9283 addTouchables(result); 9284 return result; 9285 } 9286 9287 /** 9288 * Add any touchable views that are descendants of this view (possibly 9289 * including this view if it is touchable itself) to views. 9290 * 9291 * @param views Touchable views found so far 9292 */ 9293 public void addTouchables(ArrayList<View> views) { 9294 final int viewFlags = mViewFlags; 9295 9296 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 9297 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 9298 && (viewFlags & ENABLED_MASK) == ENABLED) { 9299 views.add(this); 9300 } 9301 } 9302 9303 /** 9304 * Returns whether this View is accessibility focused. 9305 * 9306 * @return True if this View is accessibility focused. 9307 */ 9308 public boolean isAccessibilityFocused() { 9309 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 9310 } 9311 9312 /** 9313 * Call this to try to give accessibility focus to this view. 9314 * 9315 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 9316 * returns false or the view is no visible or the view already has accessibility 9317 * focus. 9318 * 9319 * See also {@link #focusSearch(int)}, which is what you call to say that you 9320 * have focus, and you want your parent to look for the next one. 9321 * 9322 * @return Whether this view actually took accessibility focus. 9323 * 9324 * @hide 9325 */ 9326 public boolean requestAccessibilityFocus() { 9327 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 9328 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 9329 return false; 9330 } 9331 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9332 return false; 9333 } 9334 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 9335 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 9336 ViewRootImpl viewRootImpl = getViewRootImpl(); 9337 if (viewRootImpl != null) { 9338 viewRootImpl.setAccessibilityFocus(this, null); 9339 } 9340 invalidate(); 9341 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 9342 return true; 9343 } 9344 return false; 9345 } 9346 9347 /** 9348 * Call this to try to clear accessibility focus of this view. 9349 * 9350 * See also {@link #focusSearch(int)}, which is what you call to say that you 9351 * have focus, and you want your parent to look for the next one. 9352 * 9353 * @hide 9354 */ 9355 public void clearAccessibilityFocus() { 9356 clearAccessibilityFocusNoCallbacks(0); 9357 9358 // Clear the global reference of accessibility focus if this view or 9359 // any of its descendants had accessibility focus. This will NOT send 9360 // an event or update internal state if focus is cleared from a 9361 // descendant view, which may leave views in inconsistent states. 9362 final ViewRootImpl viewRootImpl = getViewRootImpl(); 9363 if (viewRootImpl != null) { 9364 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 9365 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 9366 viewRootImpl.setAccessibilityFocus(null, null); 9367 } 9368 } 9369 } 9370 9371 private void sendAccessibilityHoverEvent(int eventType) { 9372 // Since we are not delivering to a client accessibility events from not 9373 // important views (unless the clinet request that) we need to fire the 9374 // event from the deepest view exposed to the client. As a consequence if 9375 // the user crosses a not exposed view the client will see enter and exit 9376 // of the exposed predecessor followed by and enter and exit of that same 9377 // predecessor when entering and exiting the not exposed descendant. This 9378 // is fine since the client has a clear idea which view is hovered at the 9379 // price of a couple more events being sent. This is a simple and 9380 // working solution. 9381 View source = this; 9382 while (true) { 9383 if (source.includeForAccessibility()) { 9384 source.sendAccessibilityEvent(eventType); 9385 return; 9386 } 9387 ViewParent parent = source.getParent(); 9388 if (parent instanceof View) { 9389 source = (View) parent; 9390 } else { 9391 return; 9392 } 9393 } 9394 } 9395 9396 /** 9397 * Clears accessibility focus without calling any callback methods 9398 * normally invoked in {@link #clearAccessibilityFocus()}. This method 9399 * is used separately from that one for clearing accessibility focus when 9400 * giving this focus to another view. 9401 * 9402 * @param action The action, if any, that led to focus being cleared. Set to 9403 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 9404 * the window. 9405 */ 9406 void clearAccessibilityFocusNoCallbacks(int action) { 9407 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 9408 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 9409 invalidate(); 9410 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 9411 AccessibilityEvent event = AccessibilityEvent.obtain( 9412 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 9413 event.setAction(action); 9414 if (mAccessibilityDelegate != null) { 9415 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 9416 } else { 9417 sendAccessibilityEventUnchecked(event); 9418 } 9419 } 9420 } 9421 } 9422 9423 /** 9424 * Call this to try to give focus to a specific view or to one of its 9425 * descendants. 9426 * 9427 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9428 * false), or if it is focusable and it is not focusable in touch mode 9429 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9430 * 9431 * See also {@link #focusSearch(int)}, which is what you call to say that you 9432 * have focus, and you want your parent to look for the next one. 9433 * 9434 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 9435 * {@link #FOCUS_DOWN} and <code>null</code>. 9436 * 9437 * @return Whether this view or one of its descendants actually took focus. 9438 */ 9439 public final boolean requestFocus() { 9440 return requestFocus(View.FOCUS_DOWN); 9441 } 9442 9443 /** 9444 * Call this to try to give focus to a specific view or to one of its 9445 * descendants and give it a hint about what direction focus is heading. 9446 * 9447 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9448 * false), or if it is focusable and it is not focusable in touch mode 9449 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9450 * 9451 * See also {@link #focusSearch(int)}, which is what you call to say that you 9452 * have focus, and you want your parent to look for the next one. 9453 * 9454 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 9455 * <code>null</code> set for the previously focused rectangle. 9456 * 9457 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9458 * @return Whether this view or one of its descendants actually took focus. 9459 */ 9460 public final boolean requestFocus(int direction) { 9461 return requestFocus(direction, null); 9462 } 9463 9464 /** 9465 * Call this to try to give focus to a specific view or to one of its descendants 9466 * and give it hints about the direction and a specific rectangle that the focus 9467 * is coming from. The rectangle can help give larger views a finer grained hint 9468 * about where focus is coming from, and therefore, where to show selection, or 9469 * forward focus change internally. 9470 * 9471 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9472 * false), or if it is focusable and it is not focusable in touch mode 9473 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9474 * 9475 * A View will not take focus if it is not visible. 9476 * 9477 * A View will not take focus if one of its parents has 9478 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 9479 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 9480 * 9481 * See also {@link #focusSearch(int)}, which is what you call to say that you 9482 * have focus, and you want your parent to look for the next one. 9483 * 9484 * You may wish to override this method if your custom {@link View} has an internal 9485 * {@link View} that it wishes to forward the request to. 9486 * 9487 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9488 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 9489 * to give a finer grained hint about where focus is coming from. May be null 9490 * if there is no hint. 9491 * @return Whether this view or one of its descendants actually took focus. 9492 */ 9493 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 9494 return requestFocusNoSearch(direction, previouslyFocusedRect); 9495 } 9496 9497 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 9498 // need to be focusable 9499 if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE || 9500 (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9501 return false; 9502 } 9503 9504 // need to be focusable in touch mode if in touch mode 9505 if (isInTouchMode() && 9506 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 9507 return false; 9508 } 9509 9510 // need to not have any parents blocking us 9511 if (hasAncestorThatBlocksDescendantFocus()) { 9512 return false; 9513 } 9514 9515 handleFocusGainInternal(direction, previouslyFocusedRect); 9516 return true; 9517 } 9518 9519 /** 9520 * Call this to try to give focus to a specific view or to one of its descendants. This is a 9521 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 9522 * touch mode to request focus when they are touched. 9523 * 9524 * @return Whether this view or one of its descendants actually took focus. 9525 * 9526 * @see #isInTouchMode() 9527 * 9528 */ 9529 public final boolean requestFocusFromTouch() { 9530 // Leave touch mode if we need to 9531 if (isInTouchMode()) { 9532 ViewRootImpl viewRoot = getViewRootImpl(); 9533 if (viewRoot != null) { 9534 viewRoot.ensureTouchMode(false); 9535 } 9536 } 9537 return requestFocus(View.FOCUS_DOWN); 9538 } 9539 9540 /** 9541 * @return Whether any ancestor of this view blocks descendant focus. 9542 */ 9543 private boolean hasAncestorThatBlocksDescendantFocus() { 9544 final boolean focusableInTouchMode = isFocusableInTouchMode(); 9545 ViewParent ancestor = mParent; 9546 while (ancestor instanceof ViewGroup) { 9547 final ViewGroup vgAncestor = (ViewGroup) ancestor; 9548 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 9549 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 9550 return true; 9551 } else { 9552 ancestor = vgAncestor.getParent(); 9553 } 9554 } 9555 return false; 9556 } 9557 9558 /** 9559 * Gets the mode for determining whether this View is important for accessibility. 9560 * A view is important for accessibility if it fires accessibility events and if it 9561 * is reported to accessibility services that query the screen. 9562 * 9563 * @return The mode for determining whether a view is important for accessibility, one 9564 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 9565 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 9566 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 9567 * 9568 * @attr ref android.R.styleable#View_importantForAccessibility 9569 * 9570 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9571 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9572 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9573 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9574 */ 9575 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 9576 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 9577 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 9578 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 9579 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 9580 to = "noHideDescendants") 9581 }) 9582 public int getImportantForAccessibility() { 9583 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9584 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9585 } 9586 9587 /** 9588 * Sets the live region mode for this view. This indicates to accessibility 9589 * services whether they should automatically notify the user about changes 9590 * to the view's content description or text, or to the content descriptions 9591 * or text of the view's children (where applicable). 9592 * <p> 9593 * For example, in a login screen with a TextView that displays an "incorrect 9594 * password" notification, that view should be marked as a live region with 9595 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9596 * <p> 9597 * To disable change notifications for this view, use 9598 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 9599 * mode for most views. 9600 * <p> 9601 * To indicate that the user should be notified of changes, use 9602 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9603 * <p> 9604 * If the view's changes should interrupt ongoing speech and notify the user 9605 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 9606 * 9607 * @param mode The live region mode for this view, one of: 9608 * <ul> 9609 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 9610 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 9611 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 9612 * </ul> 9613 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9614 */ 9615 public void setAccessibilityLiveRegion(int mode) { 9616 if (mode != getAccessibilityLiveRegion()) { 9617 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9618 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 9619 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9620 notifyViewAccessibilityStateChangedIfNeeded( 9621 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9622 } 9623 } 9624 9625 /** 9626 * Gets the live region mode for this View. 9627 * 9628 * @return The live region mode for the view. 9629 * 9630 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9631 * 9632 * @see #setAccessibilityLiveRegion(int) 9633 */ 9634 public int getAccessibilityLiveRegion() { 9635 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 9636 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 9637 } 9638 9639 /** 9640 * Sets how to determine whether this view is important for accessibility 9641 * which is if it fires accessibility events and if it is reported to 9642 * accessibility services that query the screen. 9643 * 9644 * @param mode How to determine whether this view is important for accessibility. 9645 * 9646 * @attr ref android.R.styleable#View_importantForAccessibility 9647 * 9648 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9649 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9650 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9651 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9652 */ 9653 public void setImportantForAccessibility(int mode) { 9654 final int oldMode = getImportantForAccessibility(); 9655 if (mode != oldMode) { 9656 final boolean hideDescendants = 9657 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 9658 9659 // If this node or its descendants are no longer important, try to 9660 // clear accessibility focus. 9661 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 9662 final View focusHost = findAccessibilityFocusHost(hideDescendants); 9663 if (focusHost != null) { 9664 focusHost.clearAccessibilityFocus(); 9665 } 9666 } 9667 9668 // If we're moving between AUTO and another state, we might not need 9669 // to send a subtree changed notification. We'll store the computed 9670 // importance, since we'll need to check it later to make sure. 9671 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 9672 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 9673 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 9674 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9675 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 9676 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9677 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 9678 notifySubtreeAccessibilityStateChangedIfNeeded(); 9679 } else { 9680 notifyViewAccessibilityStateChangedIfNeeded( 9681 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9682 } 9683 } 9684 } 9685 9686 /** 9687 * Returns the view within this view's hierarchy that is hosting 9688 * accessibility focus. 9689 * 9690 * @param searchDescendants whether to search for focus in descendant views 9691 * @return the view hosting accessibility focus, or {@code null} 9692 */ 9693 private View findAccessibilityFocusHost(boolean searchDescendants) { 9694 if (isAccessibilityFocusedViewOrHost()) { 9695 return this; 9696 } 9697 9698 if (searchDescendants) { 9699 final ViewRootImpl viewRoot = getViewRootImpl(); 9700 if (viewRoot != null) { 9701 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 9702 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 9703 return focusHost; 9704 } 9705 } 9706 } 9707 9708 return null; 9709 } 9710 9711 /** 9712 * Computes whether this view should be exposed for accessibility. In 9713 * general, views that are interactive or provide information are exposed 9714 * while views that serve only as containers are hidden. 9715 * <p> 9716 * If an ancestor of this view has importance 9717 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 9718 * returns <code>false</code>. 9719 * <p> 9720 * Otherwise, the value is computed according to the view's 9721 * {@link #getImportantForAccessibility()} value: 9722 * <ol> 9723 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 9724 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 9725 * </code> 9726 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 9727 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 9728 * view satisfies any of the following: 9729 * <ul> 9730 * <li>Is actionable, e.g. {@link #isClickable()}, 9731 * {@link #isLongClickable()}, or {@link #isFocusable()} 9732 * <li>Has an {@link AccessibilityDelegate} 9733 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 9734 * {@link OnKeyListener}, etc. 9735 * <li>Is an accessibility live region, e.g. 9736 * {@link #getAccessibilityLiveRegion()} is not 9737 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 9738 * </ul> 9739 * </ol> 9740 * 9741 * @return Whether the view is exposed for accessibility. 9742 * @see #setImportantForAccessibility(int) 9743 * @see #getImportantForAccessibility() 9744 */ 9745 public boolean isImportantForAccessibility() { 9746 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9747 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9748 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 9749 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 9750 return false; 9751 } 9752 9753 // Check parent mode to ensure we're not hidden. 9754 ViewParent parent = mParent; 9755 while (parent instanceof View) { 9756 if (((View) parent).getImportantForAccessibility() 9757 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 9758 return false; 9759 } 9760 parent = parent.getParent(); 9761 } 9762 9763 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 9764 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 9765 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 9766 } 9767 9768 /** 9769 * Gets the parent for accessibility purposes. Note that the parent for 9770 * accessibility is not necessary the immediate parent. It is the first 9771 * predecessor that is important for accessibility. 9772 * 9773 * @return The parent for accessibility purposes. 9774 */ 9775 public ViewParent getParentForAccessibility() { 9776 if (mParent instanceof View) { 9777 View parentView = (View) mParent; 9778 if (parentView.includeForAccessibility()) { 9779 return mParent; 9780 } else { 9781 return mParent.getParentForAccessibility(); 9782 } 9783 } 9784 return null; 9785 } 9786 9787 /** 9788 * Adds the children of this View relevant for accessibility to the given list 9789 * as output. Since some Views are not important for accessibility the added 9790 * child views are not necessarily direct children of this view, rather they are 9791 * the first level of descendants important for accessibility. 9792 * 9793 * @param outChildren The output list that will receive children for accessibility. 9794 */ 9795 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 9796 9797 } 9798 9799 /** 9800 * Whether to regard this view for accessibility. A view is regarded for 9801 * accessibility if it is important for accessibility or the querying 9802 * accessibility service has explicitly requested that view not 9803 * important for accessibility are regarded. 9804 * 9805 * @return Whether to regard the view for accessibility. 9806 * 9807 * @hide 9808 */ 9809 public boolean includeForAccessibility() { 9810 if (mAttachInfo != null) { 9811 return (mAttachInfo.mAccessibilityFetchFlags 9812 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 9813 || isImportantForAccessibility(); 9814 } 9815 return false; 9816 } 9817 9818 /** 9819 * Returns whether the View is considered actionable from 9820 * accessibility perspective. Such view are important for 9821 * accessibility. 9822 * 9823 * @return True if the view is actionable for accessibility. 9824 * 9825 * @hide 9826 */ 9827 public boolean isActionableForAccessibility() { 9828 return (isClickable() || isLongClickable() || isFocusable()); 9829 } 9830 9831 /** 9832 * Returns whether the View has registered callbacks which makes it 9833 * important for accessibility. 9834 * 9835 * @return True if the view is actionable for accessibility. 9836 */ 9837 private boolean hasListenersForAccessibility() { 9838 ListenerInfo info = getListenerInfo(); 9839 return mTouchDelegate != null || info.mOnKeyListener != null 9840 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 9841 || info.mOnHoverListener != null || info.mOnDragListener != null; 9842 } 9843 9844 /** 9845 * Notifies that the accessibility state of this view changed. The change 9846 * is local to this view and does not represent structural changes such 9847 * as children and parent. For example, the view became focusable. The 9848 * notification is at at most once every 9849 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 9850 * to avoid unnecessary load to the system. Also once a view has a pending 9851 * notification this method is a NOP until the notification has been sent. 9852 * 9853 * @hide 9854 */ 9855 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 9856 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 9857 return; 9858 } 9859 if (mSendViewStateChangedAccessibilityEvent == null) { 9860 mSendViewStateChangedAccessibilityEvent = 9861 new SendViewStateChangedAccessibilityEvent(); 9862 } 9863 mSendViewStateChangedAccessibilityEvent.runOrPost(changeType); 9864 } 9865 9866 /** 9867 * Notifies that the accessibility state of this view changed. The change 9868 * is *not* local to this view and does represent structural changes such 9869 * as children and parent. For example, the view size changed. The 9870 * notification is at at most once every 9871 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 9872 * to avoid unnecessary load to the system. Also once a view has a pending 9873 * notification this method is a NOP until the notification has been sent. 9874 * 9875 * @hide 9876 */ 9877 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 9878 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 9879 return; 9880 } 9881 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 9882 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 9883 if (mParent != null) { 9884 try { 9885 mParent.notifySubtreeAccessibilityStateChanged( 9886 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 9887 } catch (AbstractMethodError e) { 9888 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 9889 " does not fully implement ViewParent", e); 9890 } 9891 } 9892 } 9893 } 9894 9895 /** 9896 * Change the visibility of the View without triggering any other changes. This is 9897 * important for transitions, where visibility changes should not adjust focus or 9898 * trigger a new layout. This is only used when the visibility has already been changed 9899 * and we need a transient value during an animation. When the animation completes, 9900 * the original visibility value is always restored. 9901 * 9902 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9903 * @hide 9904 */ 9905 public void setTransitionVisibility(@Visibility int visibility) { 9906 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 9907 } 9908 9909 /** 9910 * Reset the flag indicating the accessibility state of the subtree rooted 9911 * at this view changed. 9912 */ 9913 void resetSubtreeAccessibilityStateChanged() { 9914 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 9915 } 9916 9917 /** 9918 * Report an accessibility action to this view's parents for delegated processing. 9919 * 9920 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 9921 * call this method to delegate an accessibility action to a supporting parent. If the parent 9922 * returns true from its 9923 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 9924 * method this method will return true to signify that the action was consumed.</p> 9925 * 9926 * <p>This method is useful for implementing nested scrolling child views. If 9927 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 9928 * a custom view implementation may invoke this method to allow a parent to consume the 9929 * scroll first. If this method returns true the custom view should skip its own scrolling 9930 * behavior.</p> 9931 * 9932 * @param action Accessibility action to delegate 9933 * @param arguments Optional action arguments 9934 * @return true if the action was consumed by a parent 9935 */ 9936 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 9937 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 9938 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 9939 return true; 9940 } 9941 } 9942 return false; 9943 } 9944 9945 /** 9946 * Performs the specified accessibility action on the view. For 9947 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 9948 * <p> 9949 * If an {@link AccessibilityDelegate} has been specified via calling 9950 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9951 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 9952 * is responsible for handling this call. 9953 * </p> 9954 * 9955 * <p>The default implementation will delegate 9956 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 9957 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 9958 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 9959 * 9960 * @param action The action to perform. 9961 * @param arguments Optional action arguments. 9962 * @return Whether the action was performed. 9963 */ 9964 public boolean performAccessibilityAction(int action, Bundle arguments) { 9965 if (mAccessibilityDelegate != null) { 9966 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 9967 } else { 9968 return performAccessibilityActionInternal(action, arguments); 9969 } 9970 } 9971 9972 /** 9973 * @see #performAccessibilityAction(int, Bundle) 9974 * 9975 * Note: Called from the default {@link AccessibilityDelegate}. 9976 * 9977 * @hide 9978 */ 9979 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 9980 if (isNestedScrollingEnabled() 9981 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 9982 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 9983 || action == R.id.accessibilityActionScrollUp 9984 || action == R.id.accessibilityActionScrollLeft 9985 || action == R.id.accessibilityActionScrollDown 9986 || action == R.id.accessibilityActionScrollRight)) { 9987 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 9988 return true; 9989 } 9990 } 9991 9992 switch (action) { 9993 case AccessibilityNodeInfo.ACTION_CLICK: { 9994 if (isClickable()) { 9995 performClick(); 9996 return true; 9997 } 9998 } break; 9999 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 10000 if (isLongClickable()) { 10001 performLongClick(); 10002 return true; 10003 } 10004 } break; 10005 case AccessibilityNodeInfo.ACTION_FOCUS: { 10006 if (!hasFocus()) { 10007 // Get out of touch mode since accessibility 10008 // wants to move focus around. 10009 getViewRootImpl().ensureTouchMode(false); 10010 return requestFocus(); 10011 } 10012 } break; 10013 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 10014 if (hasFocus()) { 10015 clearFocus(); 10016 return !isFocused(); 10017 } 10018 } break; 10019 case AccessibilityNodeInfo.ACTION_SELECT: { 10020 if (!isSelected()) { 10021 setSelected(true); 10022 return isSelected(); 10023 } 10024 } break; 10025 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 10026 if (isSelected()) { 10027 setSelected(false); 10028 return !isSelected(); 10029 } 10030 } break; 10031 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 10032 if (!isAccessibilityFocused()) { 10033 return requestAccessibilityFocus(); 10034 } 10035 } break; 10036 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 10037 if (isAccessibilityFocused()) { 10038 clearAccessibilityFocus(); 10039 return true; 10040 } 10041 } break; 10042 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 10043 if (arguments != null) { 10044 final int granularity = arguments.getInt( 10045 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10046 final boolean extendSelection = arguments.getBoolean( 10047 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10048 return traverseAtGranularity(granularity, true, extendSelection); 10049 } 10050 } break; 10051 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 10052 if (arguments != null) { 10053 final int granularity = arguments.getInt( 10054 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10055 final boolean extendSelection = arguments.getBoolean( 10056 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10057 return traverseAtGranularity(granularity, false, extendSelection); 10058 } 10059 } break; 10060 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 10061 CharSequence text = getIterableTextForAccessibility(); 10062 if (text == null) { 10063 return false; 10064 } 10065 final int start = (arguments != null) ? arguments.getInt( 10066 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 10067 final int end = (arguments != null) ? arguments.getInt( 10068 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 10069 // Only cursor position can be specified (selection length == 0) 10070 if ((getAccessibilitySelectionStart() != start 10071 || getAccessibilitySelectionEnd() != end) 10072 && (start == end)) { 10073 setAccessibilitySelection(start, end); 10074 notifyViewAccessibilityStateChangedIfNeeded( 10075 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10076 return true; 10077 } 10078 } break; 10079 case R.id.accessibilityActionShowOnScreen: { 10080 if (mAttachInfo != null) { 10081 final Rect r = mAttachInfo.mTmpInvalRect; 10082 getDrawingRect(r); 10083 return requestRectangleOnScreen(r, true); 10084 } 10085 } break; 10086 case R.id.accessibilityActionContextClick: { 10087 if (isContextClickable()) { 10088 performContextClick(); 10089 return true; 10090 } 10091 } break; 10092 } 10093 return false; 10094 } 10095 10096 private boolean traverseAtGranularity(int granularity, boolean forward, 10097 boolean extendSelection) { 10098 CharSequence text = getIterableTextForAccessibility(); 10099 if (text == null || text.length() == 0) { 10100 return false; 10101 } 10102 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 10103 if (iterator == null) { 10104 return false; 10105 } 10106 int current = getAccessibilitySelectionEnd(); 10107 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10108 current = forward ? 0 : text.length(); 10109 } 10110 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 10111 if (range == null) { 10112 return false; 10113 } 10114 final int segmentStart = range[0]; 10115 final int segmentEnd = range[1]; 10116 int selectionStart; 10117 int selectionEnd; 10118 if (extendSelection && isAccessibilitySelectionExtendable()) { 10119 selectionStart = getAccessibilitySelectionStart(); 10120 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10121 selectionStart = forward ? segmentStart : segmentEnd; 10122 } 10123 selectionEnd = forward ? segmentEnd : segmentStart; 10124 } else { 10125 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 10126 } 10127 setAccessibilitySelection(selectionStart, selectionEnd); 10128 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 10129 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 10130 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 10131 return true; 10132 } 10133 10134 /** 10135 * Gets the text reported for accessibility purposes. 10136 * 10137 * @return The accessibility text. 10138 * 10139 * @hide 10140 */ 10141 public CharSequence getIterableTextForAccessibility() { 10142 return getContentDescription(); 10143 } 10144 10145 /** 10146 * Gets whether accessibility selection can be extended. 10147 * 10148 * @return If selection is extensible. 10149 * 10150 * @hide 10151 */ 10152 public boolean isAccessibilitySelectionExtendable() { 10153 return false; 10154 } 10155 10156 /** 10157 * @hide 10158 */ 10159 public int getAccessibilitySelectionStart() { 10160 return mAccessibilityCursorPosition; 10161 } 10162 10163 /** 10164 * @hide 10165 */ 10166 public int getAccessibilitySelectionEnd() { 10167 return getAccessibilitySelectionStart(); 10168 } 10169 10170 /** 10171 * @hide 10172 */ 10173 public void setAccessibilitySelection(int start, int end) { 10174 if (start == end && end == mAccessibilityCursorPosition) { 10175 return; 10176 } 10177 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 10178 mAccessibilityCursorPosition = start; 10179 } else { 10180 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 10181 } 10182 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 10183 } 10184 10185 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 10186 int fromIndex, int toIndex) { 10187 if (mParent == null) { 10188 return; 10189 } 10190 AccessibilityEvent event = AccessibilityEvent.obtain( 10191 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 10192 onInitializeAccessibilityEvent(event); 10193 onPopulateAccessibilityEvent(event); 10194 event.setFromIndex(fromIndex); 10195 event.setToIndex(toIndex); 10196 event.setAction(action); 10197 event.setMovementGranularity(granularity); 10198 mParent.requestSendAccessibilityEvent(this, event); 10199 } 10200 10201 /** 10202 * @hide 10203 */ 10204 public TextSegmentIterator getIteratorForGranularity(int granularity) { 10205 switch (granularity) { 10206 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 10207 CharSequence text = getIterableTextForAccessibility(); 10208 if (text != null && text.length() > 0) { 10209 CharacterTextSegmentIterator iterator = 10210 CharacterTextSegmentIterator.getInstance( 10211 mContext.getResources().getConfiguration().locale); 10212 iterator.initialize(text.toString()); 10213 return iterator; 10214 } 10215 } break; 10216 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 10217 CharSequence text = getIterableTextForAccessibility(); 10218 if (text != null && text.length() > 0) { 10219 WordTextSegmentIterator iterator = 10220 WordTextSegmentIterator.getInstance( 10221 mContext.getResources().getConfiguration().locale); 10222 iterator.initialize(text.toString()); 10223 return iterator; 10224 } 10225 } break; 10226 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 10227 CharSequence text = getIterableTextForAccessibility(); 10228 if (text != null && text.length() > 0) { 10229 ParagraphTextSegmentIterator iterator = 10230 ParagraphTextSegmentIterator.getInstance(); 10231 iterator.initialize(text.toString()); 10232 return iterator; 10233 } 10234 } break; 10235 } 10236 return null; 10237 } 10238 10239 /** 10240 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 10241 * and {@link #onFinishTemporaryDetach()}. 10242 * 10243 * <p>This method always returns {@code true} when called directly or indirectly from 10244 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 10245 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 10246 * <ul> 10247 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 10248 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 10249 * </ul> 10250 * </p> 10251 * 10252 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 10253 * and {@link #onFinishTemporaryDetach()}. 10254 */ 10255 public final boolean isTemporarilyDetached() { 10256 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 10257 } 10258 10259 /** 10260 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 10261 * a container View. 10262 */ 10263 @CallSuper 10264 public void dispatchStartTemporaryDetach() { 10265 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 10266 onStartTemporaryDetach(); 10267 } 10268 10269 /** 10270 * This is called when a container is going to temporarily detach a child, with 10271 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 10272 * It will either be followed by {@link #onFinishTemporaryDetach()} or 10273 * {@link #onDetachedFromWindow()} when the container is done. 10274 */ 10275 public void onStartTemporaryDetach() { 10276 removeUnsetPressCallback(); 10277 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 10278 } 10279 10280 /** 10281 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 10282 * a container View. 10283 */ 10284 @CallSuper 10285 public void dispatchFinishTemporaryDetach() { 10286 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 10287 onFinishTemporaryDetach(); 10288 if (hasWindowFocus() && hasFocus()) { 10289 InputMethodManager.getInstance().focusIn(this); 10290 } 10291 } 10292 10293 /** 10294 * Called after {@link #onStartTemporaryDetach} when the container is done 10295 * changing the view. 10296 */ 10297 public void onFinishTemporaryDetach() { 10298 } 10299 10300 /** 10301 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 10302 * for this view's window. Returns null if the view is not currently attached 10303 * to the window. Normally you will not need to use this directly, but 10304 * just use the standard high-level event callbacks like 10305 * {@link #onKeyDown(int, KeyEvent)}. 10306 */ 10307 public KeyEvent.DispatcherState getKeyDispatcherState() { 10308 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 10309 } 10310 10311 /** 10312 * Dispatch a key event before it is processed by any input method 10313 * associated with the view hierarchy. This can be used to intercept 10314 * key events in special situations before the IME consumes them; a 10315 * typical example would be handling the BACK key to update the application's 10316 * UI instead of allowing the IME to see it and close itself. 10317 * 10318 * @param event The key event to be dispatched. 10319 * @return True if the event was handled, false otherwise. 10320 */ 10321 public boolean dispatchKeyEventPreIme(KeyEvent event) { 10322 return onKeyPreIme(event.getKeyCode(), event); 10323 } 10324 10325 /** 10326 * Dispatch a key event to the next view on the focus path. This path runs 10327 * from the top of the view tree down to the currently focused view. If this 10328 * view has focus, it will dispatch to itself. Otherwise it will dispatch 10329 * the next node down the focus path. This method also fires any key 10330 * listeners. 10331 * 10332 * @param event The key event to be dispatched. 10333 * @return True if the event was handled, false otherwise. 10334 */ 10335 public boolean dispatchKeyEvent(KeyEvent event) { 10336 if (mInputEventConsistencyVerifier != null) { 10337 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 10338 } 10339 10340 // Give any attached key listener a first crack at the event. 10341 //noinspection SimplifiableIfStatement 10342 ListenerInfo li = mListenerInfo; 10343 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 10344 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 10345 return true; 10346 } 10347 10348 if (event.dispatch(this, mAttachInfo != null 10349 ? mAttachInfo.mKeyDispatchState : null, this)) { 10350 return true; 10351 } 10352 10353 if (mInputEventConsistencyVerifier != null) { 10354 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10355 } 10356 return false; 10357 } 10358 10359 /** 10360 * Dispatches a key shortcut event. 10361 * 10362 * @param event The key event to be dispatched. 10363 * @return True if the event was handled by the view, false otherwise. 10364 */ 10365 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 10366 return onKeyShortcut(event.getKeyCode(), event); 10367 } 10368 10369 /** 10370 * Pass the touch screen motion event down to the target view, or this 10371 * view if it is the target. 10372 * 10373 * @param event The motion event to be dispatched. 10374 * @return True if the event was handled by the view, false otherwise. 10375 */ 10376 public boolean dispatchTouchEvent(MotionEvent event) { 10377 // If the event should be handled by accessibility focus first. 10378 if (event.isTargetAccessibilityFocus()) { 10379 // We don't have focus or no virtual descendant has it, do not handle the event. 10380 if (!isAccessibilityFocusedViewOrHost()) { 10381 return false; 10382 } 10383 // We have focus and got the event, then use normal event dispatch. 10384 event.setTargetAccessibilityFocus(false); 10385 } 10386 10387 boolean result = false; 10388 10389 if (mInputEventConsistencyVerifier != null) { 10390 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 10391 } 10392 10393 final int actionMasked = event.getActionMasked(); 10394 if (actionMasked == MotionEvent.ACTION_DOWN) { 10395 // Defensive cleanup for new gesture 10396 stopNestedScroll(); 10397 } 10398 10399 if (onFilterTouchEventForSecurity(event)) { 10400 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 10401 result = true; 10402 } 10403 //noinspection SimplifiableIfStatement 10404 ListenerInfo li = mListenerInfo; 10405 if (li != null && li.mOnTouchListener != null 10406 && (mViewFlags & ENABLED_MASK) == ENABLED 10407 && li.mOnTouchListener.onTouch(this, event)) { 10408 result = true; 10409 } 10410 10411 if (!result && onTouchEvent(event)) { 10412 result = true; 10413 } 10414 } 10415 10416 if (!result && mInputEventConsistencyVerifier != null) { 10417 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10418 } 10419 10420 // Clean up after nested scrolls if this is the end of a gesture; 10421 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 10422 // of the gesture. 10423 if (actionMasked == MotionEvent.ACTION_UP || 10424 actionMasked == MotionEvent.ACTION_CANCEL || 10425 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 10426 stopNestedScroll(); 10427 } 10428 10429 return result; 10430 } 10431 10432 boolean isAccessibilityFocusedViewOrHost() { 10433 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 10434 .getAccessibilityFocusedHost() == this); 10435 } 10436 10437 /** 10438 * Filter the touch event to apply security policies. 10439 * 10440 * @param event The motion event to be filtered. 10441 * @return True if the event should be dispatched, false if the event should be dropped. 10442 * 10443 * @see #getFilterTouchesWhenObscured 10444 */ 10445 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 10446 //noinspection RedundantIfStatement 10447 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 10448 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 10449 // Window is obscured, drop this touch. 10450 return false; 10451 } 10452 return true; 10453 } 10454 10455 /** 10456 * Pass a trackball motion event down to the focused view. 10457 * 10458 * @param event The motion event to be dispatched. 10459 * @return True if the event was handled by the view, false otherwise. 10460 */ 10461 public boolean dispatchTrackballEvent(MotionEvent event) { 10462 if (mInputEventConsistencyVerifier != null) { 10463 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 10464 } 10465 10466 return onTrackballEvent(event); 10467 } 10468 10469 /** 10470 * Dispatch a generic motion event. 10471 * <p> 10472 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 10473 * are delivered to the view under the pointer. All other generic motion events are 10474 * delivered to the focused view. Hover events are handled specially and are delivered 10475 * to {@link #onHoverEvent(MotionEvent)}. 10476 * </p> 10477 * 10478 * @param event The motion event to be dispatched. 10479 * @return True if the event was handled by the view, false otherwise. 10480 */ 10481 public boolean dispatchGenericMotionEvent(MotionEvent event) { 10482 if (mInputEventConsistencyVerifier != null) { 10483 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 10484 } 10485 10486 final int source = event.getSource(); 10487 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 10488 final int action = event.getAction(); 10489 if (action == MotionEvent.ACTION_HOVER_ENTER 10490 || action == MotionEvent.ACTION_HOVER_MOVE 10491 || action == MotionEvent.ACTION_HOVER_EXIT) { 10492 if (dispatchHoverEvent(event)) { 10493 return true; 10494 } 10495 } else if (dispatchGenericPointerEvent(event)) { 10496 return true; 10497 } 10498 } else if (dispatchGenericFocusedEvent(event)) { 10499 return true; 10500 } 10501 10502 if (dispatchGenericMotionEventInternal(event)) { 10503 return true; 10504 } 10505 10506 if (mInputEventConsistencyVerifier != null) { 10507 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10508 } 10509 return false; 10510 } 10511 10512 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 10513 //noinspection SimplifiableIfStatement 10514 ListenerInfo li = mListenerInfo; 10515 if (li != null && li.mOnGenericMotionListener != null 10516 && (mViewFlags & ENABLED_MASK) == ENABLED 10517 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 10518 return true; 10519 } 10520 10521 if (onGenericMotionEvent(event)) { 10522 return true; 10523 } 10524 10525 final int actionButton = event.getActionButton(); 10526 switch (event.getActionMasked()) { 10527 case MotionEvent.ACTION_BUTTON_PRESS: 10528 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 10529 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10530 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10531 if (performContextClick(event.getX(), event.getY())) { 10532 mInContextButtonPress = true; 10533 setPressed(true, event.getX(), event.getY()); 10534 removeTapCallback(); 10535 removeLongPressCallback(); 10536 return true; 10537 } 10538 } 10539 break; 10540 10541 case MotionEvent.ACTION_BUTTON_RELEASE: 10542 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10543 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10544 mInContextButtonPress = false; 10545 mIgnoreNextUpEvent = true; 10546 } 10547 break; 10548 } 10549 10550 if (mInputEventConsistencyVerifier != null) { 10551 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10552 } 10553 return false; 10554 } 10555 10556 /** 10557 * Dispatch a hover event. 10558 * <p> 10559 * Do not call this method directly. 10560 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10561 * </p> 10562 * 10563 * @param event The motion event to be dispatched. 10564 * @return True if the event was handled by the view, false otherwise. 10565 */ 10566 protected boolean dispatchHoverEvent(MotionEvent event) { 10567 ListenerInfo li = mListenerInfo; 10568 //noinspection SimplifiableIfStatement 10569 if (li != null && li.mOnHoverListener != null 10570 && (mViewFlags & ENABLED_MASK) == ENABLED 10571 && li.mOnHoverListener.onHover(this, event)) { 10572 return true; 10573 } 10574 10575 return onHoverEvent(event); 10576 } 10577 10578 /** 10579 * Returns true if the view has a child to which it has recently sent 10580 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 10581 * it does not have a hovered child, then it must be the innermost hovered view. 10582 * @hide 10583 */ 10584 protected boolean hasHoveredChild() { 10585 return false; 10586 } 10587 10588 /** 10589 * Dispatch a generic motion event to the view under the first pointer. 10590 * <p> 10591 * Do not call this method directly. 10592 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10593 * </p> 10594 * 10595 * @param event The motion event to be dispatched. 10596 * @return True if the event was handled by the view, false otherwise. 10597 */ 10598 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 10599 return false; 10600 } 10601 10602 /** 10603 * Dispatch a generic motion event to the currently focused view. 10604 * <p> 10605 * Do not call this method directly. 10606 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10607 * </p> 10608 * 10609 * @param event The motion event to be dispatched. 10610 * @return True if the event was handled by the view, false otherwise. 10611 */ 10612 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 10613 return false; 10614 } 10615 10616 /** 10617 * Dispatch a pointer event. 10618 * <p> 10619 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 10620 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 10621 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 10622 * and should not be expected to handle other pointing device features. 10623 * </p> 10624 * 10625 * @param event The motion event to be dispatched. 10626 * @return True if the event was handled by the view, false otherwise. 10627 * @hide 10628 */ 10629 public final boolean dispatchPointerEvent(MotionEvent event) { 10630 if (event.isTouchEvent()) { 10631 return dispatchTouchEvent(event); 10632 } else { 10633 return dispatchGenericMotionEvent(event); 10634 } 10635 } 10636 10637 /** 10638 * Called when the window containing this view gains or loses window focus. 10639 * ViewGroups should override to route to their children. 10640 * 10641 * @param hasFocus True if the window containing this view now has focus, 10642 * false otherwise. 10643 */ 10644 public void dispatchWindowFocusChanged(boolean hasFocus) { 10645 onWindowFocusChanged(hasFocus); 10646 } 10647 10648 /** 10649 * Called when the window containing this view gains or loses focus. Note 10650 * that this is separate from view focus: to receive key events, both 10651 * your view and its window must have focus. If a window is displayed 10652 * on top of yours that takes input focus, then your own window will lose 10653 * focus but the view focus will remain unchanged. 10654 * 10655 * @param hasWindowFocus True if the window containing this view now has 10656 * focus, false otherwise. 10657 */ 10658 public void onWindowFocusChanged(boolean hasWindowFocus) { 10659 InputMethodManager imm = InputMethodManager.peekInstance(); 10660 if (!hasWindowFocus) { 10661 if (isPressed()) { 10662 setPressed(false); 10663 } 10664 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10665 imm.focusOut(this); 10666 } 10667 removeLongPressCallback(); 10668 removeTapCallback(); 10669 onFocusLost(); 10670 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10671 imm.focusIn(this); 10672 } 10673 refreshDrawableState(); 10674 } 10675 10676 /** 10677 * Returns true if this view is in a window that currently has window focus. 10678 * Note that this is not the same as the view itself having focus. 10679 * 10680 * @return True if this view is in a window that currently has window focus. 10681 */ 10682 public boolean hasWindowFocus() { 10683 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 10684 } 10685 10686 /** 10687 * Dispatch a view visibility change down the view hierarchy. 10688 * ViewGroups should override to route to their children. 10689 * @param changedView The view whose visibility changed. Could be 'this' or 10690 * an ancestor view. 10691 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 10692 * {@link #INVISIBLE} or {@link #GONE}. 10693 */ 10694 protected void dispatchVisibilityChanged(@NonNull View changedView, 10695 @Visibility int visibility) { 10696 onVisibilityChanged(changedView, visibility); 10697 } 10698 10699 /** 10700 * Called when the visibility of the view or an ancestor of the view has 10701 * changed. 10702 * 10703 * @param changedView The view whose visibility changed. May be 10704 * {@code this} or an ancestor view. 10705 * @param visibility The new visibility, one of {@link #VISIBLE}, 10706 * {@link #INVISIBLE} or {@link #GONE}. 10707 */ 10708 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 10709 } 10710 10711 /** 10712 * Dispatch a hint about whether this view is displayed. For instance, when 10713 * a View moves out of the screen, it might receives a display hint indicating 10714 * the view is not displayed. Applications should not <em>rely</em> on this hint 10715 * as there is no guarantee that they will receive one. 10716 * 10717 * @param hint A hint about whether or not this view is displayed: 10718 * {@link #VISIBLE} or {@link #INVISIBLE}. 10719 */ 10720 public void dispatchDisplayHint(@Visibility int hint) { 10721 onDisplayHint(hint); 10722 } 10723 10724 /** 10725 * Gives this view a hint about whether is displayed or not. For instance, when 10726 * a View moves out of the screen, it might receives a display hint indicating 10727 * the view is not displayed. Applications should not <em>rely</em> on this hint 10728 * as there is no guarantee that they will receive one. 10729 * 10730 * @param hint A hint about whether or not this view is displayed: 10731 * {@link #VISIBLE} or {@link #INVISIBLE}. 10732 */ 10733 protected void onDisplayHint(@Visibility int hint) { 10734 } 10735 10736 /** 10737 * Dispatch a window visibility change down the view hierarchy. 10738 * ViewGroups should override to route to their children. 10739 * 10740 * @param visibility The new visibility of the window. 10741 * 10742 * @see #onWindowVisibilityChanged(int) 10743 */ 10744 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 10745 onWindowVisibilityChanged(visibility); 10746 } 10747 10748 /** 10749 * Called when the window containing has change its visibility 10750 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 10751 * that this tells you whether or not your window is being made visible 10752 * to the window manager; this does <em>not</em> tell you whether or not 10753 * your window is obscured by other windows on the screen, even if it 10754 * is itself visible. 10755 * 10756 * @param visibility The new visibility of the window. 10757 */ 10758 protected void onWindowVisibilityChanged(@Visibility int visibility) { 10759 if (visibility == VISIBLE) { 10760 initialAwakenScrollBars(); 10761 } 10762 } 10763 10764 /** 10765 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 10766 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 10767 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 10768 * 10769 * @param isVisible true if this view's visibility to the user is uninterrupted by its 10770 * ancestors or by window visibility 10771 * @return true if this view is visible to the user, not counting clipping or overlapping 10772 */ 10773 boolean dispatchVisibilityAggregated(boolean isVisible) { 10774 final boolean thisVisible = getVisibility() == VISIBLE; 10775 // If we're not visible but something is telling us we are, ignore it. 10776 if (thisVisible || !isVisible) { 10777 onVisibilityAggregated(isVisible); 10778 } 10779 return thisVisible && isVisible; 10780 } 10781 10782 /** 10783 * Called when the user-visibility of this View is potentially affected by a change 10784 * to this view itself, an ancestor view or the window this view is attached to. 10785 * 10786 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 10787 * and this view's window is also visible 10788 */ 10789 @CallSuper 10790 public void onVisibilityAggregated(boolean isVisible) { 10791 if (isVisible && mAttachInfo != null) { 10792 initialAwakenScrollBars(); 10793 } 10794 10795 final Drawable dr = mBackground; 10796 if (dr != null && isVisible != dr.isVisible()) { 10797 dr.setVisible(isVisible, false); 10798 } 10799 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 10800 if (fg != null && isVisible != fg.isVisible()) { 10801 fg.setVisible(isVisible, false); 10802 } 10803 } 10804 10805 /** 10806 * Returns the current visibility of the window this view is attached to 10807 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 10808 * 10809 * @return Returns the current visibility of the view's window. 10810 */ 10811 @Visibility 10812 public int getWindowVisibility() { 10813 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 10814 } 10815 10816 /** 10817 * Retrieve the overall visible display size in which the window this view is 10818 * attached to has been positioned in. This takes into account screen 10819 * decorations above the window, for both cases where the window itself 10820 * is being position inside of them or the window is being placed under 10821 * then and covered insets are used for the window to position its content 10822 * inside. In effect, this tells you the available area where content can 10823 * be placed and remain visible to users. 10824 * 10825 * <p>This function requires an IPC back to the window manager to retrieve 10826 * the requested information, so should not be used in performance critical 10827 * code like drawing. 10828 * 10829 * @param outRect Filled in with the visible display frame. If the view 10830 * is not attached to a window, this is simply the raw display size. 10831 */ 10832 public void getWindowVisibleDisplayFrame(Rect outRect) { 10833 if (mAttachInfo != null) { 10834 try { 10835 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 10836 } catch (RemoteException e) { 10837 return; 10838 } 10839 // XXX This is really broken, and probably all needs to be done 10840 // in the window manager, and we need to know more about whether 10841 // we want the area behind or in front of the IME. 10842 final Rect insets = mAttachInfo.mVisibleInsets; 10843 outRect.left += insets.left; 10844 outRect.top += insets.top; 10845 outRect.right -= insets.right; 10846 outRect.bottom -= insets.bottom; 10847 return; 10848 } 10849 // The view is not attached to a display so we don't have a context. 10850 // Make a best guess about the display size. 10851 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 10852 d.getRectSize(outRect); 10853 } 10854 10855 /** 10856 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 10857 * is currently in without any insets. 10858 * 10859 * @hide 10860 */ 10861 public void getWindowDisplayFrame(Rect outRect) { 10862 if (mAttachInfo != null) { 10863 try { 10864 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 10865 } catch (RemoteException e) { 10866 return; 10867 } 10868 return; 10869 } 10870 // The view is not attached to a display so we don't have a context. 10871 // Make a best guess about the display size. 10872 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 10873 d.getRectSize(outRect); 10874 } 10875 10876 /** 10877 * Dispatch a notification about a resource configuration change down 10878 * the view hierarchy. 10879 * ViewGroups should override to route to their children. 10880 * 10881 * @param newConfig The new resource configuration. 10882 * 10883 * @see #onConfigurationChanged(android.content.res.Configuration) 10884 */ 10885 public void dispatchConfigurationChanged(Configuration newConfig) { 10886 onConfigurationChanged(newConfig); 10887 } 10888 10889 /** 10890 * Called when the current configuration of the resources being used 10891 * by the application have changed. You can use this to decide when 10892 * to reload resources that can changed based on orientation and other 10893 * configuration characteristics. You only need to use this if you are 10894 * not relying on the normal {@link android.app.Activity} mechanism of 10895 * recreating the activity instance upon a configuration change. 10896 * 10897 * @param newConfig The new resource configuration. 10898 */ 10899 protected void onConfigurationChanged(Configuration newConfig) { 10900 } 10901 10902 /** 10903 * Private function to aggregate all per-view attributes in to the view 10904 * root. 10905 */ 10906 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 10907 performCollectViewAttributes(attachInfo, visibility); 10908 } 10909 10910 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 10911 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 10912 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 10913 attachInfo.mKeepScreenOn = true; 10914 } 10915 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 10916 ListenerInfo li = mListenerInfo; 10917 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 10918 attachInfo.mHasSystemUiListeners = true; 10919 } 10920 } 10921 } 10922 10923 void needGlobalAttributesUpdate(boolean force) { 10924 final AttachInfo ai = mAttachInfo; 10925 if (ai != null && !ai.mRecomputeGlobalAttributes) { 10926 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 10927 || ai.mHasSystemUiListeners) { 10928 ai.mRecomputeGlobalAttributes = true; 10929 } 10930 } 10931 } 10932 10933 /** 10934 * Returns whether the device is currently in touch mode. Touch mode is entered 10935 * once the user begins interacting with the device by touch, and affects various 10936 * things like whether focus is always visible to the user. 10937 * 10938 * @return Whether the device is in touch mode. 10939 */ 10940 @ViewDebug.ExportedProperty 10941 public boolean isInTouchMode() { 10942 if (mAttachInfo != null) { 10943 return mAttachInfo.mInTouchMode; 10944 } else { 10945 return ViewRootImpl.isInTouchMode(); 10946 } 10947 } 10948 10949 /** 10950 * Returns the context the view is running in, through which it can 10951 * access the current theme, resources, etc. 10952 * 10953 * @return The view's Context. 10954 */ 10955 @ViewDebug.CapturedViewProperty 10956 public final Context getContext() { 10957 return mContext; 10958 } 10959 10960 /** 10961 * Handle a key event before it is processed by any input method 10962 * associated with the view hierarchy. This can be used to intercept 10963 * key events in special situations before the IME consumes them; a 10964 * typical example would be handling the BACK key to update the application's 10965 * UI instead of allowing the IME to see it and close itself. 10966 * 10967 * @param keyCode The value in event.getKeyCode(). 10968 * @param event Description of the key event. 10969 * @return If you handled the event, return true. If you want to allow the 10970 * event to be handled by the next receiver, return false. 10971 */ 10972 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 10973 return false; 10974 } 10975 10976 /** 10977 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 10978 * KeyEvent.Callback.onKeyDown()}: perform press of the view 10979 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 10980 * is released, if the view is enabled and clickable. 10981 * <p> 10982 * Key presses in software keyboards will generally NOT trigger this 10983 * listener, although some may elect to do so in some situations. Do not 10984 * rely on this to catch software key presses. 10985 * 10986 * @param keyCode a key code that represents the button pressed, from 10987 * {@link android.view.KeyEvent} 10988 * @param event the KeyEvent object that defines the button action 10989 */ 10990 public boolean onKeyDown(int keyCode, KeyEvent event) { 10991 if (KeyEvent.isConfirmKey(keyCode)) { 10992 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 10993 return true; 10994 } 10995 10996 if (event.getRepeatCount() == 0) { 10997 // Long clickable items don't necessarily have to be clickable. 10998 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 10999 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 11000 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 11001 // For the purposes of menu anchoring and drawable hotspots, 11002 // key events are considered to be at the center of the view. 11003 final float x = getWidth() / 2f; 11004 final float y = getHeight() / 2f; 11005 if (clickable) { 11006 setPressed(true, x, y); 11007 } 11008 checkForLongClick(0, x, y); 11009 return true; 11010 } 11011 } 11012 } 11013 11014 return false; 11015 } 11016 11017 /** 11018 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 11019 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 11020 * the event). 11021 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11022 * although some may elect to do so in some situations. Do not rely on this to 11023 * catch software key presses. 11024 */ 11025 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 11026 return false; 11027 } 11028 11029 /** 11030 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 11031 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 11032 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 11033 * or {@link KeyEvent#KEYCODE_SPACE} is released. 11034 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11035 * although some may elect to do so in some situations. Do not rely on this to 11036 * catch software key presses. 11037 * 11038 * @param keyCode A key code that represents the button pressed, from 11039 * {@link android.view.KeyEvent}. 11040 * @param event The KeyEvent object that defines the button action. 11041 */ 11042 public boolean onKeyUp(int keyCode, KeyEvent event) { 11043 if (KeyEvent.isConfirmKey(keyCode)) { 11044 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11045 return true; 11046 } 11047 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 11048 setPressed(false); 11049 11050 if (!mHasPerformedLongPress) { 11051 // This is a tap, so remove the longpress check 11052 removeLongPressCallback(); 11053 return performClick(); 11054 } 11055 } 11056 } 11057 return false; 11058 } 11059 11060 /** 11061 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 11062 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 11063 * the event). 11064 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11065 * although some may elect to do so in some situations. Do not rely on this to 11066 * catch software key presses. 11067 * 11068 * @param keyCode A key code that represents the button pressed, from 11069 * {@link android.view.KeyEvent}. 11070 * @param repeatCount The number of times the action was made. 11071 * @param event The KeyEvent object that defines the button action. 11072 */ 11073 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 11074 return false; 11075 } 11076 11077 /** 11078 * Called on the focused view when a key shortcut event is not handled. 11079 * Override this method to implement local key shortcuts for the View. 11080 * Key shortcuts can also be implemented by setting the 11081 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 11082 * 11083 * @param keyCode The value in event.getKeyCode(). 11084 * @param event Description of the key event. 11085 * @return If you handled the event, return true. If you want to allow the 11086 * event to be handled by the next receiver, return false. 11087 */ 11088 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 11089 return false; 11090 } 11091 11092 /** 11093 * Check whether the called view is a text editor, in which case it 11094 * would make sense to automatically display a soft input window for 11095 * it. Subclasses should override this if they implement 11096 * {@link #onCreateInputConnection(EditorInfo)} to return true if 11097 * a call on that method would return a non-null InputConnection, and 11098 * they are really a first-class editor that the user would normally 11099 * start typing on when the go into a window containing your view. 11100 * 11101 * <p>The default implementation always returns false. This does 11102 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 11103 * will not be called or the user can not otherwise perform edits on your 11104 * view; it is just a hint to the system that this is not the primary 11105 * purpose of this view. 11106 * 11107 * @return Returns true if this view is a text editor, else false. 11108 */ 11109 public boolean onCheckIsTextEditor() { 11110 return false; 11111 } 11112 11113 /** 11114 * Create a new InputConnection for an InputMethod to interact 11115 * with the view. The default implementation returns null, since it doesn't 11116 * support input methods. You can override this to implement such support. 11117 * This is only needed for views that take focus and text input. 11118 * 11119 * <p>When implementing this, you probably also want to implement 11120 * {@link #onCheckIsTextEditor()} to indicate you will return a 11121 * non-null InputConnection.</p> 11122 * 11123 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 11124 * object correctly and in its entirety, so that the connected IME can rely 11125 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 11126 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 11127 * must be filled in with the correct cursor position for IMEs to work correctly 11128 * with your application.</p> 11129 * 11130 * @param outAttrs Fill in with attribute information about the connection. 11131 */ 11132 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 11133 return null; 11134 } 11135 11136 /** 11137 * Called by the {@link android.view.inputmethod.InputMethodManager} 11138 * when a view who is not the current 11139 * input connection target is trying to make a call on the manager. The 11140 * default implementation returns false; you can override this to return 11141 * true for certain views if you are performing InputConnection proxying 11142 * to them. 11143 * @param view The View that is making the InputMethodManager call. 11144 * @return Return true to allow the call, false to reject. 11145 */ 11146 public boolean checkInputConnectionProxy(View view) { 11147 return false; 11148 } 11149 11150 /** 11151 * Show the context menu for this view. It is not safe to hold on to the 11152 * menu after returning from this method. 11153 * 11154 * You should normally not overload this method. Overload 11155 * {@link #onCreateContextMenu(ContextMenu)} or define an 11156 * {@link OnCreateContextMenuListener} to add items to the context menu. 11157 * 11158 * @param menu The context menu to populate 11159 */ 11160 public void createContextMenu(ContextMenu menu) { 11161 ContextMenuInfo menuInfo = getContextMenuInfo(); 11162 11163 // Sets the current menu info so all items added to menu will have 11164 // my extra info set. 11165 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 11166 11167 onCreateContextMenu(menu); 11168 ListenerInfo li = mListenerInfo; 11169 if (li != null && li.mOnCreateContextMenuListener != null) { 11170 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 11171 } 11172 11173 // Clear the extra information so subsequent items that aren't mine don't 11174 // have my extra info. 11175 ((MenuBuilder)menu).setCurrentMenuInfo(null); 11176 11177 if (mParent != null) { 11178 mParent.createContextMenu(menu); 11179 } 11180 } 11181 11182 /** 11183 * Views should implement this if they have extra information to associate 11184 * with the context menu. The return result is supplied as a parameter to 11185 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 11186 * callback. 11187 * 11188 * @return Extra information about the item for which the context menu 11189 * should be shown. This information will vary across different 11190 * subclasses of View. 11191 */ 11192 protected ContextMenuInfo getContextMenuInfo() { 11193 return null; 11194 } 11195 11196 /** 11197 * Views should implement this if the view itself is going to add items to 11198 * the context menu. 11199 * 11200 * @param menu the context menu to populate 11201 */ 11202 protected void onCreateContextMenu(ContextMenu menu) { 11203 } 11204 11205 /** 11206 * Implement this method to handle trackball motion events. The 11207 * <em>relative</em> movement of the trackball since the last event 11208 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 11209 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 11210 * that a movement of 1 corresponds to the user pressing one DPAD key (so 11211 * they will often be fractional values, representing the more fine-grained 11212 * movement information available from a trackball). 11213 * 11214 * @param event The motion event. 11215 * @return True if the event was handled, false otherwise. 11216 */ 11217 public boolean onTrackballEvent(MotionEvent event) { 11218 return false; 11219 } 11220 11221 /** 11222 * Implement this method to handle generic motion events. 11223 * <p> 11224 * Generic motion events describe joystick movements, mouse hovers, track pad 11225 * touches, scroll wheel movements and other input events. The 11226 * {@link MotionEvent#getSource() source} of the motion event specifies 11227 * the class of input that was received. Implementations of this method 11228 * must examine the bits in the source before processing the event. 11229 * The following code example shows how this is done. 11230 * </p><p> 11231 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11232 * are delivered to the view under the pointer. All other generic motion events are 11233 * delivered to the focused view. 11234 * </p> 11235 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 11236 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 11237 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 11238 * // process the joystick movement... 11239 * return true; 11240 * } 11241 * } 11242 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 11243 * switch (event.getAction()) { 11244 * case MotionEvent.ACTION_HOVER_MOVE: 11245 * // process the mouse hover movement... 11246 * return true; 11247 * case MotionEvent.ACTION_SCROLL: 11248 * // process the scroll wheel movement... 11249 * return true; 11250 * } 11251 * } 11252 * return super.onGenericMotionEvent(event); 11253 * }</pre> 11254 * 11255 * @param event The generic motion event being processed. 11256 * @return True if the event was handled, false otherwise. 11257 */ 11258 public boolean onGenericMotionEvent(MotionEvent event) { 11259 return false; 11260 } 11261 11262 /** 11263 * Implement this method to handle hover events. 11264 * <p> 11265 * This method is called whenever a pointer is hovering into, over, or out of the 11266 * bounds of a view and the view is not currently being touched. 11267 * Hover events are represented as pointer events with action 11268 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 11269 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 11270 * </p> 11271 * <ul> 11272 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 11273 * when the pointer enters the bounds of the view.</li> 11274 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 11275 * when the pointer has already entered the bounds of the view and has moved.</li> 11276 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 11277 * when the pointer has exited the bounds of the view or when the pointer is 11278 * about to go down due to a button click, tap, or similar user action that 11279 * causes the view to be touched.</li> 11280 * </ul> 11281 * <p> 11282 * The view should implement this method to return true to indicate that it is 11283 * handling the hover event, such as by changing its drawable state. 11284 * </p><p> 11285 * The default implementation calls {@link #setHovered} to update the hovered state 11286 * of the view when a hover enter or hover exit event is received, if the view 11287 * is enabled and is clickable. The default implementation also sends hover 11288 * accessibility events. 11289 * </p> 11290 * 11291 * @param event The motion event that describes the hover. 11292 * @return True if the view handled the hover event. 11293 * 11294 * @see #isHovered 11295 * @see #setHovered 11296 * @see #onHoverChanged 11297 */ 11298 public boolean onHoverEvent(MotionEvent event) { 11299 // The root view may receive hover (or touch) events that are outside the bounds of 11300 // the window. This code ensures that we only send accessibility events for 11301 // hovers that are actually within the bounds of the root view. 11302 final int action = event.getActionMasked(); 11303 if (!mSendingHoverAccessibilityEvents) { 11304 if ((action == MotionEvent.ACTION_HOVER_ENTER 11305 || action == MotionEvent.ACTION_HOVER_MOVE) 11306 && !hasHoveredChild() 11307 && pointInView(event.getX(), event.getY())) { 11308 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 11309 mSendingHoverAccessibilityEvents = true; 11310 } 11311 } else { 11312 if (action == MotionEvent.ACTION_HOVER_EXIT 11313 || (action == MotionEvent.ACTION_MOVE 11314 && !pointInView(event.getX(), event.getY()))) { 11315 mSendingHoverAccessibilityEvents = false; 11316 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 11317 } 11318 } 11319 11320 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 11321 && event.isFromSource(InputDevice.SOURCE_MOUSE) 11322 && isOnScrollbar(event.getX(), event.getY())) { 11323 awakenScrollBars(); 11324 } 11325 if (isHoverable()) { 11326 switch (action) { 11327 case MotionEvent.ACTION_HOVER_ENTER: 11328 setHovered(true); 11329 break; 11330 case MotionEvent.ACTION_HOVER_EXIT: 11331 setHovered(false); 11332 break; 11333 } 11334 11335 // Dispatch the event to onGenericMotionEvent before returning true. 11336 // This is to provide compatibility with existing applications that 11337 // handled HOVER_MOVE events in onGenericMotionEvent and that would 11338 // break because of the new default handling for hoverable views 11339 // in onHoverEvent. 11340 // Note that onGenericMotionEvent will be called by default when 11341 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 11342 dispatchGenericMotionEventInternal(event); 11343 // The event was already handled by calling setHovered(), so always 11344 // return true. 11345 return true; 11346 } 11347 11348 return false; 11349 } 11350 11351 /** 11352 * Returns true if the view should handle {@link #onHoverEvent} 11353 * by calling {@link #setHovered} to change its hovered state. 11354 * 11355 * @return True if the view is hoverable. 11356 */ 11357 private boolean isHoverable() { 11358 final int viewFlags = mViewFlags; 11359 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11360 return false; 11361 } 11362 11363 return (viewFlags & CLICKABLE) == CLICKABLE 11364 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 11365 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11366 } 11367 11368 /** 11369 * Returns true if the view is currently hovered. 11370 * 11371 * @return True if the view is currently hovered. 11372 * 11373 * @see #setHovered 11374 * @see #onHoverChanged 11375 */ 11376 @ViewDebug.ExportedProperty 11377 public boolean isHovered() { 11378 return (mPrivateFlags & PFLAG_HOVERED) != 0; 11379 } 11380 11381 /** 11382 * Sets whether the view is currently hovered. 11383 * <p> 11384 * Calling this method also changes the drawable state of the view. This 11385 * enables the view to react to hover by using different drawable resources 11386 * to change its appearance. 11387 * </p><p> 11388 * The {@link #onHoverChanged} method is called when the hovered state changes. 11389 * </p> 11390 * 11391 * @param hovered True if the view is hovered. 11392 * 11393 * @see #isHovered 11394 * @see #onHoverChanged 11395 */ 11396 public void setHovered(boolean hovered) { 11397 if (hovered) { 11398 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 11399 mPrivateFlags |= PFLAG_HOVERED; 11400 refreshDrawableState(); 11401 onHoverChanged(true); 11402 } 11403 } else { 11404 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 11405 mPrivateFlags &= ~PFLAG_HOVERED; 11406 refreshDrawableState(); 11407 onHoverChanged(false); 11408 } 11409 } 11410 } 11411 11412 /** 11413 * Implement this method to handle hover state changes. 11414 * <p> 11415 * This method is called whenever the hover state changes as a result of a 11416 * call to {@link #setHovered}. 11417 * </p> 11418 * 11419 * @param hovered The current hover state, as returned by {@link #isHovered}. 11420 * 11421 * @see #isHovered 11422 * @see #setHovered 11423 */ 11424 public void onHoverChanged(boolean hovered) { 11425 } 11426 11427 /** 11428 * Handles scroll bar dragging by mouse input. 11429 * 11430 * @hide 11431 * @param event The motion event. 11432 * 11433 * @return true if the event was handled as a scroll bar dragging, false otherwise. 11434 */ 11435 protected boolean handleScrollBarDragging(MotionEvent event) { 11436 if (mScrollCache == null) { 11437 return false; 11438 } 11439 final float x = event.getX(); 11440 final float y = event.getY(); 11441 final int action = event.getAction(); 11442 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 11443 && action != MotionEvent.ACTION_DOWN) 11444 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 11445 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 11446 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11447 return false; 11448 } 11449 11450 switch (action) { 11451 case MotionEvent.ACTION_MOVE: 11452 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 11453 return false; 11454 } 11455 if (mScrollCache.mScrollBarDraggingState 11456 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 11457 final Rect bounds = mScrollCache.mScrollBarBounds; 11458 getVerticalScrollBarBounds(bounds); 11459 final int range = computeVerticalScrollRange(); 11460 final int offset = computeVerticalScrollOffset(); 11461 final int extent = computeVerticalScrollExtent(); 11462 11463 final int thumbLength = ScrollBarUtils.getThumbLength( 11464 bounds.height(), bounds.width(), extent, range); 11465 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11466 bounds.height(), thumbLength, extent, range, offset); 11467 11468 final float diff = y - mScrollCache.mScrollBarDraggingPos; 11469 final float maxThumbOffset = bounds.height() - thumbLength; 11470 final float newThumbOffset = 11471 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11472 final int height = getHeight(); 11473 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11474 && height > 0 && extent > 0) { 11475 final int newY = Math.round((range - extent) 11476 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 11477 if (newY != getScrollY()) { 11478 mScrollCache.mScrollBarDraggingPos = y; 11479 setScrollY(newY); 11480 } 11481 } 11482 return true; 11483 } 11484 if (mScrollCache.mScrollBarDraggingState 11485 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 11486 final Rect bounds = mScrollCache.mScrollBarBounds; 11487 getHorizontalScrollBarBounds(bounds); 11488 final int range = computeHorizontalScrollRange(); 11489 final int offset = computeHorizontalScrollOffset(); 11490 final int extent = computeHorizontalScrollExtent(); 11491 11492 final int thumbLength = ScrollBarUtils.getThumbLength( 11493 bounds.width(), bounds.height(), extent, range); 11494 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11495 bounds.width(), thumbLength, extent, range, offset); 11496 11497 final float diff = x - mScrollCache.mScrollBarDraggingPos; 11498 final float maxThumbOffset = bounds.width() - thumbLength; 11499 final float newThumbOffset = 11500 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11501 final int width = getWidth(); 11502 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11503 && width > 0 && extent > 0) { 11504 final int newX = Math.round((range - extent) 11505 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 11506 if (newX != getScrollX()) { 11507 mScrollCache.mScrollBarDraggingPos = x; 11508 setScrollX(newX); 11509 } 11510 } 11511 return true; 11512 } 11513 case MotionEvent.ACTION_DOWN: 11514 if (mScrollCache.state == ScrollabilityCache.OFF) { 11515 return false; 11516 } 11517 if (isOnVerticalScrollbarThumb(x, y)) { 11518 mScrollCache.mScrollBarDraggingState = 11519 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 11520 mScrollCache.mScrollBarDraggingPos = y; 11521 return true; 11522 } 11523 if (isOnHorizontalScrollbarThumb(x, y)) { 11524 mScrollCache.mScrollBarDraggingState = 11525 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 11526 mScrollCache.mScrollBarDraggingPos = x; 11527 return true; 11528 } 11529 } 11530 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11531 return false; 11532 } 11533 11534 /** 11535 * Implement this method to handle touch screen motion events. 11536 * <p> 11537 * If this method is used to detect click actions, it is recommended that 11538 * the actions be performed by implementing and calling 11539 * {@link #performClick()}. This will ensure consistent system behavior, 11540 * including: 11541 * <ul> 11542 * <li>obeying click sound preferences 11543 * <li>dispatching OnClickListener calls 11544 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 11545 * accessibility features are enabled 11546 * </ul> 11547 * 11548 * @param event The motion event. 11549 * @return True if the event was handled, false otherwise. 11550 */ 11551 public boolean onTouchEvent(MotionEvent event) { 11552 final float x = event.getX(); 11553 final float y = event.getY(); 11554 final int viewFlags = mViewFlags; 11555 final int action = event.getAction(); 11556 11557 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 11558 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 11559 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11560 11561 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11562 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 11563 setPressed(false); 11564 } 11565 // A disabled view that is clickable still consumes the touch 11566 // events, it just doesn't respond to them. 11567 return clickable; 11568 } 11569 if (mTouchDelegate != null) { 11570 if (mTouchDelegate.onTouchEvent(event)) { 11571 return true; 11572 } 11573 } 11574 11575 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 11576 switch (action) { 11577 case MotionEvent.ACTION_UP: 11578 if ((viewFlags & TOOLTIP) == TOOLTIP) { 11579 handleTooltipUp(); 11580 } 11581 if (!clickable) { 11582 removeTapCallback(); 11583 removeLongPressCallback(); 11584 mInContextButtonPress = false; 11585 mHasPerformedLongPress = false; 11586 mIgnoreNextUpEvent = false; 11587 break; 11588 } 11589 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 11590 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 11591 // take focus if we don't have it already and we should in 11592 // touch mode. 11593 boolean focusTaken = false; 11594 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 11595 focusTaken = requestFocus(); 11596 } 11597 11598 if (prepressed) { 11599 // The button is being released before we actually 11600 // showed it as pressed. Make it show the pressed 11601 // state now (before scheduling the click) to ensure 11602 // the user sees it. 11603 setPressed(true, x, y); 11604 } 11605 11606 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 11607 // This is a tap, so remove the longpress check 11608 removeLongPressCallback(); 11609 11610 // Only perform take click actions if we were in the pressed state 11611 if (!focusTaken) { 11612 // Use a Runnable and post this rather than calling 11613 // performClick directly. This lets other visual state 11614 // of the view update before click actions start. 11615 if (mPerformClick == null) { 11616 mPerformClick = new PerformClick(); 11617 } 11618 if (!post(mPerformClick)) { 11619 performClick(); 11620 } 11621 } 11622 } 11623 11624 if (mUnsetPressedState == null) { 11625 mUnsetPressedState = new UnsetPressedState(); 11626 } 11627 11628 if (prepressed) { 11629 postDelayed(mUnsetPressedState, 11630 ViewConfiguration.getPressedStateDuration()); 11631 } else if (!post(mUnsetPressedState)) { 11632 // If the post failed, unpress right now 11633 mUnsetPressedState.run(); 11634 } 11635 11636 removeTapCallback(); 11637 } 11638 mIgnoreNextUpEvent = false; 11639 break; 11640 11641 case MotionEvent.ACTION_DOWN: 11642 mHasPerformedLongPress = false; 11643 11644 if (!clickable) { 11645 checkForLongClick(0, x, y); 11646 break; 11647 } 11648 11649 if (performButtonActionOnTouchDown(event)) { 11650 break; 11651 } 11652 11653 // Walk up the hierarchy to determine if we're inside a scrolling container. 11654 boolean isInScrollingContainer = isInScrollingContainer(); 11655 11656 // For views inside a scrolling container, delay the pressed feedback for 11657 // a short period in case this is a scroll. 11658 if (isInScrollingContainer) { 11659 mPrivateFlags |= PFLAG_PREPRESSED; 11660 if (mPendingCheckForTap == null) { 11661 mPendingCheckForTap = new CheckForTap(); 11662 } 11663 mPendingCheckForTap.x = event.getX(); 11664 mPendingCheckForTap.y = event.getY(); 11665 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 11666 } else { 11667 // Not inside a scrolling container, so show the feedback right away 11668 setPressed(true, x, y); 11669 checkForLongClick(0, x, y); 11670 } 11671 break; 11672 11673 case MotionEvent.ACTION_CANCEL: 11674 if (clickable) { 11675 setPressed(false); 11676 } 11677 removeTapCallback(); 11678 removeLongPressCallback(); 11679 mInContextButtonPress = false; 11680 mHasPerformedLongPress = false; 11681 mIgnoreNextUpEvent = false; 11682 break; 11683 11684 case MotionEvent.ACTION_MOVE: 11685 if (clickable) { 11686 drawableHotspotChanged(x, y); 11687 } 11688 11689 // Be lenient about moving outside of buttons 11690 if (!pointInView(x, y, mTouchSlop)) { 11691 // Outside button 11692 // Remove any future long press/tap checks 11693 removeTapCallback(); 11694 removeLongPressCallback(); 11695 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 11696 setPressed(false); 11697 } 11698 } 11699 break; 11700 } 11701 11702 return true; 11703 } 11704 11705 return false; 11706 } 11707 11708 /** 11709 * @hide 11710 */ 11711 public boolean isInScrollingContainer() { 11712 ViewParent p = getParent(); 11713 while (p != null && p instanceof ViewGroup) { 11714 if (((ViewGroup) p).shouldDelayChildPressedState()) { 11715 return true; 11716 } 11717 p = p.getParent(); 11718 } 11719 return false; 11720 } 11721 11722 /** 11723 * Remove the longpress detection timer. 11724 */ 11725 private void removeLongPressCallback() { 11726 if (mPendingCheckForLongPress != null) { 11727 removeCallbacks(mPendingCheckForLongPress); 11728 } 11729 } 11730 11731 /** 11732 * Remove the pending click action 11733 */ 11734 private void removePerformClickCallback() { 11735 if (mPerformClick != null) { 11736 removeCallbacks(mPerformClick); 11737 } 11738 } 11739 11740 /** 11741 * Remove the prepress detection timer. 11742 */ 11743 private void removeUnsetPressCallback() { 11744 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 11745 setPressed(false); 11746 removeCallbacks(mUnsetPressedState); 11747 } 11748 } 11749 11750 /** 11751 * Remove the tap detection timer. 11752 */ 11753 private void removeTapCallback() { 11754 if (mPendingCheckForTap != null) { 11755 mPrivateFlags &= ~PFLAG_PREPRESSED; 11756 removeCallbacks(mPendingCheckForTap); 11757 } 11758 } 11759 11760 /** 11761 * Cancels a pending long press. Your subclass can use this if you 11762 * want the context menu to come up if the user presses and holds 11763 * at the same place, but you don't want it to come up if they press 11764 * and then move around enough to cause scrolling. 11765 */ 11766 public void cancelLongPress() { 11767 removeLongPressCallback(); 11768 11769 /* 11770 * The prepressed state handled by the tap callback is a display 11771 * construct, but the tap callback will post a long press callback 11772 * less its own timeout. Remove it here. 11773 */ 11774 removeTapCallback(); 11775 } 11776 11777 /** 11778 * Remove the pending callback for sending a 11779 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 11780 */ 11781 private void removeSendViewScrolledAccessibilityEventCallback() { 11782 if (mSendViewScrolledAccessibilityEvent != null) { 11783 removeCallbacks(mSendViewScrolledAccessibilityEvent); 11784 mSendViewScrolledAccessibilityEvent.mIsPending = false; 11785 } 11786 } 11787 11788 /** 11789 * Sets the TouchDelegate for this View. 11790 */ 11791 public void setTouchDelegate(TouchDelegate delegate) { 11792 mTouchDelegate = delegate; 11793 } 11794 11795 /** 11796 * Gets the TouchDelegate for this View. 11797 */ 11798 public TouchDelegate getTouchDelegate() { 11799 return mTouchDelegate; 11800 } 11801 11802 /** 11803 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 11804 * 11805 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 11806 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 11807 * available. This method should only be called for touch events. 11808 * 11809 * <p class="note">This api is not intended for most applications. Buffered dispatch 11810 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 11811 * streams will not improve your input latency. Side effects include: increased latency, 11812 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 11813 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 11814 * you.</p> 11815 */ 11816 public final void requestUnbufferedDispatch(MotionEvent event) { 11817 final int action = event.getAction(); 11818 if (mAttachInfo == null 11819 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 11820 || !event.isTouchEvent()) { 11821 return; 11822 } 11823 mAttachInfo.mUnbufferedDispatchRequested = true; 11824 } 11825 11826 /** 11827 * Set flags controlling behavior of this view. 11828 * 11829 * @param flags Constant indicating the value which should be set 11830 * @param mask Constant indicating the bit range that should be changed 11831 */ 11832 void setFlags(int flags, int mask) { 11833 final boolean accessibilityEnabled = 11834 AccessibilityManager.getInstance(mContext).isEnabled(); 11835 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 11836 11837 int old = mViewFlags; 11838 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 11839 11840 int changed = mViewFlags ^ old; 11841 if (changed == 0) { 11842 return; 11843 } 11844 int privateFlags = mPrivateFlags; 11845 11846 /* Check if the FOCUSABLE bit has changed */ 11847 if (((changed & FOCUSABLE_MASK) != 0) && 11848 ((privateFlags & PFLAG_HAS_BOUNDS) !=0)) { 11849 if (((old & FOCUSABLE_MASK) == FOCUSABLE) 11850 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 11851 /* Give up focus if we are no longer focusable */ 11852 clearFocus(); 11853 } else if (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE) 11854 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 11855 /* 11856 * Tell the view system that we are now available to take focus 11857 * if no one else already has it. 11858 */ 11859 if (mParent != null) mParent.focusableViewAvailable(this); 11860 } 11861 } 11862 11863 final int newVisibility = flags & VISIBILITY_MASK; 11864 if (newVisibility == VISIBLE) { 11865 if ((changed & VISIBILITY_MASK) != 0) { 11866 /* 11867 * If this view is becoming visible, invalidate it in case it changed while 11868 * it was not visible. Marking it drawn ensures that the invalidation will 11869 * go through. 11870 */ 11871 mPrivateFlags |= PFLAG_DRAWN; 11872 invalidate(true); 11873 11874 needGlobalAttributesUpdate(true); 11875 11876 // a view becoming visible is worth notifying the parent 11877 // about in case nothing has focus. even if this specific view 11878 // isn't focusable, it may contain something that is, so let 11879 // the root view try to give this focus if nothing else does. 11880 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 11881 mParent.focusableViewAvailable(this); 11882 } 11883 } 11884 } 11885 11886 /* Check if the GONE bit has changed */ 11887 if ((changed & GONE) != 0) { 11888 needGlobalAttributesUpdate(false); 11889 requestLayout(); 11890 11891 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 11892 if (hasFocus()) clearFocus(); 11893 clearAccessibilityFocus(); 11894 destroyDrawingCache(); 11895 if (mParent instanceof View) { 11896 // GONE views noop invalidation, so invalidate the parent 11897 ((View) mParent).invalidate(true); 11898 } 11899 // Mark the view drawn to ensure that it gets invalidated properly the next 11900 // time it is visible and gets invalidated 11901 mPrivateFlags |= PFLAG_DRAWN; 11902 } 11903 if (mAttachInfo != null) { 11904 mAttachInfo.mViewVisibilityChanged = true; 11905 } 11906 } 11907 11908 /* Check if the VISIBLE bit has changed */ 11909 if ((changed & INVISIBLE) != 0) { 11910 needGlobalAttributesUpdate(false); 11911 /* 11912 * If this view is becoming invisible, set the DRAWN flag so that 11913 * the next invalidate() will not be skipped. 11914 */ 11915 mPrivateFlags |= PFLAG_DRAWN; 11916 11917 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 11918 // root view becoming invisible shouldn't clear focus and accessibility focus 11919 if (getRootView() != this) { 11920 if (hasFocus()) clearFocus(); 11921 clearAccessibilityFocus(); 11922 } 11923 } 11924 if (mAttachInfo != null) { 11925 mAttachInfo.mViewVisibilityChanged = true; 11926 } 11927 } 11928 11929 if ((changed & VISIBILITY_MASK) != 0) { 11930 // If the view is invisible, cleanup its display list to free up resources 11931 if (newVisibility != VISIBLE && mAttachInfo != null) { 11932 cleanupDraw(); 11933 } 11934 11935 if (mParent instanceof ViewGroup) { 11936 ((ViewGroup) mParent).onChildVisibilityChanged(this, 11937 (changed & VISIBILITY_MASK), newVisibility); 11938 ((View) mParent).invalidate(true); 11939 } else if (mParent != null) { 11940 mParent.invalidateChild(this, null); 11941 } 11942 11943 if (mAttachInfo != null) { 11944 dispatchVisibilityChanged(this, newVisibility); 11945 11946 // Aggregated visibility changes are dispatched to attached views 11947 // in visible windows where the parent is currently shown/drawn 11948 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 11949 // discounting clipping or overlapping. This makes it a good place 11950 // to change animation states. 11951 if (mParent != null && getWindowVisibility() == VISIBLE && 11952 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 11953 dispatchVisibilityAggregated(newVisibility == VISIBLE); 11954 } 11955 notifySubtreeAccessibilityStateChangedIfNeeded(); 11956 } 11957 } 11958 11959 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 11960 destroyDrawingCache(); 11961 } 11962 11963 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 11964 destroyDrawingCache(); 11965 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 11966 invalidateParentCaches(); 11967 } 11968 11969 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 11970 destroyDrawingCache(); 11971 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 11972 } 11973 11974 if ((changed & DRAW_MASK) != 0) { 11975 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 11976 if (mBackground != null 11977 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 11978 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 11979 } else { 11980 mPrivateFlags |= PFLAG_SKIP_DRAW; 11981 } 11982 } else { 11983 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 11984 } 11985 requestLayout(); 11986 invalidate(true); 11987 } 11988 11989 if ((changed & KEEP_SCREEN_ON) != 0) { 11990 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 11991 mParent.recomputeViewAttributes(this); 11992 } 11993 } 11994 11995 if (accessibilityEnabled) { 11996 if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0 11997 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 11998 || (changed & CONTEXT_CLICKABLE) != 0) { 11999 if (oldIncludeForAccessibility != includeForAccessibility()) { 12000 notifySubtreeAccessibilityStateChangedIfNeeded(); 12001 } else { 12002 notifyViewAccessibilityStateChangedIfNeeded( 12003 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12004 } 12005 } else if ((changed & ENABLED_MASK) != 0) { 12006 notifyViewAccessibilityStateChangedIfNeeded( 12007 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12008 } 12009 } 12010 } 12011 12012 /** 12013 * Change the view's z order in the tree, so it's on top of other sibling 12014 * views. This ordering change may affect layout, if the parent container 12015 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 12016 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 12017 * method should be followed by calls to {@link #requestLayout()} and 12018 * {@link View#invalidate()} on the view's parent to force the parent to redraw 12019 * with the new child ordering. 12020 * 12021 * @see ViewGroup#bringChildToFront(View) 12022 */ 12023 public void bringToFront() { 12024 if (mParent != null) { 12025 mParent.bringChildToFront(this); 12026 } 12027 } 12028 12029 /** 12030 * This is called in response to an internal scroll in this view (i.e., the 12031 * view scrolled its own contents). This is typically as a result of 12032 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 12033 * called. 12034 * 12035 * @param l Current horizontal scroll origin. 12036 * @param t Current vertical scroll origin. 12037 * @param oldl Previous horizontal scroll origin. 12038 * @param oldt Previous vertical scroll origin. 12039 */ 12040 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 12041 notifySubtreeAccessibilityStateChangedIfNeeded(); 12042 12043 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 12044 postSendViewScrolledAccessibilityEventCallback(); 12045 } 12046 12047 mBackgroundSizeChanged = true; 12048 if (mForegroundInfo != null) { 12049 mForegroundInfo.mBoundsChanged = true; 12050 } 12051 12052 final AttachInfo ai = mAttachInfo; 12053 if (ai != null) { 12054 ai.mViewScrollChanged = true; 12055 } 12056 12057 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 12058 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 12059 } 12060 } 12061 12062 /** 12063 * Interface definition for a callback to be invoked when the scroll 12064 * X or Y positions of a view change. 12065 * <p> 12066 * <b>Note:</b> Some views handle scrolling independently from View and may 12067 * have their own separate listeners for scroll-type events. For example, 12068 * {@link android.widget.ListView ListView} allows clients to register an 12069 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 12070 * to listen for changes in list scroll position. 12071 * 12072 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 12073 */ 12074 public interface OnScrollChangeListener { 12075 /** 12076 * Called when the scroll position of a view changes. 12077 * 12078 * @param v The view whose scroll position has changed. 12079 * @param scrollX Current horizontal scroll origin. 12080 * @param scrollY Current vertical scroll origin. 12081 * @param oldScrollX Previous horizontal scroll origin. 12082 * @param oldScrollY Previous vertical scroll origin. 12083 */ 12084 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 12085 } 12086 12087 /** 12088 * Interface definition for a callback to be invoked when the layout bounds of a view 12089 * changes due to layout processing. 12090 */ 12091 public interface OnLayoutChangeListener { 12092 /** 12093 * Called when the layout bounds of a view changes due to layout processing. 12094 * 12095 * @param v The view whose bounds have changed. 12096 * @param left The new value of the view's left property. 12097 * @param top The new value of the view's top property. 12098 * @param right The new value of the view's right property. 12099 * @param bottom The new value of the view's bottom property. 12100 * @param oldLeft The previous value of the view's left property. 12101 * @param oldTop The previous value of the view's top property. 12102 * @param oldRight The previous value of the view's right property. 12103 * @param oldBottom The previous value of the view's bottom property. 12104 */ 12105 void onLayoutChange(View v, int left, int top, int right, int bottom, 12106 int oldLeft, int oldTop, int oldRight, int oldBottom); 12107 } 12108 12109 /** 12110 * This is called during layout when the size of this view has changed. If 12111 * you were just added to the view hierarchy, you're called with the old 12112 * values of 0. 12113 * 12114 * @param w Current width of this view. 12115 * @param h Current height of this view. 12116 * @param oldw Old width of this view. 12117 * @param oldh Old height of this view. 12118 */ 12119 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 12120 } 12121 12122 /** 12123 * Called by draw to draw the child views. This may be overridden 12124 * by derived classes to gain control just before its children are drawn 12125 * (but after its own view has been drawn). 12126 * @param canvas the canvas on which to draw the view 12127 */ 12128 protected void dispatchDraw(Canvas canvas) { 12129 12130 } 12131 12132 /** 12133 * Gets the parent of this view. Note that the parent is a 12134 * ViewParent and not necessarily a View. 12135 * 12136 * @return Parent of this view. 12137 */ 12138 public final ViewParent getParent() { 12139 return mParent; 12140 } 12141 12142 /** 12143 * Set the horizontal scrolled position of your view. This will cause a call to 12144 * {@link #onScrollChanged(int, int, int, int)} and the view will be 12145 * invalidated. 12146 * @param value the x position to scroll to 12147 */ 12148 public void setScrollX(int value) { 12149 scrollTo(value, mScrollY); 12150 } 12151 12152 /** 12153 * Set the vertical scrolled position of your view. This will cause a call to 12154 * {@link #onScrollChanged(int, int, int, int)} and the view will be 12155 * invalidated. 12156 * @param value the y position to scroll to 12157 */ 12158 public void setScrollY(int value) { 12159 scrollTo(mScrollX, value); 12160 } 12161 12162 /** 12163 * Return the scrolled left position of this view. This is the left edge of 12164 * the displayed part of your view. You do not need to draw any pixels 12165 * farther left, since those are outside of the frame of your view on 12166 * screen. 12167 * 12168 * @return The left edge of the displayed part of your view, in pixels. 12169 */ 12170 public final int getScrollX() { 12171 return mScrollX; 12172 } 12173 12174 /** 12175 * Return the scrolled top position of this view. This is the top edge of 12176 * the displayed part of your view. You do not need to draw any pixels above 12177 * it, since those are outside of the frame of your view on screen. 12178 * 12179 * @return The top edge of the displayed part of your view, in pixels. 12180 */ 12181 public final int getScrollY() { 12182 return mScrollY; 12183 } 12184 12185 /** 12186 * Return the width of the your view. 12187 * 12188 * @return The width of your view, in pixels. 12189 */ 12190 @ViewDebug.ExportedProperty(category = "layout") 12191 public final int getWidth() { 12192 return mRight - mLeft; 12193 } 12194 12195 /** 12196 * Return the height of your view. 12197 * 12198 * @return The height of your view, in pixels. 12199 */ 12200 @ViewDebug.ExportedProperty(category = "layout") 12201 public final int getHeight() { 12202 return mBottom - mTop; 12203 } 12204 12205 /** 12206 * Return the visible drawing bounds of your view. Fills in the output 12207 * rectangle with the values from getScrollX(), getScrollY(), 12208 * getWidth(), and getHeight(). These bounds do not account for any 12209 * transformation properties currently set on the view, such as 12210 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 12211 * 12212 * @param outRect The (scrolled) drawing bounds of the view. 12213 */ 12214 public void getDrawingRect(Rect outRect) { 12215 outRect.left = mScrollX; 12216 outRect.top = mScrollY; 12217 outRect.right = mScrollX + (mRight - mLeft); 12218 outRect.bottom = mScrollY + (mBottom - mTop); 12219 } 12220 12221 /** 12222 * Like {@link #getMeasuredWidthAndState()}, but only returns the 12223 * raw width component (that is the result is masked by 12224 * {@link #MEASURED_SIZE_MASK}). 12225 * 12226 * @return The raw measured width of this view. 12227 */ 12228 public final int getMeasuredWidth() { 12229 return mMeasuredWidth & MEASURED_SIZE_MASK; 12230 } 12231 12232 /** 12233 * Return the full width measurement information for this view as computed 12234 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 12235 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 12236 * This should be used during measurement and layout calculations only. Use 12237 * {@link #getWidth()} to see how wide a view is after layout. 12238 * 12239 * @return The measured width of this view as a bit mask. 12240 */ 12241 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 12242 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 12243 name = "MEASURED_STATE_TOO_SMALL"), 12244 }) 12245 public final int getMeasuredWidthAndState() { 12246 return mMeasuredWidth; 12247 } 12248 12249 /** 12250 * Like {@link #getMeasuredHeightAndState()}, but only returns the 12251 * raw height component (that is the result is masked by 12252 * {@link #MEASURED_SIZE_MASK}). 12253 * 12254 * @return The raw measured height of this view. 12255 */ 12256 public final int getMeasuredHeight() { 12257 return mMeasuredHeight & MEASURED_SIZE_MASK; 12258 } 12259 12260 /** 12261 * Return the full height measurement information for this view as computed 12262 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 12263 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 12264 * This should be used during measurement and layout calculations only. Use 12265 * {@link #getHeight()} to see how wide a view is after layout. 12266 * 12267 * @return The measured height of this view as a bit mask. 12268 */ 12269 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 12270 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 12271 name = "MEASURED_STATE_TOO_SMALL"), 12272 }) 12273 public final int getMeasuredHeightAndState() { 12274 return mMeasuredHeight; 12275 } 12276 12277 /** 12278 * Return only the state bits of {@link #getMeasuredWidthAndState()} 12279 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 12280 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 12281 * and the height component is at the shifted bits 12282 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 12283 */ 12284 public final int getMeasuredState() { 12285 return (mMeasuredWidth&MEASURED_STATE_MASK) 12286 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 12287 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 12288 } 12289 12290 /** 12291 * The transform matrix of this view, which is calculated based on the current 12292 * rotation, scale, and pivot properties. 12293 * 12294 * @see #getRotation() 12295 * @see #getScaleX() 12296 * @see #getScaleY() 12297 * @see #getPivotX() 12298 * @see #getPivotY() 12299 * @return The current transform matrix for the view 12300 */ 12301 public Matrix getMatrix() { 12302 ensureTransformationInfo(); 12303 final Matrix matrix = mTransformationInfo.mMatrix; 12304 mRenderNode.getMatrix(matrix); 12305 return matrix; 12306 } 12307 12308 /** 12309 * Returns true if the transform matrix is the identity matrix. 12310 * Recomputes the matrix if necessary. 12311 * 12312 * @return True if the transform matrix is the identity matrix, false otherwise. 12313 */ 12314 final boolean hasIdentityMatrix() { 12315 return mRenderNode.hasIdentityMatrix(); 12316 } 12317 12318 void ensureTransformationInfo() { 12319 if (mTransformationInfo == null) { 12320 mTransformationInfo = new TransformationInfo(); 12321 } 12322 } 12323 12324 /** 12325 * Utility method to retrieve the inverse of the current mMatrix property. 12326 * We cache the matrix to avoid recalculating it when transform properties 12327 * have not changed. 12328 * 12329 * @return The inverse of the current matrix of this view. 12330 * @hide 12331 */ 12332 public final Matrix getInverseMatrix() { 12333 ensureTransformationInfo(); 12334 if (mTransformationInfo.mInverseMatrix == null) { 12335 mTransformationInfo.mInverseMatrix = new Matrix(); 12336 } 12337 final Matrix matrix = mTransformationInfo.mInverseMatrix; 12338 mRenderNode.getInverseMatrix(matrix); 12339 return matrix; 12340 } 12341 12342 /** 12343 * Gets the distance along the Z axis from the camera to this view. 12344 * 12345 * @see #setCameraDistance(float) 12346 * 12347 * @return The distance along the Z axis. 12348 */ 12349 public float getCameraDistance() { 12350 final float dpi = mResources.getDisplayMetrics().densityDpi; 12351 return -(mRenderNode.getCameraDistance() * dpi); 12352 } 12353 12354 /** 12355 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 12356 * views are drawn) from the camera to this view. The camera's distance 12357 * affects 3D transformations, for instance rotations around the X and Y 12358 * axis. If the rotationX or rotationY properties are changed and this view is 12359 * large (more than half the size of the screen), it is recommended to always 12360 * use a camera distance that's greater than the height (X axis rotation) or 12361 * the width (Y axis rotation) of this view.</p> 12362 * 12363 * <p>The distance of the camera from the view plane can have an affect on the 12364 * perspective distortion of the view when it is rotated around the x or y axis. 12365 * For example, a large distance will result in a large viewing angle, and there 12366 * will not be much perspective distortion of the view as it rotates. A short 12367 * distance may cause much more perspective distortion upon rotation, and can 12368 * also result in some drawing artifacts if the rotated view ends up partially 12369 * behind the camera (which is why the recommendation is to use a distance at 12370 * least as far as the size of the view, if the view is to be rotated.)</p> 12371 * 12372 * <p>The distance is expressed in "depth pixels." The default distance depends 12373 * on the screen density. For instance, on a medium density display, the 12374 * default distance is 1280. On a high density display, the default distance 12375 * is 1920.</p> 12376 * 12377 * <p>If you want to specify a distance that leads to visually consistent 12378 * results across various densities, use the following formula:</p> 12379 * <pre> 12380 * float scale = context.getResources().getDisplayMetrics().density; 12381 * view.setCameraDistance(distance * scale); 12382 * </pre> 12383 * 12384 * <p>The density scale factor of a high density display is 1.5, 12385 * and 1920 = 1280 * 1.5.</p> 12386 * 12387 * @param distance The distance in "depth pixels", if negative the opposite 12388 * value is used 12389 * 12390 * @see #setRotationX(float) 12391 * @see #setRotationY(float) 12392 */ 12393 public void setCameraDistance(float distance) { 12394 final float dpi = mResources.getDisplayMetrics().densityDpi; 12395 12396 invalidateViewProperty(true, false); 12397 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 12398 invalidateViewProperty(false, false); 12399 12400 invalidateParentIfNeededAndWasQuickRejected(); 12401 } 12402 12403 /** 12404 * The degrees that the view is rotated around the pivot point. 12405 * 12406 * @see #setRotation(float) 12407 * @see #getPivotX() 12408 * @see #getPivotY() 12409 * 12410 * @return The degrees of rotation. 12411 */ 12412 @ViewDebug.ExportedProperty(category = "drawing") 12413 public float getRotation() { 12414 return mRenderNode.getRotation(); 12415 } 12416 12417 /** 12418 * Sets the degrees that the view is rotated around the pivot point. Increasing values 12419 * result in clockwise rotation. 12420 * 12421 * @param rotation The degrees of rotation. 12422 * 12423 * @see #getRotation() 12424 * @see #getPivotX() 12425 * @see #getPivotY() 12426 * @see #setRotationX(float) 12427 * @see #setRotationY(float) 12428 * 12429 * @attr ref android.R.styleable#View_rotation 12430 */ 12431 public void setRotation(float rotation) { 12432 if (rotation != getRotation()) { 12433 // Double-invalidation is necessary to capture view's old and new areas 12434 invalidateViewProperty(true, false); 12435 mRenderNode.setRotation(rotation); 12436 invalidateViewProperty(false, true); 12437 12438 invalidateParentIfNeededAndWasQuickRejected(); 12439 notifySubtreeAccessibilityStateChangedIfNeeded(); 12440 } 12441 } 12442 12443 /** 12444 * The degrees that the view is rotated around the vertical axis through the pivot point. 12445 * 12446 * @see #getPivotX() 12447 * @see #getPivotY() 12448 * @see #setRotationY(float) 12449 * 12450 * @return The degrees of Y rotation. 12451 */ 12452 @ViewDebug.ExportedProperty(category = "drawing") 12453 public float getRotationY() { 12454 return mRenderNode.getRotationY(); 12455 } 12456 12457 /** 12458 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 12459 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 12460 * down the y axis. 12461 * 12462 * When rotating large views, it is recommended to adjust the camera distance 12463 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12464 * 12465 * @param rotationY The degrees of Y rotation. 12466 * 12467 * @see #getRotationY() 12468 * @see #getPivotX() 12469 * @see #getPivotY() 12470 * @see #setRotation(float) 12471 * @see #setRotationX(float) 12472 * @see #setCameraDistance(float) 12473 * 12474 * @attr ref android.R.styleable#View_rotationY 12475 */ 12476 public void setRotationY(float rotationY) { 12477 if (rotationY != getRotationY()) { 12478 invalidateViewProperty(true, false); 12479 mRenderNode.setRotationY(rotationY); 12480 invalidateViewProperty(false, true); 12481 12482 invalidateParentIfNeededAndWasQuickRejected(); 12483 notifySubtreeAccessibilityStateChangedIfNeeded(); 12484 } 12485 } 12486 12487 /** 12488 * The degrees that the view is rotated around the horizontal axis through the pivot point. 12489 * 12490 * @see #getPivotX() 12491 * @see #getPivotY() 12492 * @see #setRotationX(float) 12493 * 12494 * @return The degrees of X rotation. 12495 */ 12496 @ViewDebug.ExportedProperty(category = "drawing") 12497 public float getRotationX() { 12498 return mRenderNode.getRotationX(); 12499 } 12500 12501 /** 12502 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 12503 * Increasing values result in clockwise rotation from the viewpoint of looking down the 12504 * x axis. 12505 * 12506 * When rotating large views, it is recommended to adjust the camera distance 12507 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12508 * 12509 * @param rotationX The degrees of X rotation. 12510 * 12511 * @see #getRotationX() 12512 * @see #getPivotX() 12513 * @see #getPivotY() 12514 * @see #setRotation(float) 12515 * @see #setRotationY(float) 12516 * @see #setCameraDistance(float) 12517 * 12518 * @attr ref android.R.styleable#View_rotationX 12519 */ 12520 public void setRotationX(float rotationX) { 12521 if (rotationX != getRotationX()) { 12522 invalidateViewProperty(true, false); 12523 mRenderNode.setRotationX(rotationX); 12524 invalidateViewProperty(false, true); 12525 12526 invalidateParentIfNeededAndWasQuickRejected(); 12527 notifySubtreeAccessibilityStateChangedIfNeeded(); 12528 } 12529 } 12530 12531 /** 12532 * The amount that the view is scaled in x around the pivot point, as a proportion of 12533 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 12534 * 12535 * <p>By default, this is 1.0f. 12536 * 12537 * @see #getPivotX() 12538 * @see #getPivotY() 12539 * @return The scaling factor. 12540 */ 12541 @ViewDebug.ExportedProperty(category = "drawing") 12542 public float getScaleX() { 12543 return mRenderNode.getScaleX(); 12544 } 12545 12546 /** 12547 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 12548 * the view's unscaled width. A value of 1 means that no scaling is applied. 12549 * 12550 * @param scaleX The scaling factor. 12551 * @see #getPivotX() 12552 * @see #getPivotY() 12553 * 12554 * @attr ref android.R.styleable#View_scaleX 12555 */ 12556 public void setScaleX(float scaleX) { 12557 if (scaleX != getScaleX()) { 12558 invalidateViewProperty(true, false); 12559 mRenderNode.setScaleX(scaleX); 12560 invalidateViewProperty(false, true); 12561 12562 invalidateParentIfNeededAndWasQuickRejected(); 12563 notifySubtreeAccessibilityStateChangedIfNeeded(); 12564 } 12565 } 12566 12567 /** 12568 * The amount that the view is scaled in y around the pivot point, as a proportion of 12569 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 12570 * 12571 * <p>By default, this is 1.0f. 12572 * 12573 * @see #getPivotX() 12574 * @see #getPivotY() 12575 * @return The scaling factor. 12576 */ 12577 @ViewDebug.ExportedProperty(category = "drawing") 12578 public float getScaleY() { 12579 return mRenderNode.getScaleY(); 12580 } 12581 12582 /** 12583 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 12584 * the view's unscaled width. A value of 1 means that no scaling is applied. 12585 * 12586 * @param scaleY The scaling factor. 12587 * @see #getPivotX() 12588 * @see #getPivotY() 12589 * 12590 * @attr ref android.R.styleable#View_scaleY 12591 */ 12592 public void setScaleY(float scaleY) { 12593 if (scaleY != getScaleY()) { 12594 invalidateViewProperty(true, false); 12595 mRenderNode.setScaleY(scaleY); 12596 invalidateViewProperty(false, true); 12597 12598 invalidateParentIfNeededAndWasQuickRejected(); 12599 notifySubtreeAccessibilityStateChangedIfNeeded(); 12600 } 12601 } 12602 12603 /** 12604 * The x location of the point around which the view is {@link #setRotation(float) rotated} 12605 * and {@link #setScaleX(float) scaled}. 12606 * 12607 * @see #getRotation() 12608 * @see #getScaleX() 12609 * @see #getScaleY() 12610 * @see #getPivotY() 12611 * @return The x location of the pivot point. 12612 * 12613 * @attr ref android.R.styleable#View_transformPivotX 12614 */ 12615 @ViewDebug.ExportedProperty(category = "drawing") 12616 public float getPivotX() { 12617 return mRenderNode.getPivotX(); 12618 } 12619 12620 /** 12621 * Sets the x location of the point around which the view is 12622 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 12623 * By default, the pivot point is centered on the object. 12624 * Setting this property disables this behavior and causes the view to use only the 12625 * explicitly set pivotX and pivotY values. 12626 * 12627 * @param pivotX The x location of the pivot point. 12628 * @see #getRotation() 12629 * @see #getScaleX() 12630 * @see #getScaleY() 12631 * @see #getPivotY() 12632 * 12633 * @attr ref android.R.styleable#View_transformPivotX 12634 */ 12635 public void setPivotX(float pivotX) { 12636 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 12637 invalidateViewProperty(true, false); 12638 mRenderNode.setPivotX(pivotX); 12639 invalidateViewProperty(false, true); 12640 12641 invalidateParentIfNeededAndWasQuickRejected(); 12642 } 12643 } 12644 12645 /** 12646 * The y location of the point around which the view is {@link #setRotation(float) rotated} 12647 * and {@link #setScaleY(float) scaled}. 12648 * 12649 * @see #getRotation() 12650 * @see #getScaleX() 12651 * @see #getScaleY() 12652 * @see #getPivotY() 12653 * @return The y location of the pivot point. 12654 * 12655 * @attr ref android.R.styleable#View_transformPivotY 12656 */ 12657 @ViewDebug.ExportedProperty(category = "drawing") 12658 public float getPivotY() { 12659 return mRenderNode.getPivotY(); 12660 } 12661 12662 /** 12663 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 12664 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 12665 * Setting this property disables this behavior and causes the view to use only the 12666 * explicitly set pivotX and pivotY values. 12667 * 12668 * @param pivotY The y location of the pivot point. 12669 * @see #getRotation() 12670 * @see #getScaleX() 12671 * @see #getScaleY() 12672 * @see #getPivotY() 12673 * 12674 * @attr ref android.R.styleable#View_transformPivotY 12675 */ 12676 public void setPivotY(float pivotY) { 12677 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 12678 invalidateViewProperty(true, false); 12679 mRenderNode.setPivotY(pivotY); 12680 invalidateViewProperty(false, true); 12681 12682 invalidateParentIfNeededAndWasQuickRejected(); 12683 } 12684 } 12685 12686 /** 12687 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 12688 * completely transparent and 1 means the view is completely opaque. 12689 * 12690 * <p>By default this is 1.0f. 12691 * @return The opacity of the view. 12692 */ 12693 @ViewDebug.ExportedProperty(category = "drawing") 12694 public float getAlpha() { 12695 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 12696 } 12697 12698 /** 12699 * Sets the behavior for overlapping rendering for this view (see {@link 12700 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 12701 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 12702 * providing the value which is then used internally. That is, when {@link 12703 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 12704 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 12705 * instead. 12706 * 12707 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 12708 * instead of that returned by {@link #hasOverlappingRendering()}. 12709 * 12710 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 12711 */ 12712 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 12713 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 12714 if (hasOverlappingRendering) { 12715 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 12716 } else { 12717 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 12718 } 12719 } 12720 12721 /** 12722 * Returns the value for overlapping rendering that is used internally. This is either 12723 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 12724 * the return value of {@link #hasOverlappingRendering()}, otherwise. 12725 * 12726 * @return The value for overlapping rendering being used internally. 12727 */ 12728 public final boolean getHasOverlappingRendering() { 12729 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 12730 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 12731 hasOverlappingRendering(); 12732 } 12733 12734 /** 12735 * Returns whether this View has content which overlaps. 12736 * 12737 * <p>This function, intended to be overridden by specific View types, is an optimization when 12738 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 12739 * an offscreen buffer and then composited into place, which can be expensive. If the view has 12740 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 12741 * directly. An example of overlapping rendering is a TextView with a background image, such as 12742 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 12743 * ImageView with only the foreground image. The default implementation returns true; subclasses 12744 * should override if they have cases which can be optimized.</p> 12745 * 12746 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 12747 * necessitates that a View return true if it uses the methods internally without passing the 12748 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 12749 * 12750 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 12751 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 12752 * 12753 * @return true if the content in this view might overlap, false otherwise. 12754 */ 12755 @ViewDebug.ExportedProperty(category = "drawing") 12756 public boolean hasOverlappingRendering() { 12757 return true; 12758 } 12759 12760 /** 12761 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 12762 * completely transparent and 1 means the view is completely opaque. 12763 * 12764 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 12765 * can have significant performance implications, especially for large views. It is best to use 12766 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 12767 * 12768 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 12769 * strongly recommended for performance reasons to either override 12770 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 12771 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 12772 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 12773 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 12774 * of rendering cost, even for simple or small views. Starting with 12775 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 12776 * applied to the view at the rendering level.</p> 12777 * 12778 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 12779 * responsible for applying the opacity itself.</p> 12780 * 12781 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 12782 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 12783 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 12784 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 12785 * 12786 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 12787 * value will clip a View to its bounds, unless the View returns <code>false</code> from 12788 * {@link #hasOverlappingRendering}.</p> 12789 * 12790 * @param alpha The opacity of the view. 12791 * 12792 * @see #hasOverlappingRendering() 12793 * @see #setLayerType(int, android.graphics.Paint) 12794 * 12795 * @attr ref android.R.styleable#View_alpha 12796 */ 12797 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 12798 ensureTransformationInfo(); 12799 if (mTransformationInfo.mAlpha != alpha) { 12800 // Report visibility changes, which can affect children, to accessibility 12801 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 12802 notifySubtreeAccessibilityStateChangedIfNeeded(); 12803 } 12804 mTransformationInfo.mAlpha = alpha; 12805 if (onSetAlpha((int) (alpha * 255))) { 12806 mPrivateFlags |= PFLAG_ALPHA_SET; 12807 // subclass is handling alpha - don't optimize rendering cache invalidation 12808 invalidateParentCaches(); 12809 invalidate(true); 12810 } else { 12811 mPrivateFlags &= ~PFLAG_ALPHA_SET; 12812 invalidateViewProperty(true, false); 12813 mRenderNode.setAlpha(getFinalAlpha()); 12814 } 12815 } 12816 } 12817 12818 /** 12819 * Faster version of setAlpha() which performs the same steps except there are 12820 * no calls to invalidate(). The caller of this function should perform proper invalidation 12821 * on the parent and this object. The return value indicates whether the subclass handles 12822 * alpha (the return value for onSetAlpha()). 12823 * 12824 * @param alpha The new value for the alpha property 12825 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 12826 * the new value for the alpha property is different from the old value 12827 */ 12828 boolean setAlphaNoInvalidation(float alpha) { 12829 ensureTransformationInfo(); 12830 if (mTransformationInfo.mAlpha != alpha) { 12831 mTransformationInfo.mAlpha = alpha; 12832 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 12833 if (subclassHandlesAlpha) { 12834 mPrivateFlags |= PFLAG_ALPHA_SET; 12835 return true; 12836 } else { 12837 mPrivateFlags &= ~PFLAG_ALPHA_SET; 12838 mRenderNode.setAlpha(getFinalAlpha()); 12839 } 12840 } 12841 return false; 12842 } 12843 12844 /** 12845 * This property is hidden and intended only for use by the Fade transition, which 12846 * animates it to produce a visual translucency that does not side-effect (or get 12847 * affected by) the real alpha property. This value is composited with the other 12848 * alpha value (and the AlphaAnimation value, when that is present) to produce 12849 * a final visual translucency result, which is what is passed into the DisplayList. 12850 * 12851 * @hide 12852 */ 12853 public void setTransitionAlpha(float alpha) { 12854 ensureTransformationInfo(); 12855 if (mTransformationInfo.mTransitionAlpha != alpha) { 12856 mTransformationInfo.mTransitionAlpha = alpha; 12857 mPrivateFlags &= ~PFLAG_ALPHA_SET; 12858 invalidateViewProperty(true, false); 12859 mRenderNode.setAlpha(getFinalAlpha()); 12860 } 12861 } 12862 12863 /** 12864 * Calculates the visual alpha of this view, which is a combination of the actual 12865 * alpha value and the transitionAlpha value (if set). 12866 */ 12867 private float getFinalAlpha() { 12868 if (mTransformationInfo != null) { 12869 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 12870 } 12871 return 1; 12872 } 12873 12874 /** 12875 * This property is hidden and intended only for use by the Fade transition, which 12876 * animates it to produce a visual translucency that does not side-effect (or get 12877 * affected by) the real alpha property. This value is composited with the other 12878 * alpha value (and the AlphaAnimation value, when that is present) to produce 12879 * a final visual translucency result, which is what is passed into the DisplayList. 12880 * 12881 * @hide 12882 */ 12883 @ViewDebug.ExportedProperty(category = "drawing") 12884 public float getTransitionAlpha() { 12885 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 12886 } 12887 12888 /** 12889 * Top position of this view relative to its parent. 12890 * 12891 * @return The top of this view, in pixels. 12892 */ 12893 @ViewDebug.CapturedViewProperty 12894 public final int getTop() { 12895 return mTop; 12896 } 12897 12898 /** 12899 * Sets the top position of this view relative to its parent. This method is meant to be called 12900 * by the layout system and should not generally be called otherwise, because the property 12901 * may be changed at any time by the layout. 12902 * 12903 * @param top The top of this view, in pixels. 12904 */ 12905 public final void setTop(int top) { 12906 if (top != mTop) { 12907 final boolean matrixIsIdentity = hasIdentityMatrix(); 12908 if (matrixIsIdentity) { 12909 if (mAttachInfo != null) { 12910 int minTop; 12911 int yLoc; 12912 if (top < mTop) { 12913 minTop = top; 12914 yLoc = top - mTop; 12915 } else { 12916 minTop = mTop; 12917 yLoc = 0; 12918 } 12919 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 12920 } 12921 } else { 12922 // Double-invalidation is necessary to capture view's old and new areas 12923 invalidate(true); 12924 } 12925 12926 int width = mRight - mLeft; 12927 int oldHeight = mBottom - mTop; 12928 12929 mTop = top; 12930 mRenderNode.setTop(mTop); 12931 12932 sizeChange(width, mBottom - mTop, width, oldHeight); 12933 12934 if (!matrixIsIdentity) { 12935 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 12936 invalidate(true); 12937 } 12938 mBackgroundSizeChanged = true; 12939 if (mForegroundInfo != null) { 12940 mForegroundInfo.mBoundsChanged = true; 12941 } 12942 invalidateParentIfNeeded(); 12943 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 12944 // View was rejected last time it was drawn by its parent; this may have changed 12945 invalidateParentIfNeeded(); 12946 } 12947 } 12948 } 12949 12950 /** 12951 * Bottom position of this view relative to its parent. 12952 * 12953 * @return The bottom of this view, in pixels. 12954 */ 12955 @ViewDebug.CapturedViewProperty 12956 public final int getBottom() { 12957 return mBottom; 12958 } 12959 12960 /** 12961 * True if this view has changed since the last time being drawn. 12962 * 12963 * @return The dirty state of this view. 12964 */ 12965 public boolean isDirty() { 12966 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 12967 } 12968 12969 /** 12970 * Sets the bottom position of this view relative to its parent. This method is meant to be 12971 * called by the layout system and should not generally be called otherwise, because the 12972 * property may be changed at any time by the layout. 12973 * 12974 * @param bottom The bottom of this view, in pixels. 12975 */ 12976 public final void setBottom(int bottom) { 12977 if (bottom != mBottom) { 12978 final boolean matrixIsIdentity = hasIdentityMatrix(); 12979 if (matrixIsIdentity) { 12980 if (mAttachInfo != null) { 12981 int maxBottom; 12982 if (bottom < mBottom) { 12983 maxBottom = mBottom; 12984 } else { 12985 maxBottom = bottom; 12986 } 12987 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 12988 } 12989 } else { 12990 // Double-invalidation is necessary to capture view's old and new areas 12991 invalidate(true); 12992 } 12993 12994 int width = mRight - mLeft; 12995 int oldHeight = mBottom - mTop; 12996 12997 mBottom = bottom; 12998 mRenderNode.setBottom(mBottom); 12999 13000 sizeChange(width, mBottom - mTop, width, oldHeight); 13001 13002 if (!matrixIsIdentity) { 13003 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13004 invalidate(true); 13005 } 13006 mBackgroundSizeChanged = true; 13007 if (mForegroundInfo != null) { 13008 mForegroundInfo.mBoundsChanged = true; 13009 } 13010 invalidateParentIfNeeded(); 13011 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13012 // View was rejected last time it was drawn by its parent; this may have changed 13013 invalidateParentIfNeeded(); 13014 } 13015 } 13016 } 13017 13018 /** 13019 * Left position of this view relative to its parent. 13020 * 13021 * @return The left edge of this view, in pixels. 13022 */ 13023 @ViewDebug.CapturedViewProperty 13024 public final int getLeft() { 13025 return mLeft; 13026 } 13027 13028 /** 13029 * Sets the left position of this view relative to its parent. This method is meant to be called 13030 * by the layout system and should not generally be called otherwise, because the property 13031 * may be changed at any time by the layout. 13032 * 13033 * @param left The left of this view, in pixels. 13034 */ 13035 public final void setLeft(int left) { 13036 if (left != mLeft) { 13037 final boolean matrixIsIdentity = hasIdentityMatrix(); 13038 if (matrixIsIdentity) { 13039 if (mAttachInfo != null) { 13040 int minLeft; 13041 int xLoc; 13042 if (left < mLeft) { 13043 minLeft = left; 13044 xLoc = left - mLeft; 13045 } else { 13046 minLeft = mLeft; 13047 xLoc = 0; 13048 } 13049 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 13050 } 13051 } else { 13052 // Double-invalidation is necessary to capture view's old and new areas 13053 invalidate(true); 13054 } 13055 13056 int oldWidth = mRight - mLeft; 13057 int height = mBottom - mTop; 13058 13059 mLeft = left; 13060 mRenderNode.setLeft(left); 13061 13062 sizeChange(mRight - mLeft, height, oldWidth, height); 13063 13064 if (!matrixIsIdentity) { 13065 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13066 invalidate(true); 13067 } 13068 mBackgroundSizeChanged = true; 13069 if (mForegroundInfo != null) { 13070 mForegroundInfo.mBoundsChanged = true; 13071 } 13072 invalidateParentIfNeeded(); 13073 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13074 // View was rejected last time it was drawn by its parent; this may have changed 13075 invalidateParentIfNeeded(); 13076 } 13077 } 13078 } 13079 13080 /** 13081 * Right position of this view relative to its parent. 13082 * 13083 * @return The right edge of this view, in pixels. 13084 */ 13085 @ViewDebug.CapturedViewProperty 13086 public final int getRight() { 13087 return mRight; 13088 } 13089 13090 /** 13091 * Sets the right position of this view relative to its parent. This method is meant to be called 13092 * by the layout system and should not generally be called otherwise, because the property 13093 * may be changed at any time by the layout. 13094 * 13095 * @param right The right of this view, in pixels. 13096 */ 13097 public final void setRight(int right) { 13098 if (right != mRight) { 13099 final boolean matrixIsIdentity = hasIdentityMatrix(); 13100 if (matrixIsIdentity) { 13101 if (mAttachInfo != null) { 13102 int maxRight; 13103 if (right < mRight) { 13104 maxRight = mRight; 13105 } else { 13106 maxRight = right; 13107 } 13108 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 13109 } 13110 } else { 13111 // Double-invalidation is necessary to capture view's old and new areas 13112 invalidate(true); 13113 } 13114 13115 int oldWidth = mRight - mLeft; 13116 int height = mBottom - mTop; 13117 13118 mRight = right; 13119 mRenderNode.setRight(mRight); 13120 13121 sizeChange(mRight - mLeft, height, oldWidth, height); 13122 13123 if (!matrixIsIdentity) { 13124 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13125 invalidate(true); 13126 } 13127 mBackgroundSizeChanged = true; 13128 if (mForegroundInfo != null) { 13129 mForegroundInfo.mBoundsChanged = true; 13130 } 13131 invalidateParentIfNeeded(); 13132 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13133 // View was rejected last time it was drawn by its parent; this may have changed 13134 invalidateParentIfNeeded(); 13135 } 13136 } 13137 } 13138 13139 /** 13140 * The visual x position of this view, in pixels. This is equivalent to the 13141 * {@link #setTranslationX(float) translationX} property plus the current 13142 * {@link #getLeft() left} property. 13143 * 13144 * @return The visual x position of this view, in pixels. 13145 */ 13146 @ViewDebug.ExportedProperty(category = "drawing") 13147 public float getX() { 13148 return mLeft + getTranslationX(); 13149 } 13150 13151 /** 13152 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 13153 * {@link #setTranslationX(float) translationX} property to be the difference between 13154 * the x value passed in and the current {@link #getLeft() left} property. 13155 * 13156 * @param x The visual x position of this view, in pixels. 13157 */ 13158 public void setX(float x) { 13159 setTranslationX(x - mLeft); 13160 } 13161 13162 /** 13163 * The visual y position of this view, in pixels. This is equivalent to the 13164 * {@link #setTranslationY(float) translationY} property plus the current 13165 * {@link #getTop() top} property. 13166 * 13167 * @return The visual y position of this view, in pixels. 13168 */ 13169 @ViewDebug.ExportedProperty(category = "drawing") 13170 public float getY() { 13171 return mTop + getTranslationY(); 13172 } 13173 13174 /** 13175 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 13176 * {@link #setTranslationY(float) translationY} property to be the difference between 13177 * the y value passed in and the current {@link #getTop() top} property. 13178 * 13179 * @param y The visual y position of this view, in pixels. 13180 */ 13181 public void setY(float y) { 13182 setTranslationY(y - mTop); 13183 } 13184 13185 /** 13186 * The visual z position of this view, in pixels. This is equivalent to the 13187 * {@link #setTranslationZ(float) translationZ} property plus the current 13188 * {@link #getElevation() elevation} property. 13189 * 13190 * @return The visual z position of this view, in pixels. 13191 */ 13192 @ViewDebug.ExportedProperty(category = "drawing") 13193 public float getZ() { 13194 return getElevation() + getTranslationZ(); 13195 } 13196 13197 /** 13198 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 13199 * {@link #setTranslationZ(float) translationZ} property to be the difference between 13200 * the x value passed in and the current {@link #getElevation() elevation} property. 13201 * 13202 * @param z The visual z position of this view, in pixels. 13203 */ 13204 public void setZ(float z) { 13205 setTranslationZ(z - getElevation()); 13206 } 13207 13208 /** 13209 * The base elevation of this view relative to its parent, in pixels. 13210 * 13211 * @return The base depth position of the view, in pixels. 13212 */ 13213 @ViewDebug.ExportedProperty(category = "drawing") 13214 public float getElevation() { 13215 return mRenderNode.getElevation(); 13216 } 13217 13218 /** 13219 * Sets the base elevation of this view, in pixels. 13220 * 13221 * @attr ref android.R.styleable#View_elevation 13222 */ 13223 public void setElevation(float elevation) { 13224 if (elevation != getElevation()) { 13225 invalidateViewProperty(true, false); 13226 mRenderNode.setElevation(elevation); 13227 invalidateViewProperty(false, true); 13228 13229 invalidateParentIfNeededAndWasQuickRejected(); 13230 } 13231 } 13232 13233 /** 13234 * The horizontal location of this view relative to its {@link #getLeft() left} position. 13235 * This position is post-layout, in addition to wherever the object's 13236 * layout placed it. 13237 * 13238 * @return The horizontal position of this view relative to its left position, in pixels. 13239 */ 13240 @ViewDebug.ExportedProperty(category = "drawing") 13241 public float getTranslationX() { 13242 return mRenderNode.getTranslationX(); 13243 } 13244 13245 /** 13246 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 13247 * This effectively positions the object post-layout, in addition to wherever the object's 13248 * layout placed it. 13249 * 13250 * @param translationX The horizontal position of this view relative to its left position, 13251 * in pixels. 13252 * 13253 * @attr ref android.R.styleable#View_translationX 13254 */ 13255 public void setTranslationX(float translationX) { 13256 if (translationX != getTranslationX()) { 13257 invalidateViewProperty(true, false); 13258 mRenderNode.setTranslationX(translationX); 13259 invalidateViewProperty(false, true); 13260 13261 invalidateParentIfNeededAndWasQuickRejected(); 13262 notifySubtreeAccessibilityStateChangedIfNeeded(); 13263 } 13264 } 13265 13266 /** 13267 * The vertical location of this view relative to its {@link #getTop() top} position. 13268 * This position is post-layout, in addition to wherever the object's 13269 * layout placed it. 13270 * 13271 * @return The vertical position of this view relative to its top position, 13272 * in pixels. 13273 */ 13274 @ViewDebug.ExportedProperty(category = "drawing") 13275 public float getTranslationY() { 13276 return mRenderNode.getTranslationY(); 13277 } 13278 13279 /** 13280 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 13281 * This effectively positions the object post-layout, in addition to wherever the object's 13282 * layout placed it. 13283 * 13284 * @param translationY The vertical position of this view relative to its top position, 13285 * in pixels. 13286 * 13287 * @attr ref android.R.styleable#View_translationY 13288 */ 13289 public void setTranslationY(float translationY) { 13290 if (translationY != getTranslationY()) { 13291 invalidateViewProperty(true, false); 13292 mRenderNode.setTranslationY(translationY); 13293 invalidateViewProperty(false, true); 13294 13295 invalidateParentIfNeededAndWasQuickRejected(); 13296 notifySubtreeAccessibilityStateChangedIfNeeded(); 13297 } 13298 } 13299 13300 /** 13301 * The depth location of this view relative to its {@link #getElevation() elevation}. 13302 * 13303 * @return The depth of this view relative to its elevation. 13304 */ 13305 @ViewDebug.ExportedProperty(category = "drawing") 13306 public float getTranslationZ() { 13307 return mRenderNode.getTranslationZ(); 13308 } 13309 13310 /** 13311 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 13312 * 13313 * @attr ref android.R.styleable#View_translationZ 13314 */ 13315 public void setTranslationZ(float translationZ) { 13316 if (translationZ != getTranslationZ()) { 13317 invalidateViewProperty(true, false); 13318 mRenderNode.setTranslationZ(translationZ); 13319 invalidateViewProperty(false, true); 13320 13321 invalidateParentIfNeededAndWasQuickRejected(); 13322 } 13323 } 13324 13325 /** @hide */ 13326 public void setAnimationMatrix(Matrix matrix) { 13327 invalidateViewProperty(true, false); 13328 mRenderNode.setAnimationMatrix(matrix); 13329 invalidateViewProperty(false, true); 13330 13331 invalidateParentIfNeededAndWasQuickRejected(); 13332 } 13333 13334 /** 13335 * Returns the current StateListAnimator if exists. 13336 * 13337 * @return StateListAnimator or null if it does not exists 13338 * @see #setStateListAnimator(android.animation.StateListAnimator) 13339 */ 13340 public StateListAnimator getStateListAnimator() { 13341 return mStateListAnimator; 13342 } 13343 13344 /** 13345 * Attaches the provided StateListAnimator to this View. 13346 * <p> 13347 * Any previously attached StateListAnimator will be detached. 13348 * 13349 * @param stateListAnimator The StateListAnimator to update the view 13350 * @see {@link android.animation.StateListAnimator} 13351 */ 13352 public void setStateListAnimator(StateListAnimator stateListAnimator) { 13353 if (mStateListAnimator == stateListAnimator) { 13354 return; 13355 } 13356 if (mStateListAnimator != null) { 13357 mStateListAnimator.setTarget(null); 13358 } 13359 mStateListAnimator = stateListAnimator; 13360 if (stateListAnimator != null) { 13361 stateListAnimator.setTarget(this); 13362 if (isAttachedToWindow()) { 13363 stateListAnimator.setState(getDrawableState()); 13364 } 13365 } 13366 } 13367 13368 /** 13369 * Returns whether the Outline should be used to clip the contents of the View. 13370 * <p> 13371 * Note that this flag will only be respected if the View's Outline returns true from 13372 * {@link Outline#canClip()}. 13373 * 13374 * @see #setOutlineProvider(ViewOutlineProvider) 13375 * @see #setClipToOutline(boolean) 13376 */ 13377 public final boolean getClipToOutline() { 13378 return mRenderNode.getClipToOutline(); 13379 } 13380 13381 /** 13382 * Sets whether the View's Outline should be used to clip the contents of the View. 13383 * <p> 13384 * Only a single non-rectangular clip can be applied on a View at any time. 13385 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 13386 * circular reveal} animation take priority over Outline clipping, and 13387 * child Outline clipping takes priority over Outline clipping done by a 13388 * parent. 13389 * <p> 13390 * Note that this flag will only be respected if the View's Outline returns true from 13391 * {@link Outline#canClip()}. 13392 * 13393 * @see #setOutlineProvider(ViewOutlineProvider) 13394 * @see #getClipToOutline() 13395 */ 13396 public void setClipToOutline(boolean clipToOutline) { 13397 damageInParent(); 13398 if (getClipToOutline() != clipToOutline) { 13399 mRenderNode.setClipToOutline(clipToOutline); 13400 } 13401 } 13402 13403 // correspond to the enum values of View_outlineProvider 13404 private static final int PROVIDER_BACKGROUND = 0; 13405 private static final int PROVIDER_NONE = 1; 13406 private static final int PROVIDER_BOUNDS = 2; 13407 private static final int PROVIDER_PADDED_BOUNDS = 3; 13408 private void setOutlineProviderFromAttribute(int providerInt) { 13409 switch (providerInt) { 13410 case PROVIDER_BACKGROUND: 13411 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 13412 break; 13413 case PROVIDER_NONE: 13414 setOutlineProvider(null); 13415 break; 13416 case PROVIDER_BOUNDS: 13417 setOutlineProvider(ViewOutlineProvider.BOUNDS); 13418 break; 13419 case PROVIDER_PADDED_BOUNDS: 13420 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 13421 break; 13422 } 13423 } 13424 13425 /** 13426 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 13427 * the shape of the shadow it casts, and enables outline clipping. 13428 * <p> 13429 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 13430 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 13431 * outline provider with this method allows this behavior to be overridden. 13432 * <p> 13433 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 13434 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 13435 * <p> 13436 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 13437 * 13438 * @see #setClipToOutline(boolean) 13439 * @see #getClipToOutline() 13440 * @see #getOutlineProvider() 13441 */ 13442 public void setOutlineProvider(ViewOutlineProvider provider) { 13443 mOutlineProvider = provider; 13444 invalidateOutline(); 13445 } 13446 13447 /** 13448 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 13449 * that defines the shape of the shadow it casts, and enables outline clipping. 13450 * 13451 * @see #setOutlineProvider(ViewOutlineProvider) 13452 */ 13453 public ViewOutlineProvider getOutlineProvider() { 13454 return mOutlineProvider; 13455 } 13456 13457 /** 13458 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 13459 * 13460 * @see #setOutlineProvider(ViewOutlineProvider) 13461 */ 13462 public void invalidateOutline() { 13463 rebuildOutline(); 13464 13465 notifySubtreeAccessibilityStateChangedIfNeeded(); 13466 invalidateViewProperty(false, false); 13467 } 13468 13469 /** 13470 * Internal version of {@link #invalidateOutline()} which invalidates the 13471 * outline without invalidating the view itself. This is intended to be called from 13472 * within methods in the View class itself which are the result of the view being 13473 * invalidated already. For example, when we are drawing the background of a View, 13474 * we invalidate the outline in case it changed in the meantime, but we do not 13475 * need to invalidate the view because we're already drawing the background as part 13476 * of drawing the view in response to an earlier invalidation of the view. 13477 */ 13478 private void rebuildOutline() { 13479 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 13480 if (mAttachInfo == null) return; 13481 13482 if (mOutlineProvider == null) { 13483 // no provider, remove outline 13484 mRenderNode.setOutline(null); 13485 } else { 13486 final Outline outline = mAttachInfo.mTmpOutline; 13487 outline.setEmpty(); 13488 outline.setAlpha(1.0f); 13489 13490 mOutlineProvider.getOutline(this, outline); 13491 mRenderNode.setOutline(outline); 13492 } 13493 } 13494 13495 /** 13496 * HierarchyViewer only 13497 * 13498 * @hide 13499 */ 13500 @ViewDebug.ExportedProperty(category = "drawing") 13501 public boolean hasShadow() { 13502 return mRenderNode.hasShadow(); 13503 } 13504 13505 13506 /** @hide */ 13507 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 13508 mRenderNode.setRevealClip(shouldClip, x, y, radius); 13509 invalidateViewProperty(false, false); 13510 } 13511 13512 /** 13513 * Hit rectangle in parent's coordinates 13514 * 13515 * @param outRect The hit rectangle of the view. 13516 */ 13517 public void getHitRect(Rect outRect) { 13518 if (hasIdentityMatrix() || mAttachInfo == null) { 13519 outRect.set(mLeft, mTop, mRight, mBottom); 13520 } else { 13521 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 13522 tmpRect.set(0, 0, getWidth(), getHeight()); 13523 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 13524 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 13525 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 13526 } 13527 } 13528 13529 /** 13530 * Determines whether the given point, in local coordinates is inside the view. 13531 */ 13532 /*package*/ final boolean pointInView(float localX, float localY) { 13533 return pointInView(localX, localY, 0); 13534 } 13535 13536 /** 13537 * Utility method to determine whether the given point, in local coordinates, 13538 * is inside the view, where the area of the view is expanded by the slop factor. 13539 * This method is called while processing touch-move events to determine if the event 13540 * is still within the view. 13541 * 13542 * @hide 13543 */ 13544 public boolean pointInView(float localX, float localY, float slop) { 13545 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 13546 localY < ((mBottom - mTop) + slop); 13547 } 13548 13549 /** 13550 * When a view has focus and the user navigates away from it, the next view is searched for 13551 * starting from the rectangle filled in by this method. 13552 * 13553 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 13554 * of the view. However, if your view maintains some idea of internal selection, 13555 * such as a cursor, or a selected row or column, you should override this method and 13556 * fill in a more specific rectangle. 13557 * 13558 * @param r The rectangle to fill in, in this view's coordinates. 13559 */ 13560 public void getFocusedRect(Rect r) { 13561 getDrawingRect(r); 13562 } 13563 13564 /** 13565 * If some part of this view is not clipped by any of its parents, then 13566 * return that area in r in global (root) coordinates. To convert r to local 13567 * coordinates (without taking possible View rotations into account), offset 13568 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 13569 * If the view is completely clipped or translated out, return false. 13570 * 13571 * @param r If true is returned, r holds the global coordinates of the 13572 * visible portion of this view. 13573 * @param globalOffset If true is returned, globalOffset holds the dx,dy 13574 * between this view and its root. globalOffet may be null. 13575 * @return true if r is non-empty (i.e. part of the view is visible at the 13576 * root level. 13577 */ 13578 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 13579 int width = mRight - mLeft; 13580 int height = mBottom - mTop; 13581 if (width > 0 && height > 0) { 13582 r.set(0, 0, width, height); 13583 if (globalOffset != null) { 13584 globalOffset.set(-mScrollX, -mScrollY); 13585 } 13586 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 13587 } 13588 return false; 13589 } 13590 13591 public final boolean getGlobalVisibleRect(Rect r) { 13592 return getGlobalVisibleRect(r, null); 13593 } 13594 13595 public final boolean getLocalVisibleRect(Rect r) { 13596 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 13597 if (getGlobalVisibleRect(r, offset)) { 13598 r.offset(-offset.x, -offset.y); // make r local 13599 return true; 13600 } 13601 return false; 13602 } 13603 13604 /** 13605 * Offset this view's vertical location by the specified number of pixels. 13606 * 13607 * @param offset the number of pixels to offset the view by 13608 */ 13609 public void offsetTopAndBottom(int offset) { 13610 if (offset != 0) { 13611 final boolean matrixIsIdentity = hasIdentityMatrix(); 13612 if (matrixIsIdentity) { 13613 if (isHardwareAccelerated()) { 13614 invalidateViewProperty(false, false); 13615 } else { 13616 final ViewParent p = mParent; 13617 if (p != null && mAttachInfo != null) { 13618 final Rect r = mAttachInfo.mTmpInvalRect; 13619 int minTop; 13620 int maxBottom; 13621 int yLoc; 13622 if (offset < 0) { 13623 minTop = mTop + offset; 13624 maxBottom = mBottom; 13625 yLoc = offset; 13626 } else { 13627 minTop = mTop; 13628 maxBottom = mBottom + offset; 13629 yLoc = 0; 13630 } 13631 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 13632 p.invalidateChild(this, r); 13633 } 13634 } 13635 } else { 13636 invalidateViewProperty(false, false); 13637 } 13638 13639 mTop += offset; 13640 mBottom += offset; 13641 mRenderNode.offsetTopAndBottom(offset); 13642 if (isHardwareAccelerated()) { 13643 invalidateViewProperty(false, false); 13644 invalidateParentIfNeededAndWasQuickRejected(); 13645 } else { 13646 if (!matrixIsIdentity) { 13647 invalidateViewProperty(false, true); 13648 } 13649 invalidateParentIfNeeded(); 13650 } 13651 notifySubtreeAccessibilityStateChangedIfNeeded(); 13652 } 13653 } 13654 13655 /** 13656 * Offset this view's horizontal location by the specified amount of pixels. 13657 * 13658 * @param offset the number of pixels to offset the view by 13659 */ 13660 public void offsetLeftAndRight(int offset) { 13661 if (offset != 0) { 13662 final boolean matrixIsIdentity = hasIdentityMatrix(); 13663 if (matrixIsIdentity) { 13664 if (isHardwareAccelerated()) { 13665 invalidateViewProperty(false, false); 13666 } else { 13667 final ViewParent p = mParent; 13668 if (p != null && mAttachInfo != null) { 13669 final Rect r = mAttachInfo.mTmpInvalRect; 13670 int minLeft; 13671 int maxRight; 13672 if (offset < 0) { 13673 minLeft = mLeft + offset; 13674 maxRight = mRight; 13675 } else { 13676 minLeft = mLeft; 13677 maxRight = mRight + offset; 13678 } 13679 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 13680 p.invalidateChild(this, r); 13681 } 13682 } 13683 } else { 13684 invalidateViewProperty(false, false); 13685 } 13686 13687 mLeft += offset; 13688 mRight += offset; 13689 mRenderNode.offsetLeftAndRight(offset); 13690 if (isHardwareAccelerated()) { 13691 invalidateViewProperty(false, false); 13692 invalidateParentIfNeededAndWasQuickRejected(); 13693 } else { 13694 if (!matrixIsIdentity) { 13695 invalidateViewProperty(false, true); 13696 } 13697 invalidateParentIfNeeded(); 13698 } 13699 notifySubtreeAccessibilityStateChangedIfNeeded(); 13700 } 13701 } 13702 13703 /** 13704 * Get the LayoutParams associated with this view. All views should have 13705 * layout parameters. These supply parameters to the <i>parent</i> of this 13706 * view specifying how it should be arranged. There are many subclasses of 13707 * ViewGroup.LayoutParams, and these correspond to the different subclasses 13708 * of ViewGroup that are responsible for arranging their children. 13709 * 13710 * This method may return null if this View is not attached to a parent 13711 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 13712 * was not invoked successfully. When a View is attached to a parent 13713 * ViewGroup, this method must not return null. 13714 * 13715 * @return The LayoutParams associated with this view, or null if no 13716 * parameters have been set yet 13717 */ 13718 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 13719 public ViewGroup.LayoutParams getLayoutParams() { 13720 return mLayoutParams; 13721 } 13722 13723 /** 13724 * Set the layout parameters associated with this view. These supply 13725 * parameters to the <i>parent</i> of this view specifying how it should be 13726 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 13727 * correspond to the different subclasses of ViewGroup that are responsible 13728 * for arranging their children. 13729 * 13730 * @param params The layout parameters for this view, cannot be null 13731 */ 13732 public void setLayoutParams(ViewGroup.LayoutParams params) { 13733 if (params == null) { 13734 throw new NullPointerException("Layout parameters cannot be null"); 13735 } 13736 mLayoutParams = params; 13737 resolveLayoutParams(); 13738 if (mParent instanceof ViewGroup) { 13739 ((ViewGroup) mParent).onSetLayoutParams(this, params); 13740 } 13741 requestLayout(); 13742 } 13743 13744 /** 13745 * Resolve the layout parameters depending on the resolved layout direction 13746 * 13747 * @hide 13748 */ 13749 public void resolveLayoutParams() { 13750 if (mLayoutParams != null) { 13751 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 13752 } 13753 } 13754 13755 /** 13756 * Set the scrolled position of your view. This will cause a call to 13757 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13758 * invalidated. 13759 * @param x the x position to scroll to 13760 * @param y the y position to scroll to 13761 */ 13762 public void scrollTo(int x, int y) { 13763 if (mScrollX != x || mScrollY != y) { 13764 int oldX = mScrollX; 13765 int oldY = mScrollY; 13766 mScrollX = x; 13767 mScrollY = y; 13768 invalidateParentCaches(); 13769 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 13770 if (!awakenScrollBars()) { 13771 postInvalidateOnAnimation(); 13772 } 13773 } 13774 } 13775 13776 /** 13777 * Move the scrolled position of your view. This will cause a call to 13778 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13779 * invalidated. 13780 * @param x the amount of pixels to scroll by horizontally 13781 * @param y the amount of pixels to scroll by vertically 13782 */ 13783 public void scrollBy(int x, int y) { 13784 scrollTo(mScrollX + x, mScrollY + y); 13785 } 13786 13787 /** 13788 * <p>Trigger the scrollbars to draw. When invoked this method starts an 13789 * animation to fade the scrollbars out after a default delay. If a subclass 13790 * provides animated scrolling, the start delay should equal the duration 13791 * of the scrolling animation.</p> 13792 * 13793 * <p>The animation starts only if at least one of the scrollbars is 13794 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 13795 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 13796 * this method returns true, and false otherwise. If the animation is 13797 * started, this method calls {@link #invalidate()}; in that case the 13798 * caller should not call {@link #invalidate()}.</p> 13799 * 13800 * <p>This method should be invoked every time a subclass directly updates 13801 * the scroll parameters.</p> 13802 * 13803 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 13804 * and {@link #scrollTo(int, int)}.</p> 13805 * 13806 * @return true if the animation is played, false otherwise 13807 * 13808 * @see #awakenScrollBars(int) 13809 * @see #scrollBy(int, int) 13810 * @see #scrollTo(int, int) 13811 * @see #isHorizontalScrollBarEnabled() 13812 * @see #isVerticalScrollBarEnabled() 13813 * @see #setHorizontalScrollBarEnabled(boolean) 13814 * @see #setVerticalScrollBarEnabled(boolean) 13815 */ 13816 protected boolean awakenScrollBars() { 13817 return mScrollCache != null && 13818 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 13819 } 13820 13821 /** 13822 * Trigger the scrollbars to draw. 13823 * This method differs from awakenScrollBars() only in its default duration. 13824 * initialAwakenScrollBars() will show the scroll bars for longer than 13825 * usual to give the user more of a chance to notice them. 13826 * 13827 * @return true if the animation is played, false otherwise. 13828 */ 13829 private boolean initialAwakenScrollBars() { 13830 return mScrollCache != null && 13831 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 13832 } 13833 13834 /** 13835 * <p> 13836 * Trigger the scrollbars to draw. When invoked this method starts an 13837 * animation to fade the scrollbars out after a fixed delay. If a subclass 13838 * provides animated scrolling, the start delay should equal the duration of 13839 * the scrolling animation. 13840 * </p> 13841 * 13842 * <p> 13843 * The animation starts only if at least one of the scrollbars is enabled, 13844 * as specified by {@link #isHorizontalScrollBarEnabled()} and 13845 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 13846 * this method returns true, and false otherwise. If the animation is 13847 * started, this method calls {@link #invalidate()}; in that case the caller 13848 * should not call {@link #invalidate()}. 13849 * </p> 13850 * 13851 * <p> 13852 * This method should be invoked every time a subclass directly updates the 13853 * scroll parameters. 13854 * </p> 13855 * 13856 * @param startDelay the delay, in milliseconds, after which the animation 13857 * should start; when the delay is 0, the animation starts 13858 * immediately 13859 * @return true if the animation is played, false otherwise 13860 * 13861 * @see #scrollBy(int, int) 13862 * @see #scrollTo(int, int) 13863 * @see #isHorizontalScrollBarEnabled() 13864 * @see #isVerticalScrollBarEnabled() 13865 * @see #setHorizontalScrollBarEnabled(boolean) 13866 * @see #setVerticalScrollBarEnabled(boolean) 13867 */ 13868 protected boolean awakenScrollBars(int startDelay) { 13869 return awakenScrollBars(startDelay, true); 13870 } 13871 13872 /** 13873 * <p> 13874 * Trigger the scrollbars to draw. When invoked this method starts an 13875 * animation to fade the scrollbars out after a fixed delay. If a subclass 13876 * provides animated scrolling, the start delay should equal the duration of 13877 * the scrolling animation. 13878 * </p> 13879 * 13880 * <p> 13881 * The animation starts only if at least one of the scrollbars is enabled, 13882 * as specified by {@link #isHorizontalScrollBarEnabled()} and 13883 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 13884 * this method returns true, and false otherwise. If the animation is 13885 * started, this method calls {@link #invalidate()} if the invalidate parameter 13886 * is set to true; in that case the caller 13887 * should not call {@link #invalidate()}. 13888 * </p> 13889 * 13890 * <p> 13891 * This method should be invoked every time a subclass directly updates the 13892 * scroll parameters. 13893 * </p> 13894 * 13895 * @param startDelay the delay, in milliseconds, after which the animation 13896 * should start; when the delay is 0, the animation starts 13897 * immediately 13898 * 13899 * @param invalidate Whether this method should call invalidate 13900 * 13901 * @return true if the animation is played, false otherwise 13902 * 13903 * @see #scrollBy(int, int) 13904 * @see #scrollTo(int, int) 13905 * @see #isHorizontalScrollBarEnabled() 13906 * @see #isVerticalScrollBarEnabled() 13907 * @see #setHorizontalScrollBarEnabled(boolean) 13908 * @see #setVerticalScrollBarEnabled(boolean) 13909 */ 13910 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 13911 final ScrollabilityCache scrollCache = mScrollCache; 13912 13913 if (scrollCache == null || !scrollCache.fadeScrollBars) { 13914 return false; 13915 } 13916 13917 if (scrollCache.scrollBar == null) { 13918 scrollCache.scrollBar = new ScrollBarDrawable(); 13919 scrollCache.scrollBar.setState(getDrawableState()); 13920 scrollCache.scrollBar.setCallback(this); 13921 } 13922 13923 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 13924 13925 if (invalidate) { 13926 // Invalidate to show the scrollbars 13927 postInvalidateOnAnimation(); 13928 } 13929 13930 if (scrollCache.state == ScrollabilityCache.OFF) { 13931 // FIXME: this is copied from WindowManagerService. 13932 // We should get this value from the system when it 13933 // is possible to do so. 13934 final int KEY_REPEAT_FIRST_DELAY = 750; 13935 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 13936 } 13937 13938 // Tell mScrollCache when we should start fading. This may 13939 // extend the fade start time if one was already scheduled 13940 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 13941 scrollCache.fadeStartTime = fadeStartTime; 13942 scrollCache.state = ScrollabilityCache.ON; 13943 13944 // Schedule our fader to run, unscheduling any old ones first 13945 if (mAttachInfo != null) { 13946 mAttachInfo.mHandler.removeCallbacks(scrollCache); 13947 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 13948 } 13949 13950 return true; 13951 } 13952 13953 return false; 13954 } 13955 13956 /** 13957 * Do not invalidate views which are not visible and which are not running an animation. They 13958 * will not get drawn and they should not set dirty flags as if they will be drawn 13959 */ 13960 private boolean skipInvalidate() { 13961 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 13962 (!(mParent instanceof ViewGroup) || 13963 !((ViewGroup) mParent).isViewTransitioning(this)); 13964 } 13965 13966 /** 13967 * Mark the area defined by dirty as needing to be drawn. If the view is 13968 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 13969 * point in the future. 13970 * <p> 13971 * This must be called from a UI thread. To call from a non-UI thread, call 13972 * {@link #postInvalidate()}. 13973 * <p> 13974 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 13975 * {@code dirty}. 13976 * 13977 * @param dirty the rectangle representing the bounds of the dirty region 13978 */ 13979 public void invalidate(Rect dirty) { 13980 final int scrollX = mScrollX; 13981 final int scrollY = mScrollY; 13982 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 13983 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 13984 } 13985 13986 /** 13987 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 13988 * coordinates of the dirty rect are relative to the view. If the view is 13989 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 13990 * point in the future. 13991 * <p> 13992 * This must be called from a UI thread. To call from a non-UI thread, call 13993 * {@link #postInvalidate()}. 13994 * 13995 * @param l the left position of the dirty region 13996 * @param t the top position of the dirty region 13997 * @param r the right position of the dirty region 13998 * @param b the bottom position of the dirty region 13999 */ 14000 public void invalidate(int l, int t, int r, int b) { 14001 final int scrollX = mScrollX; 14002 final int scrollY = mScrollY; 14003 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 14004 } 14005 14006 /** 14007 * Invalidate the whole view. If the view is visible, 14008 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 14009 * the future. 14010 * <p> 14011 * This must be called from a UI thread. To call from a non-UI thread, call 14012 * {@link #postInvalidate()}. 14013 */ 14014 public void invalidate() { 14015 invalidate(true); 14016 } 14017 14018 /** 14019 * This is where the invalidate() work actually happens. A full invalidate() 14020 * causes the drawing cache to be invalidated, but this function can be 14021 * called with invalidateCache set to false to skip that invalidation step 14022 * for cases that do not need it (for example, a component that remains at 14023 * the same dimensions with the same content). 14024 * 14025 * @param invalidateCache Whether the drawing cache for this view should be 14026 * invalidated as well. This is usually true for a full 14027 * invalidate, but may be set to false if the View's contents or 14028 * dimensions have not changed. 14029 */ 14030 void invalidate(boolean invalidateCache) { 14031 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 14032 } 14033 14034 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 14035 boolean fullInvalidate) { 14036 if (mGhostView != null) { 14037 mGhostView.invalidate(true); 14038 return; 14039 } 14040 14041 if (skipInvalidate()) { 14042 return; 14043 } 14044 14045 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 14046 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 14047 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 14048 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 14049 if (fullInvalidate) { 14050 mLastIsOpaque = isOpaque(); 14051 mPrivateFlags &= ~PFLAG_DRAWN; 14052 } 14053 14054 mPrivateFlags |= PFLAG_DIRTY; 14055 14056 if (invalidateCache) { 14057 mPrivateFlags |= PFLAG_INVALIDATED; 14058 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 14059 } 14060 14061 // Propagate the damage rectangle to the parent view. 14062 final AttachInfo ai = mAttachInfo; 14063 final ViewParent p = mParent; 14064 if (p != null && ai != null && l < r && t < b) { 14065 final Rect damage = ai.mTmpInvalRect; 14066 damage.set(l, t, r, b); 14067 p.invalidateChild(this, damage); 14068 } 14069 14070 // Damage the entire projection receiver, if necessary. 14071 if (mBackground != null && mBackground.isProjected()) { 14072 final View receiver = getProjectionReceiver(); 14073 if (receiver != null) { 14074 receiver.damageInParent(); 14075 } 14076 } 14077 } 14078 } 14079 14080 /** 14081 * @return this view's projection receiver, or {@code null} if none exists 14082 */ 14083 private View getProjectionReceiver() { 14084 ViewParent p = getParent(); 14085 while (p != null && p instanceof View) { 14086 final View v = (View) p; 14087 if (v.isProjectionReceiver()) { 14088 return v; 14089 } 14090 p = p.getParent(); 14091 } 14092 14093 return null; 14094 } 14095 14096 /** 14097 * @return whether the view is a projection receiver 14098 */ 14099 private boolean isProjectionReceiver() { 14100 return mBackground != null; 14101 } 14102 14103 /** 14104 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 14105 * set any flags or handle all of the cases handled by the default invalidation methods. 14106 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 14107 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 14108 * walk up the hierarchy, transforming the dirty rect as necessary. 14109 * 14110 * The method also handles normal invalidation logic if display list properties are not 14111 * being used in this view. The invalidateParent and forceRedraw flags are used by that 14112 * backup approach, to handle these cases used in the various property-setting methods. 14113 * 14114 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 14115 * are not being used in this view 14116 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 14117 * list properties are not being used in this view 14118 */ 14119 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 14120 if (!isHardwareAccelerated() 14121 || !mRenderNode.isValid() 14122 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 14123 if (invalidateParent) { 14124 invalidateParentCaches(); 14125 } 14126 if (forceRedraw) { 14127 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14128 } 14129 invalidate(false); 14130 } else { 14131 damageInParent(); 14132 } 14133 } 14134 14135 /** 14136 * Tells the parent view to damage this view's bounds. 14137 * 14138 * @hide 14139 */ 14140 protected void damageInParent() { 14141 final AttachInfo ai = mAttachInfo; 14142 final ViewParent p = mParent; 14143 if (p != null && ai != null) { 14144 final Rect r = ai.mTmpInvalRect; 14145 r.set(0, 0, mRight - mLeft, mBottom - mTop); 14146 if (mParent instanceof ViewGroup) { 14147 ((ViewGroup) mParent).damageChild(this, r); 14148 } else { 14149 mParent.invalidateChild(this, r); 14150 } 14151 } 14152 } 14153 14154 /** 14155 * Utility method to transform a given Rect by the current matrix of this view. 14156 */ 14157 void transformRect(final Rect rect) { 14158 if (!getMatrix().isIdentity()) { 14159 RectF boundingRect = mAttachInfo.mTmpTransformRect; 14160 boundingRect.set(rect); 14161 getMatrix().mapRect(boundingRect); 14162 rect.set((int) Math.floor(boundingRect.left), 14163 (int) Math.floor(boundingRect.top), 14164 (int) Math.ceil(boundingRect.right), 14165 (int) Math.ceil(boundingRect.bottom)); 14166 } 14167 } 14168 14169 /** 14170 * Used to indicate that the parent of this view should clear its caches. This functionality 14171 * is used to force the parent to rebuild its display list (when hardware-accelerated), 14172 * which is necessary when various parent-managed properties of the view change, such as 14173 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 14174 * clears the parent caches and does not causes an invalidate event. 14175 * 14176 * @hide 14177 */ 14178 protected void invalidateParentCaches() { 14179 if (mParent instanceof View) { 14180 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 14181 } 14182 } 14183 14184 /** 14185 * Used to indicate that the parent of this view should be invalidated. This functionality 14186 * is used to force the parent to rebuild its display list (when hardware-accelerated), 14187 * which is necessary when various parent-managed properties of the view change, such as 14188 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 14189 * an invalidation event to the parent. 14190 * 14191 * @hide 14192 */ 14193 protected void invalidateParentIfNeeded() { 14194 if (isHardwareAccelerated() && mParent instanceof View) { 14195 ((View) mParent).invalidate(true); 14196 } 14197 } 14198 14199 /** 14200 * @hide 14201 */ 14202 protected void invalidateParentIfNeededAndWasQuickRejected() { 14203 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 14204 // View was rejected last time it was drawn by its parent; this may have changed 14205 invalidateParentIfNeeded(); 14206 } 14207 } 14208 14209 /** 14210 * Indicates whether this View is opaque. An opaque View guarantees that it will 14211 * draw all the pixels overlapping its bounds using a fully opaque color. 14212 * 14213 * Subclasses of View should override this method whenever possible to indicate 14214 * whether an instance is opaque. Opaque Views are treated in a special way by 14215 * the View hierarchy, possibly allowing it to perform optimizations during 14216 * invalidate/draw passes. 14217 * 14218 * @return True if this View is guaranteed to be fully opaque, false otherwise. 14219 */ 14220 @ViewDebug.ExportedProperty(category = "drawing") 14221 public boolean isOpaque() { 14222 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 14223 getFinalAlpha() >= 1.0f; 14224 } 14225 14226 /** 14227 * @hide 14228 */ 14229 protected void computeOpaqueFlags() { 14230 // Opaque if: 14231 // - Has a background 14232 // - Background is opaque 14233 // - Doesn't have scrollbars or scrollbars overlay 14234 14235 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 14236 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 14237 } else { 14238 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 14239 } 14240 14241 final int flags = mViewFlags; 14242 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 14243 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 14244 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 14245 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 14246 } else { 14247 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 14248 } 14249 } 14250 14251 /** 14252 * @hide 14253 */ 14254 protected boolean hasOpaqueScrollbars() { 14255 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 14256 } 14257 14258 /** 14259 * @return A handler associated with the thread running the View. This 14260 * handler can be used to pump events in the UI events queue. 14261 */ 14262 public Handler getHandler() { 14263 final AttachInfo attachInfo = mAttachInfo; 14264 if (attachInfo != null) { 14265 return attachInfo.mHandler; 14266 } 14267 return null; 14268 } 14269 14270 /** 14271 * Returns the queue of runnable for this view. 14272 * 14273 * @return the queue of runnables for this view 14274 */ 14275 private HandlerActionQueue getRunQueue() { 14276 if (mRunQueue == null) { 14277 mRunQueue = new HandlerActionQueue(); 14278 } 14279 return mRunQueue; 14280 } 14281 14282 /** 14283 * Gets the view root associated with the View. 14284 * @return The view root, or null if none. 14285 * @hide 14286 */ 14287 public ViewRootImpl getViewRootImpl() { 14288 if (mAttachInfo != null) { 14289 return mAttachInfo.mViewRootImpl; 14290 } 14291 return null; 14292 } 14293 14294 /** 14295 * @hide 14296 */ 14297 public ThreadedRenderer getThreadedRenderer() { 14298 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 14299 } 14300 14301 /** 14302 * <p>Causes the Runnable to be added to the message queue. 14303 * The runnable will be run on the user interface thread.</p> 14304 * 14305 * @param action The Runnable that will be executed. 14306 * 14307 * @return Returns true if the Runnable was successfully placed in to the 14308 * message queue. Returns false on failure, usually because the 14309 * looper processing the message queue is exiting. 14310 * 14311 * @see #postDelayed 14312 * @see #removeCallbacks 14313 */ 14314 public boolean post(Runnable action) { 14315 final AttachInfo attachInfo = mAttachInfo; 14316 if (attachInfo != null) { 14317 return attachInfo.mHandler.post(action); 14318 } 14319 14320 // Postpone the runnable until we know on which thread it needs to run. 14321 // Assume that the runnable will be successfully placed after attach. 14322 getRunQueue().post(action); 14323 return true; 14324 } 14325 14326 /** 14327 * <p>Causes the Runnable to be added to the message queue, to be run 14328 * after the specified amount of time elapses. 14329 * The runnable will be run on the user interface thread.</p> 14330 * 14331 * @param action The Runnable that will be executed. 14332 * @param delayMillis The delay (in milliseconds) until the Runnable 14333 * will be executed. 14334 * 14335 * @return true if the Runnable was successfully placed in to the 14336 * message queue. Returns false on failure, usually because the 14337 * looper processing the message queue is exiting. Note that a 14338 * result of true does not mean the Runnable will be processed -- 14339 * if the looper is quit before the delivery time of the message 14340 * occurs then the message will be dropped. 14341 * 14342 * @see #post 14343 * @see #removeCallbacks 14344 */ 14345 public boolean postDelayed(Runnable action, long delayMillis) { 14346 final AttachInfo attachInfo = mAttachInfo; 14347 if (attachInfo != null) { 14348 return attachInfo.mHandler.postDelayed(action, delayMillis); 14349 } 14350 14351 // Postpone the runnable until we know on which thread it needs to run. 14352 // Assume that the runnable will be successfully placed after attach. 14353 getRunQueue().postDelayed(action, delayMillis); 14354 return true; 14355 } 14356 14357 /** 14358 * <p>Causes the Runnable to execute on the next animation time step. 14359 * The runnable will be run on the user interface thread.</p> 14360 * 14361 * @param action The Runnable that will be executed. 14362 * 14363 * @see #postOnAnimationDelayed 14364 * @see #removeCallbacks 14365 */ 14366 public void postOnAnimation(Runnable action) { 14367 final AttachInfo attachInfo = mAttachInfo; 14368 if (attachInfo != null) { 14369 attachInfo.mViewRootImpl.mChoreographer.postCallback( 14370 Choreographer.CALLBACK_ANIMATION, action, null); 14371 } else { 14372 // Postpone the runnable until we know 14373 // on which thread it needs to run. 14374 getRunQueue().post(action); 14375 } 14376 } 14377 14378 /** 14379 * <p>Causes the Runnable to execute on the next animation time step, 14380 * after the specified amount of time elapses. 14381 * The runnable will be run on the user interface thread.</p> 14382 * 14383 * @param action The Runnable that will be executed. 14384 * @param delayMillis The delay (in milliseconds) until the Runnable 14385 * will be executed. 14386 * 14387 * @see #postOnAnimation 14388 * @see #removeCallbacks 14389 */ 14390 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 14391 final AttachInfo attachInfo = mAttachInfo; 14392 if (attachInfo != null) { 14393 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 14394 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 14395 } else { 14396 // Postpone the runnable until we know 14397 // on which thread it needs to run. 14398 getRunQueue().postDelayed(action, delayMillis); 14399 } 14400 } 14401 14402 /** 14403 * <p>Removes the specified Runnable from the message queue.</p> 14404 * 14405 * @param action The Runnable to remove from the message handling queue 14406 * 14407 * @return true if this view could ask the Handler to remove the Runnable, 14408 * false otherwise. When the returned value is true, the Runnable 14409 * may or may not have been actually removed from the message queue 14410 * (for instance, if the Runnable was not in the queue already.) 14411 * 14412 * @see #post 14413 * @see #postDelayed 14414 * @see #postOnAnimation 14415 * @see #postOnAnimationDelayed 14416 */ 14417 public boolean removeCallbacks(Runnable action) { 14418 if (action != null) { 14419 final AttachInfo attachInfo = mAttachInfo; 14420 if (attachInfo != null) { 14421 attachInfo.mHandler.removeCallbacks(action); 14422 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 14423 Choreographer.CALLBACK_ANIMATION, action, null); 14424 } 14425 getRunQueue().removeCallbacks(action); 14426 } 14427 return true; 14428 } 14429 14430 /** 14431 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 14432 * Use this to invalidate the View from a non-UI thread.</p> 14433 * 14434 * <p>This method can be invoked from outside of the UI thread 14435 * only when this View is attached to a window.</p> 14436 * 14437 * @see #invalidate() 14438 * @see #postInvalidateDelayed(long) 14439 */ 14440 public void postInvalidate() { 14441 postInvalidateDelayed(0); 14442 } 14443 14444 /** 14445 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14446 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 14447 * 14448 * <p>This method can be invoked from outside of the UI thread 14449 * only when this View is attached to a window.</p> 14450 * 14451 * @param left The left coordinate of the rectangle to invalidate. 14452 * @param top The top coordinate of the rectangle to invalidate. 14453 * @param right The right coordinate of the rectangle to invalidate. 14454 * @param bottom The bottom coordinate of the rectangle to invalidate. 14455 * 14456 * @see #invalidate(int, int, int, int) 14457 * @see #invalidate(Rect) 14458 * @see #postInvalidateDelayed(long, int, int, int, int) 14459 */ 14460 public void postInvalidate(int left, int top, int right, int bottom) { 14461 postInvalidateDelayed(0, left, top, right, bottom); 14462 } 14463 14464 /** 14465 * <p>Cause an invalidate to happen on a subsequent cycle through the event 14466 * loop. Waits for the specified amount of time.</p> 14467 * 14468 * <p>This method can be invoked from outside of the UI thread 14469 * only when this View is attached to a window.</p> 14470 * 14471 * @param delayMilliseconds the duration in milliseconds to delay the 14472 * invalidation by 14473 * 14474 * @see #invalidate() 14475 * @see #postInvalidate() 14476 */ 14477 public void postInvalidateDelayed(long delayMilliseconds) { 14478 // We try only with the AttachInfo because there's no point in invalidating 14479 // if we are not attached to our window 14480 final AttachInfo attachInfo = mAttachInfo; 14481 if (attachInfo != null) { 14482 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 14483 } 14484 } 14485 14486 /** 14487 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14488 * through the event loop. Waits for the specified amount of time.</p> 14489 * 14490 * <p>This method can be invoked from outside of the UI thread 14491 * only when this View is attached to a window.</p> 14492 * 14493 * @param delayMilliseconds the duration in milliseconds to delay the 14494 * invalidation by 14495 * @param left The left coordinate of the rectangle to invalidate. 14496 * @param top The top coordinate of the rectangle to invalidate. 14497 * @param right The right coordinate of the rectangle to invalidate. 14498 * @param bottom The bottom coordinate of the rectangle to invalidate. 14499 * 14500 * @see #invalidate(int, int, int, int) 14501 * @see #invalidate(Rect) 14502 * @see #postInvalidate(int, int, int, int) 14503 */ 14504 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 14505 int right, int bottom) { 14506 14507 // We try only with the AttachInfo because there's no point in invalidating 14508 // if we are not attached to our window 14509 final AttachInfo attachInfo = mAttachInfo; 14510 if (attachInfo != null) { 14511 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14512 info.target = this; 14513 info.left = left; 14514 info.top = top; 14515 info.right = right; 14516 info.bottom = bottom; 14517 14518 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 14519 } 14520 } 14521 14522 /** 14523 * <p>Cause an invalidate to happen on the next animation time step, typically the 14524 * next display frame.</p> 14525 * 14526 * <p>This method can be invoked from outside of the UI thread 14527 * only when this View is attached to a window.</p> 14528 * 14529 * @see #invalidate() 14530 */ 14531 public void postInvalidateOnAnimation() { 14532 // We try only with the AttachInfo because there's no point in invalidating 14533 // if we are not attached to our window 14534 final AttachInfo attachInfo = mAttachInfo; 14535 if (attachInfo != null) { 14536 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 14537 } 14538 } 14539 14540 /** 14541 * <p>Cause an invalidate of the specified area to happen on the next animation 14542 * time step, typically the next display frame.</p> 14543 * 14544 * <p>This method can be invoked from outside of the UI thread 14545 * only when this View is attached to a window.</p> 14546 * 14547 * @param left The left coordinate of the rectangle to invalidate. 14548 * @param top The top coordinate of the rectangle to invalidate. 14549 * @param right The right coordinate of the rectangle to invalidate. 14550 * @param bottom The bottom coordinate of the rectangle to invalidate. 14551 * 14552 * @see #invalidate(int, int, int, int) 14553 * @see #invalidate(Rect) 14554 */ 14555 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 14556 // We try only with the AttachInfo because there's no point in invalidating 14557 // if we are not attached to our window 14558 final AttachInfo attachInfo = mAttachInfo; 14559 if (attachInfo != null) { 14560 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14561 info.target = this; 14562 info.left = left; 14563 info.top = top; 14564 info.right = right; 14565 info.bottom = bottom; 14566 14567 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 14568 } 14569 } 14570 14571 /** 14572 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 14573 * This event is sent at most once every 14574 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 14575 */ 14576 private void postSendViewScrolledAccessibilityEventCallback() { 14577 if (mSendViewScrolledAccessibilityEvent == null) { 14578 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 14579 } 14580 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 14581 mSendViewScrolledAccessibilityEvent.mIsPending = true; 14582 postDelayed(mSendViewScrolledAccessibilityEvent, 14583 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 14584 } 14585 } 14586 14587 /** 14588 * Called by a parent to request that a child update its values for mScrollX 14589 * and mScrollY if necessary. This will typically be done if the child is 14590 * animating a scroll using a {@link android.widget.Scroller Scroller} 14591 * object. 14592 */ 14593 public void computeScroll() { 14594 } 14595 14596 /** 14597 * <p>Indicate whether the horizontal edges are faded when the view is 14598 * scrolled horizontally.</p> 14599 * 14600 * @return true if the horizontal edges should are faded on scroll, false 14601 * otherwise 14602 * 14603 * @see #setHorizontalFadingEdgeEnabled(boolean) 14604 * 14605 * @attr ref android.R.styleable#View_requiresFadingEdge 14606 */ 14607 public boolean isHorizontalFadingEdgeEnabled() { 14608 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 14609 } 14610 14611 /** 14612 * <p>Define whether the horizontal edges should be faded when this view 14613 * is scrolled horizontally.</p> 14614 * 14615 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 14616 * be faded when the view is scrolled 14617 * horizontally 14618 * 14619 * @see #isHorizontalFadingEdgeEnabled() 14620 * 14621 * @attr ref android.R.styleable#View_requiresFadingEdge 14622 */ 14623 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 14624 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 14625 if (horizontalFadingEdgeEnabled) { 14626 initScrollCache(); 14627 } 14628 14629 mViewFlags ^= FADING_EDGE_HORIZONTAL; 14630 } 14631 } 14632 14633 /** 14634 * <p>Indicate whether the vertical edges are faded when the view is 14635 * scrolled horizontally.</p> 14636 * 14637 * @return true if the vertical edges should are faded on scroll, false 14638 * otherwise 14639 * 14640 * @see #setVerticalFadingEdgeEnabled(boolean) 14641 * 14642 * @attr ref android.R.styleable#View_requiresFadingEdge 14643 */ 14644 public boolean isVerticalFadingEdgeEnabled() { 14645 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 14646 } 14647 14648 /** 14649 * <p>Define whether the vertical edges should be faded when this view 14650 * is scrolled vertically.</p> 14651 * 14652 * @param verticalFadingEdgeEnabled true if the vertical edges should 14653 * be faded when the view is scrolled 14654 * vertically 14655 * 14656 * @see #isVerticalFadingEdgeEnabled() 14657 * 14658 * @attr ref android.R.styleable#View_requiresFadingEdge 14659 */ 14660 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 14661 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 14662 if (verticalFadingEdgeEnabled) { 14663 initScrollCache(); 14664 } 14665 14666 mViewFlags ^= FADING_EDGE_VERTICAL; 14667 } 14668 } 14669 14670 /** 14671 * Returns the strength, or intensity, of the top faded edge. The strength is 14672 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14673 * returns 0.0 or 1.0 but no value in between. 14674 * 14675 * Subclasses should override this method to provide a smoother fade transition 14676 * when scrolling occurs. 14677 * 14678 * @return the intensity of the top fade as a float between 0.0f and 1.0f 14679 */ 14680 protected float getTopFadingEdgeStrength() { 14681 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 14682 } 14683 14684 /** 14685 * Returns the strength, or intensity, of the bottom faded edge. The strength is 14686 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14687 * returns 0.0 or 1.0 but no value in between. 14688 * 14689 * Subclasses should override this method to provide a smoother fade transition 14690 * when scrolling occurs. 14691 * 14692 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 14693 */ 14694 protected float getBottomFadingEdgeStrength() { 14695 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 14696 computeVerticalScrollRange() ? 1.0f : 0.0f; 14697 } 14698 14699 /** 14700 * Returns the strength, or intensity, of the left faded edge. The strength is 14701 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14702 * returns 0.0 or 1.0 but no value in between. 14703 * 14704 * Subclasses should override this method to provide a smoother fade transition 14705 * when scrolling occurs. 14706 * 14707 * @return the intensity of the left fade as a float between 0.0f and 1.0f 14708 */ 14709 protected float getLeftFadingEdgeStrength() { 14710 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 14711 } 14712 14713 /** 14714 * Returns the strength, or intensity, of the right faded edge. The strength is 14715 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14716 * returns 0.0 or 1.0 but no value in between. 14717 * 14718 * Subclasses should override this method to provide a smoother fade transition 14719 * when scrolling occurs. 14720 * 14721 * @return the intensity of the right fade as a float between 0.0f and 1.0f 14722 */ 14723 protected float getRightFadingEdgeStrength() { 14724 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 14725 computeHorizontalScrollRange() ? 1.0f : 0.0f; 14726 } 14727 14728 /** 14729 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 14730 * scrollbar is not drawn by default.</p> 14731 * 14732 * @return true if the horizontal scrollbar should be painted, false 14733 * otherwise 14734 * 14735 * @see #setHorizontalScrollBarEnabled(boolean) 14736 */ 14737 public boolean isHorizontalScrollBarEnabled() { 14738 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 14739 } 14740 14741 /** 14742 * <p>Define whether the horizontal scrollbar should be drawn or not. The 14743 * scrollbar is not drawn by default.</p> 14744 * 14745 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 14746 * be painted 14747 * 14748 * @see #isHorizontalScrollBarEnabled() 14749 */ 14750 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 14751 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 14752 mViewFlags ^= SCROLLBARS_HORIZONTAL; 14753 computeOpaqueFlags(); 14754 resolvePadding(); 14755 } 14756 } 14757 14758 /** 14759 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 14760 * scrollbar is not drawn by default.</p> 14761 * 14762 * @return true if the vertical scrollbar should be painted, false 14763 * otherwise 14764 * 14765 * @see #setVerticalScrollBarEnabled(boolean) 14766 */ 14767 public boolean isVerticalScrollBarEnabled() { 14768 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 14769 } 14770 14771 /** 14772 * <p>Define whether the vertical scrollbar should be drawn or not. The 14773 * scrollbar is not drawn by default.</p> 14774 * 14775 * @param verticalScrollBarEnabled true if the vertical scrollbar should 14776 * be painted 14777 * 14778 * @see #isVerticalScrollBarEnabled() 14779 */ 14780 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 14781 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 14782 mViewFlags ^= SCROLLBARS_VERTICAL; 14783 computeOpaqueFlags(); 14784 resolvePadding(); 14785 } 14786 } 14787 14788 /** 14789 * @hide 14790 */ 14791 protected void recomputePadding() { 14792 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 14793 } 14794 14795 /** 14796 * Define whether scrollbars will fade when the view is not scrolling. 14797 * 14798 * @param fadeScrollbars whether to enable fading 14799 * 14800 * @attr ref android.R.styleable#View_fadeScrollbars 14801 */ 14802 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 14803 initScrollCache(); 14804 final ScrollabilityCache scrollabilityCache = mScrollCache; 14805 scrollabilityCache.fadeScrollBars = fadeScrollbars; 14806 if (fadeScrollbars) { 14807 scrollabilityCache.state = ScrollabilityCache.OFF; 14808 } else { 14809 scrollabilityCache.state = ScrollabilityCache.ON; 14810 } 14811 } 14812 14813 /** 14814 * 14815 * Returns true if scrollbars will fade when this view is not scrolling 14816 * 14817 * @return true if scrollbar fading is enabled 14818 * 14819 * @attr ref android.R.styleable#View_fadeScrollbars 14820 */ 14821 public boolean isScrollbarFadingEnabled() { 14822 return mScrollCache != null && mScrollCache.fadeScrollBars; 14823 } 14824 14825 /** 14826 * 14827 * Returns the delay before scrollbars fade. 14828 * 14829 * @return the delay before scrollbars fade 14830 * 14831 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 14832 */ 14833 public int getScrollBarDefaultDelayBeforeFade() { 14834 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 14835 mScrollCache.scrollBarDefaultDelayBeforeFade; 14836 } 14837 14838 /** 14839 * Define the delay before scrollbars fade. 14840 * 14841 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 14842 * 14843 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 14844 */ 14845 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 14846 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 14847 } 14848 14849 /** 14850 * 14851 * Returns the scrollbar fade duration. 14852 * 14853 * @return the scrollbar fade duration, in milliseconds 14854 * 14855 * @attr ref android.R.styleable#View_scrollbarFadeDuration 14856 */ 14857 public int getScrollBarFadeDuration() { 14858 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 14859 mScrollCache.scrollBarFadeDuration; 14860 } 14861 14862 /** 14863 * Define the scrollbar fade duration. 14864 * 14865 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 14866 * 14867 * @attr ref android.R.styleable#View_scrollbarFadeDuration 14868 */ 14869 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 14870 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 14871 } 14872 14873 /** 14874 * 14875 * Returns the scrollbar size. 14876 * 14877 * @return the scrollbar size 14878 * 14879 * @attr ref android.R.styleable#View_scrollbarSize 14880 */ 14881 public int getScrollBarSize() { 14882 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 14883 mScrollCache.scrollBarSize; 14884 } 14885 14886 /** 14887 * Define the scrollbar size. 14888 * 14889 * @param scrollBarSize - the scrollbar size 14890 * 14891 * @attr ref android.R.styleable#View_scrollbarSize 14892 */ 14893 public void setScrollBarSize(int scrollBarSize) { 14894 getScrollCache().scrollBarSize = scrollBarSize; 14895 } 14896 14897 /** 14898 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 14899 * inset. When inset, they add to the padding of the view. And the scrollbars 14900 * can be drawn inside the padding area or on the edge of the view. For example, 14901 * if a view has a background drawable and you want to draw the scrollbars 14902 * inside the padding specified by the drawable, you can use 14903 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 14904 * appear at the edge of the view, ignoring the padding, then you can use 14905 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 14906 * @param style the style of the scrollbars. Should be one of 14907 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 14908 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 14909 * @see #SCROLLBARS_INSIDE_OVERLAY 14910 * @see #SCROLLBARS_INSIDE_INSET 14911 * @see #SCROLLBARS_OUTSIDE_OVERLAY 14912 * @see #SCROLLBARS_OUTSIDE_INSET 14913 * 14914 * @attr ref android.R.styleable#View_scrollbarStyle 14915 */ 14916 public void setScrollBarStyle(@ScrollBarStyle int style) { 14917 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 14918 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 14919 computeOpaqueFlags(); 14920 resolvePadding(); 14921 } 14922 } 14923 14924 /** 14925 * <p>Returns the current scrollbar style.</p> 14926 * @return the current scrollbar style 14927 * @see #SCROLLBARS_INSIDE_OVERLAY 14928 * @see #SCROLLBARS_INSIDE_INSET 14929 * @see #SCROLLBARS_OUTSIDE_OVERLAY 14930 * @see #SCROLLBARS_OUTSIDE_INSET 14931 * 14932 * @attr ref android.R.styleable#View_scrollbarStyle 14933 */ 14934 @ViewDebug.ExportedProperty(mapping = { 14935 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 14936 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 14937 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 14938 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 14939 }) 14940 @ScrollBarStyle 14941 public int getScrollBarStyle() { 14942 return mViewFlags & SCROLLBARS_STYLE_MASK; 14943 } 14944 14945 /** 14946 * <p>Compute the horizontal range that the horizontal scrollbar 14947 * represents.</p> 14948 * 14949 * <p>The range is expressed in arbitrary units that must be the same as the 14950 * units used by {@link #computeHorizontalScrollExtent()} and 14951 * {@link #computeHorizontalScrollOffset()}.</p> 14952 * 14953 * <p>The default range is the drawing width of this view.</p> 14954 * 14955 * @return the total horizontal range represented by the horizontal 14956 * scrollbar 14957 * 14958 * @see #computeHorizontalScrollExtent() 14959 * @see #computeHorizontalScrollOffset() 14960 * @see android.widget.ScrollBarDrawable 14961 */ 14962 protected int computeHorizontalScrollRange() { 14963 return getWidth(); 14964 } 14965 14966 /** 14967 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 14968 * within the horizontal range. This value is used to compute the position 14969 * of the thumb within the scrollbar's track.</p> 14970 * 14971 * <p>The range is expressed in arbitrary units that must be the same as the 14972 * units used by {@link #computeHorizontalScrollRange()} and 14973 * {@link #computeHorizontalScrollExtent()}.</p> 14974 * 14975 * <p>The default offset is the scroll offset of this view.</p> 14976 * 14977 * @return the horizontal offset of the scrollbar's thumb 14978 * 14979 * @see #computeHorizontalScrollRange() 14980 * @see #computeHorizontalScrollExtent() 14981 * @see android.widget.ScrollBarDrawable 14982 */ 14983 protected int computeHorizontalScrollOffset() { 14984 return mScrollX; 14985 } 14986 14987 /** 14988 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 14989 * within the horizontal range. This value is used to compute the length 14990 * of the thumb within the scrollbar's track.</p> 14991 * 14992 * <p>The range is expressed in arbitrary units that must be the same as the 14993 * units used by {@link #computeHorizontalScrollRange()} and 14994 * {@link #computeHorizontalScrollOffset()}.</p> 14995 * 14996 * <p>The default extent is the drawing width of this view.</p> 14997 * 14998 * @return the horizontal extent of the scrollbar's thumb 14999 * 15000 * @see #computeHorizontalScrollRange() 15001 * @see #computeHorizontalScrollOffset() 15002 * @see android.widget.ScrollBarDrawable 15003 */ 15004 protected int computeHorizontalScrollExtent() { 15005 return getWidth(); 15006 } 15007 15008 /** 15009 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 15010 * 15011 * <p>The range is expressed in arbitrary units that must be the same as the 15012 * units used by {@link #computeVerticalScrollExtent()} and 15013 * {@link #computeVerticalScrollOffset()}.</p> 15014 * 15015 * @return the total vertical range represented by the vertical scrollbar 15016 * 15017 * <p>The default range is the drawing height of this view.</p> 15018 * 15019 * @see #computeVerticalScrollExtent() 15020 * @see #computeVerticalScrollOffset() 15021 * @see android.widget.ScrollBarDrawable 15022 */ 15023 protected int computeVerticalScrollRange() { 15024 return getHeight(); 15025 } 15026 15027 /** 15028 * <p>Compute the vertical offset of the vertical scrollbar's thumb 15029 * within the horizontal range. This value is used to compute the position 15030 * of the thumb within the scrollbar's track.</p> 15031 * 15032 * <p>The range is expressed in arbitrary units that must be the same as the 15033 * units used by {@link #computeVerticalScrollRange()} and 15034 * {@link #computeVerticalScrollExtent()}.</p> 15035 * 15036 * <p>The default offset is the scroll offset of this view.</p> 15037 * 15038 * @return the vertical offset of the scrollbar's thumb 15039 * 15040 * @see #computeVerticalScrollRange() 15041 * @see #computeVerticalScrollExtent() 15042 * @see android.widget.ScrollBarDrawable 15043 */ 15044 protected int computeVerticalScrollOffset() { 15045 return mScrollY; 15046 } 15047 15048 /** 15049 * <p>Compute the vertical extent of the vertical scrollbar's thumb 15050 * within the vertical range. This value is used to compute the length 15051 * of the thumb within the scrollbar's track.</p> 15052 * 15053 * <p>The range is expressed in arbitrary units that must be the same as the 15054 * units used by {@link #computeVerticalScrollRange()} and 15055 * {@link #computeVerticalScrollOffset()}.</p> 15056 * 15057 * <p>The default extent is the drawing height of this view.</p> 15058 * 15059 * @return the vertical extent of the scrollbar's thumb 15060 * 15061 * @see #computeVerticalScrollRange() 15062 * @see #computeVerticalScrollOffset() 15063 * @see android.widget.ScrollBarDrawable 15064 */ 15065 protected int computeVerticalScrollExtent() { 15066 return getHeight(); 15067 } 15068 15069 /** 15070 * Check if this view can be scrolled horizontally in a certain direction. 15071 * 15072 * @param direction Negative to check scrolling left, positive to check scrolling right. 15073 * @return true if this view can be scrolled in the specified direction, false otherwise. 15074 */ 15075 public boolean canScrollHorizontally(int direction) { 15076 final int offset = computeHorizontalScrollOffset(); 15077 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 15078 if (range == 0) return false; 15079 if (direction < 0) { 15080 return offset > 0; 15081 } else { 15082 return offset < range - 1; 15083 } 15084 } 15085 15086 /** 15087 * Check if this view can be scrolled vertically in a certain direction. 15088 * 15089 * @param direction Negative to check scrolling up, positive to check scrolling down. 15090 * @return true if this view can be scrolled in the specified direction, false otherwise. 15091 */ 15092 public boolean canScrollVertically(int direction) { 15093 final int offset = computeVerticalScrollOffset(); 15094 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 15095 if (range == 0) return false; 15096 if (direction < 0) { 15097 return offset > 0; 15098 } else { 15099 return offset < range - 1; 15100 } 15101 } 15102 15103 void getScrollIndicatorBounds(@NonNull Rect out) { 15104 out.left = mScrollX; 15105 out.right = mScrollX + mRight - mLeft; 15106 out.top = mScrollY; 15107 out.bottom = mScrollY + mBottom - mTop; 15108 } 15109 15110 private void onDrawScrollIndicators(Canvas c) { 15111 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 15112 // No scroll indicators enabled. 15113 return; 15114 } 15115 15116 final Drawable dr = mScrollIndicatorDrawable; 15117 if (dr == null) { 15118 // Scroll indicators aren't supported here. 15119 return; 15120 } 15121 15122 final int h = dr.getIntrinsicHeight(); 15123 final int w = dr.getIntrinsicWidth(); 15124 final Rect rect = mAttachInfo.mTmpInvalRect; 15125 getScrollIndicatorBounds(rect); 15126 15127 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 15128 final boolean canScrollUp = canScrollVertically(-1); 15129 if (canScrollUp) { 15130 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 15131 dr.draw(c); 15132 } 15133 } 15134 15135 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 15136 final boolean canScrollDown = canScrollVertically(1); 15137 if (canScrollDown) { 15138 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 15139 dr.draw(c); 15140 } 15141 } 15142 15143 final int leftRtl; 15144 final int rightRtl; 15145 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15146 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 15147 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 15148 } else { 15149 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 15150 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 15151 } 15152 15153 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 15154 if ((mPrivateFlags3 & leftMask) != 0) { 15155 final boolean canScrollLeft = canScrollHorizontally(-1); 15156 if (canScrollLeft) { 15157 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 15158 dr.draw(c); 15159 } 15160 } 15161 15162 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 15163 if ((mPrivateFlags3 & rightMask) != 0) { 15164 final boolean canScrollRight = canScrollHorizontally(1); 15165 if (canScrollRight) { 15166 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 15167 dr.draw(c); 15168 } 15169 } 15170 } 15171 15172 private void getHorizontalScrollBarBounds(Rect bounds) { 15173 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 15174 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 15175 && !isVerticalScrollBarHidden(); 15176 final int size = getHorizontalScrollbarHeight(); 15177 final int verticalScrollBarGap = drawVerticalScrollBar ? 15178 getVerticalScrollbarWidth() : 0; 15179 final int width = mRight - mLeft; 15180 final int height = mBottom - mTop; 15181 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 15182 bounds.left = mScrollX + (mPaddingLeft & inside); 15183 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 15184 bounds.bottom = bounds.top + size; 15185 } 15186 15187 private void getVerticalScrollBarBounds(Rect bounds) { 15188 if (mRoundScrollbarRenderer == null) { 15189 getStraightVerticalScrollBarBounds(bounds); 15190 } else { 15191 getRoundVerticalScrollBarBounds(bounds); 15192 } 15193 } 15194 15195 private void getRoundVerticalScrollBarBounds(Rect bounds) { 15196 final int width = mRight - mLeft; 15197 final int height = mBottom - mTop; 15198 // Do not take padding into account as we always want the scrollbars 15199 // to hug the screen for round wearable devices. 15200 bounds.left = mScrollX; 15201 bounds.top = mScrollY; 15202 bounds.right = bounds.left + width; 15203 bounds.bottom = mScrollY + height; 15204 } 15205 15206 private void getStraightVerticalScrollBarBounds(Rect bounds) { 15207 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 15208 final int size = getVerticalScrollbarWidth(); 15209 int verticalScrollbarPosition = mVerticalScrollbarPosition; 15210 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 15211 verticalScrollbarPosition = isLayoutRtl() ? 15212 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 15213 } 15214 final int width = mRight - mLeft; 15215 final int height = mBottom - mTop; 15216 switch (verticalScrollbarPosition) { 15217 default: 15218 case SCROLLBAR_POSITION_RIGHT: 15219 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 15220 break; 15221 case SCROLLBAR_POSITION_LEFT: 15222 bounds.left = mScrollX + (mUserPaddingLeft & inside); 15223 break; 15224 } 15225 bounds.top = mScrollY + (mPaddingTop & inside); 15226 bounds.right = bounds.left + size; 15227 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 15228 } 15229 15230 /** 15231 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 15232 * scrollbars are painted only if they have been awakened first.</p> 15233 * 15234 * @param canvas the canvas on which to draw the scrollbars 15235 * 15236 * @see #awakenScrollBars(int) 15237 */ 15238 protected final void onDrawScrollBars(Canvas canvas) { 15239 // scrollbars are drawn only when the animation is running 15240 final ScrollabilityCache cache = mScrollCache; 15241 15242 if (cache != null) { 15243 15244 int state = cache.state; 15245 15246 if (state == ScrollabilityCache.OFF) { 15247 return; 15248 } 15249 15250 boolean invalidate = false; 15251 15252 if (state == ScrollabilityCache.FADING) { 15253 // We're fading -- get our fade interpolation 15254 if (cache.interpolatorValues == null) { 15255 cache.interpolatorValues = new float[1]; 15256 } 15257 15258 float[] values = cache.interpolatorValues; 15259 15260 // Stops the animation if we're done 15261 if (cache.scrollBarInterpolator.timeToValues(values) == 15262 Interpolator.Result.FREEZE_END) { 15263 cache.state = ScrollabilityCache.OFF; 15264 } else { 15265 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 15266 } 15267 15268 // This will make the scroll bars inval themselves after 15269 // drawing. We only want this when we're fading so that 15270 // we prevent excessive redraws 15271 invalidate = true; 15272 } else { 15273 // We're just on -- but we may have been fading before so 15274 // reset alpha 15275 cache.scrollBar.mutate().setAlpha(255); 15276 } 15277 15278 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 15279 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 15280 && !isVerticalScrollBarHidden(); 15281 15282 // Fork out the scroll bar drawing for round wearable devices. 15283 if (mRoundScrollbarRenderer != null) { 15284 if (drawVerticalScrollBar) { 15285 final Rect bounds = cache.mScrollBarBounds; 15286 getVerticalScrollBarBounds(bounds); 15287 mRoundScrollbarRenderer.drawRoundScrollbars( 15288 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 15289 if (invalidate) { 15290 invalidate(); 15291 } 15292 } 15293 // Do not draw horizontal scroll bars for round wearable devices. 15294 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 15295 final ScrollBarDrawable scrollBar = cache.scrollBar; 15296 15297 if (drawHorizontalScrollBar) { 15298 scrollBar.setParameters(computeHorizontalScrollRange(), 15299 computeHorizontalScrollOffset(), 15300 computeHorizontalScrollExtent(), false); 15301 final Rect bounds = cache.mScrollBarBounds; 15302 getHorizontalScrollBarBounds(bounds); 15303 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 15304 bounds.right, bounds.bottom); 15305 if (invalidate) { 15306 invalidate(bounds); 15307 } 15308 } 15309 15310 if (drawVerticalScrollBar) { 15311 scrollBar.setParameters(computeVerticalScrollRange(), 15312 computeVerticalScrollOffset(), 15313 computeVerticalScrollExtent(), true); 15314 final Rect bounds = cache.mScrollBarBounds; 15315 getVerticalScrollBarBounds(bounds); 15316 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 15317 bounds.right, bounds.bottom); 15318 if (invalidate) { 15319 invalidate(bounds); 15320 } 15321 } 15322 } 15323 } 15324 } 15325 15326 /** 15327 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 15328 * FastScroller is visible. 15329 * @return whether to temporarily hide the vertical scrollbar 15330 * @hide 15331 */ 15332 protected boolean isVerticalScrollBarHidden() { 15333 return false; 15334 } 15335 15336 /** 15337 * <p>Draw the horizontal scrollbar if 15338 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 15339 * 15340 * @param canvas the canvas on which to draw the scrollbar 15341 * @param scrollBar the scrollbar's drawable 15342 * 15343 * @see #isHorizontalScrollBarEnabled() 15344 * @see #computeHorizontalScrollRange() 15345 * @see #computeHorizontalScrollExtent() 15346 * @see #computeHorizontalScrollOffset() 15347 * @see android.widget.ScrollBarDrawable 15348 * @hide 15349 */ 15350 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 15351 int l, int t, int r, int b) { 15352 scrollBar.setBounds(l, t, r, b); 15353 scrollBar.draw(canvas); 15354 } 15355 15356 /** 15357 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 15358 * returns true.</p> 15359 * 15360 * @param canvas the canvas on which to draw the scrollbar 15361 * @param scrollBar the scrollbar's drawable 15362 * 15363 * @see #isVerticalScrollBarEnabled() 15364 * @see #computeVerticalScrollRange() 15365 * @see #computeVerticalScrollExtent() 15366 * @see #computeVerticalScrollOffset() 15367 * @see android.widget.ScrollBarDrawable 15368 * @hide 15369 */ 15370 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 15371 int l, int t, int r, int b) { 15372 scrollBar.setBounds(l, t, r, b); 15373 scrollBar.draw(canvas); 15374 } 15375 15376 /** 15377 * Implement this to do your drawing. 15378 * 15379 * @param canvas the canvas on which the background will be drawn 15380 */ 15381 protected void onDraw(Canvas canvas) { 15382 } 15383 15384 /* 15385 * Caller is responsible for calling requestLayout if necessary. 15386 * (This allows addViewInLayout to not request a new layout.) 15387 */ 15388 void assignParent(ViewParent parent) { 15389 if (mParent == null) { 15390 mParent = parent; 15391 } else if (parent == null) { 15392 mParent = null; 15393 } else { 15394 throw new RuntimeException("view " + this + " being added, but" 15395 + " it already has a parent"); 15396 } 15397 } 15398 15399 /** 15400 * This is called when the view is attached to a window. At this point it 15401 * has a Surface and will start drawing. Note that this function is 15402 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 15403 * however it may be called any time before the first onDraw -- including 15404 * before or after {@link #onMeasure(int, int)}. 15405 * 15406 * @see #onDetachedFromWindow() 15407 */ 15408 @CallSuper 15409 protected void onAttachedToWindow() { 15410 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 15411 mParent.requestTransparentRegion(this); 15412 } 15413 15414 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15415 15416 jumpDrawablesToCurrentState(); 15417 15418 resetSubtreeAccessibilityStateChanged(); 15419 15420 // rebuild, since Outline not maintained while View is detached 15421 rebuildOutline(); 15422 15423 if (isFocused()) { 15424 InputMethodManager imm = InputMethodManager.peekInstance(); 15425 if (imm != null) { 15426 imm.focusIn(this); 15427 } 15428 } 15429 } 15430 15431 /** 15432 * Resolve all RTL related properties. 15433 * 15434 * @return true if resolution of RTL properties has been done 15435 * 15436 * @hide 15437 */ 15438 public boolean resolveRtlPropertiesIfNeeded() { 15439 if (!needRtlPropertiesResolution()) return false; 15440 15441 // Order is important here: LayoutDirection MUST be resolved first 15442 if (!isLayoutDirectionResolved()) { 15443 resolveLayoutDirection(); 15444 resolveLayoutParams(); 15445 } 15446 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 15447 if (!isTextDirectionResolved()) { 15448 resolveTextDirection(); 15449 } 15450 if (!isTextAlignmentResolved()) { 15451 resolveTextAlignment(); 15452 } 15453 // Should resolve Drawables before Padding because we need the layout direction of the 15454 // Drawable to correctly resolve Padding. 15455 if (!areDrawablesResolved()) { 15456 resolveDrawables(); 15457 } 15458 if (!isPaddingResolved()) { 15459 resolvePadding(); 15460 } 15461 onRtlPropertiesChanged(getLayoutDirection()); 15462 return true; 15463 } 15464 15465 /** 15466 * Reset resolution of all RTL related properties. 15467 * 15468 * @hide 15469 */ 15470 public void resetRtlProperties() { 15471 resetResolvedLayoutDirection(); 15472 resetResolvedTextDirection(); 15473 resetResolvedTextAlignment(); 15474 resetResolvedPadding(); 15475 resetResolvedDrawables(); 15476 } 15477 15478 /** 15479 * @see #onScreenStateChanged(int) 15480 */ 15481 void dispatchScreenStateChanged(int screenState) { 15482 onScreenStateChanged(screenState); 15483 } 15484 15485 /** 15486 * This method is called whenever the state of the screen this view is 15487 * attached to changes. A state change will usually occurs when the screen 15488 * turns on or off (whether it happens automatically or the user does it 15489 * manually.) 15490 * 15491 * @param screenState The new state of the screen. Can be either 15492 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 15493 */ 15494 public void onScreenStateChanged(int screenState) { 15495 } 15496 15497 /** 15498 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 15499 */ 15500 private boolean hasRtlSupport() { 15501 return mContext.getApplicationInfo().hasRtlSupport(); 15502 } 15503 15504 /** 15505 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 15506 * RTL not supported) 15507 */ 15508 private boolean isRtlCompatibilityMode() { 15509 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 15510 return targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport(); 15511 } 15512 15513 /** 15514 * @return true if RTL properties need resolution. 15515 * 15516 */ 15517 private boolean needRtlPropertiesResolution() { 15518 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 15519 } 15520 15521 /** 15522 * Called when any RTL property (layout direction or text direction or text alignment) has 15523 * been changed. 15524 * 15525 * Subclasses need to override this method to take care of cached information that depends on the 15526 * resolved layout direction, or to inform child views that inherit their layout direction. 15527 * 15528 * The default implementation does nothing. 15529 * 15530 * @param layoutDirection the direction of the layout 15531 * 15532 * @see #LAYOUT_DIRECTION_LTR 15533 * @see #LAYOUT_DIRECTION_RTL 15534 */ 15535 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 15536 } 15537 15538 /** 15539 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 15540 * that the parent directionality can and will be resolved before its children. 15541 * 15542 * @return true if resolution has been done, false otherwise. 15543 * 15544 * @hide 15545 */ 15546 public boolean resolveLayoutDirection() { 15547 // Clear any previous layout direction resolution 15548 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15549 15550 if (hasRtlSupport()) { 15551 // Set resolved depending on layout direction 15552 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 15553 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 15554 case LAYOUT_DIRECTION_INHERIT: 15555 // We cannot resolve yet. LTR is by default and let the resolution happen again 15556 // later to get the correct resolved value 15557 if (!canResolveLayoutDirection()) return false; 15558 15559 // Parent has not yet resolved, LTR is still the default 15560 try { 15561 if (!mParent.isLayoutDirectionResolved()) return false; 15562 15563 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15564 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15565 } 15566 } catch (AbstractMethodError e) { 15567 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15568 " does not fully implement ViewParent", e); 15569 } 15570 break; 15571 case LAYOUT_DIRECTION_RTL: 15572 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15573 break; 15574 case LAYOUT_DIRECTION_LOCALE: 15575 if((LAYOUT_DIRECTION_RTL == 15576 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 15577 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15578 } 15579 break; 15580 default: 15581 // Nothing to do, LTR by default 15582 } 15583 } 15584 15585 // Set to resolved 15586 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 15587 return true; 15588 } 15589 15590 /** 15591 * Check if layout direction resolution can be done. 15592 * 15593 * @return true if layout direction resolution can be done otherwise return false. 15594 */ 15595 public boolean canResolveLayoutDirection() { 15596 switch (getRawLayoutDirection()) { 15597 case LAYOUT_DIRECTION_INHERIT: 15598 if (mParent != null) { 15599 try { 15600 return mParent.canResolveLayoutDirection(); 15601 } catch (AbstractMethodError e) { 15602 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15603 " does not fully implement ViewParent", e); 15604 } 15605 } 15606 return false; 15607 15608 default: 15609 return true; 15610 } 15611 } 15612 15613 /** 15614 * Reset the resolved layout direction. Layout direction will be resolved during a call to 15615 * {@link #onMeasure(int, int)}. 15616 * 15617 * @hide 15618 */ 15619 public void resetResolvedLayoutDirection() { 15620 // Reset the current resolved bits 15621 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15622 } 15623 15624 /** 15625 * @return true if the layout direction is inherited. 15626 * 15627 * @hide 15628 */ 15629 public boolean isLayoutDirectionInherited() { 15630 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 15631 } 15632 15633 /** 15634 * @return true if layout direction has been resolved. 15635 */ 15636 public boolean isLayoutDirectionResolved() { 15637 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 15638 } 15639 15640 /** 15641 * Return if padding has been resolved 15642 * 15643 * @hide 15644 */ 15645 boolean isPaddingResolved() { 15646 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 15647 } 15648 15649 /** 15650 * Resolves padding depending on layout direction, if applicable, and 15651 * recomputes internal padding values to adjust for scroll bars. 15652 * 15653 * @hide 15654 */ 15655 public void resolvePadding() { 15656 final int resolvedLayoutDirection = getLayoutDirection(); 15657 15658 if (!isRtlCompatibilityMode()) { 15659 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 15660 // If start / end padding are defined, they will be resolved (hence overriding) to 15661 // left / right or right / left depending on the resolved layout direction. 15662 // If start / end padding are not defined, use the left / right ones. 15663 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 15664 Rect padding = sThreadLocal.get(); 15665 if (padding == null) { 15666 padding = new Rect(); 15667 sThreadLocal.set(padding); 15668 } 15669 mBackground.getPadding(padding); 15670 if (!mLeftPaddingDefined) { 15671 mUserPaddingLeftInitial = padding.left; 15672 } 15673 if (!mRightPaddingDefined) { 15674 mUserPaddingRightInitial = padding.right; 15675 } 15676 } 15677 switch (resolvedLayoutDirection) { 15678 case LAYOUT_DIRECTION_RTL: 15679 if (mUserPaddingStart != UNDEFINED_PADDING) { 15680 mUserPaddingRight = mUserPaddingStart; 15681 } else { 15682 mUserPaddingRight = mUserPaddingRightInitial; 15683 } 15684 if (mUserPaddingEnd != UNDEFINED_PADDING) { 15685 mUserPaddingLeft = mUserPaddingEnd; 15686 } else { 15687 mUserPaddingLeft = mUserPaddingLeftInitial; 15688 } 15689 break; 15690 case LAYOUT_DIRECTION_LTR: 15691 default: 15692 if (mUserPaddingStart != UNDEFINED_PADDING) { 15693 mUserPaddingLeft = mUserPaddingStart; 15694 } else { 15695 mUserPaddingLeft = mUserPaddingLeftInitial; 15696 } 15697 if (mUserPaddingEnd != UNDEFINED_PADDING) { 15698 mUserPaddingRight = mUserPaddingEnd; 15699 } else { 15700 mUserPaddingRight = mUserPaddingRightInitial; 15701 } 15702 } 15703 15704 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 15705 } 15706 15707 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 15708 onRtlPropertiesChanged(resolvedLayoutDirection); 15709 15710 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 15711 } 15712 15713 /** 15714 * Reset the resolved layout direction. 15715 * 15716 * @hide 15717 */ 15718 public void resetResolvedPadding() { 15719 resetResolvedPaddingInternal(); 15720 } 15721 15722 /** 15723 * Used when we only want to reset *this* view's padding and not trigger overrides 15724 * in ViewGroup that reset children too. 15725 */ 15726 void resetResolvedPaddingInternal() { 15727 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 15728 } 15729 15730 /** 15731 * This is called when the view is detached from a window. At this point it 15732 * no longer has a surface for drawing. 15733 * 15734 * @see #onAttachedToWindow() 15735 */ 15736 @CallSuper 15737 protected void onDetachedFromWindow() { 15738 } 15739 15740 /** 15741 * This is a framework-internal mirror of onDetachedFromWindow() that's called 15742 * after onDetachedFromWindow(). 15743 * 15744 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 15745 * The super method should be called at the end of the overridden method to ensure 15746 * subclasses are destroyed first 15747 * 15748 * @hide 15749 */ 15750 @CallSuper 15751 protected void onDetachedFromWindowInternal() { 15752 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 15753 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15754 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 15755 15756 removeUnsetPressCallback(); 15757 removeLongPressCallback(); 15758 removePerformClickCallback(); 15759 removeSendViewScrolledAccessibilityEventCallback(); 15760 stopNestedScroll(); 15761 15762 // Anything that started animating right before detach should already 15763 // be in its final state when re-attached. 15764 jumpDrawablesToCurrentState(); 15765 15766 destroyDrawingCache(); 15767 15768 cleanupDraw(); 15769 mCurrentAnimation = null; 15770 15771 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 15772 hideTooltip(); 15773 } 15774 } 15775 15776 private void cleanupDraw() { 15777 resetDisplayList(); 15778 if (mAttachInfo != null) { 15779 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 15780 } 15781 } 15782 15783 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 15784 } 15785 15786 /** 15787 * @return The number of times this view has been attached to a window 15788 */ 15789 protected int getWindowAttachCount() { 15790 return mWindowAttachCount; 15791 } 15792 15793 /** 15794 * Retrieve a unique token identifying the window this view is attached to. 15795 * @return Return the window's token for use in 15796 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 15797 */ 15798 public IBinder getWindowToken() { 15799 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 15800 } 15801 15802 /** 15803 * Retrieve the {@link WindowId} for the window this view is 15804 * currently attached to. 15805 */ 15806 public WindowId getWindowId() { 15807 if (mAttachInfo == null) { 15808 return null; 15809 } 15810 if (mAttachInfo.mWindowId == null) { 15811 try { 15812 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 15813 mAttachInfo.mWindowToken); 15814 mAttachInfo.mWindowId = new WindowId( 15815 mAttachInfo.mIWindowId); 15816 } catch (RemoteException e) { 15817 } 15818 } 15819 return mAttachInfo.mWindowId; 15820 } 15821 15822 /** 15823 * Retrieve a unique token identifying the top-level "real" window of 15824 * the window that this view is attached to. That is, this is like 15825 * {@link #getWindowToken}, except if the window this view in is a panel 15826 * window (attached to another containing window), then the token of 15827 * the containing window is returned instead. 15828 * 15829 * @return Returns the associated window token, either 15830 * {@link #getWindowToken()} or the containing window's token. 15831 */ 15832 public IBinder getApplicationWindowToken() { 15833 AttachInfo ai = mAttachInfo; 15834 if (ai != null) { 15835 IBinder appWindowToken = ai.mPanelParentWindowToken; 15836 if (appWindowToken == null) { 15837 appWindowToken = ai.mWindowToken; 15838 } 15839 return appWindowToken; 15840 } 15841 return null; 15842 } 15843 15844 /** 15845 * Gets the logical display to which the view's window has been attached. 15846 * 15847 * @return The logical display, or null if the view is not currently attached to a window. 15848 */ 15849 public Display getDisplay() { 15850 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 15851 } 15852 15853 /** 15854 * Retrieve private session object this view hierarchy is using to 15855 * communicate with the window manager. 15856 * @return the session object to communicate with the window manager 15857 */ 15858 /*package*/ IWindowSession getWindowSession() { 15859 return mAttachInfo != null ? mAttachInfo.mSession : null; 15860 } 15861 15862 /** 15863 * Return the visibility value of the least visible component passed. 15864 */ 15865 int combineVisibility(int vis1, int vis2) { 15866 // This works because VISIBLE < INVISIBLE < GONE. 15867 return Math.max(vis1, vis2); 15868 } 15869 15870 /** 15871 * @param info the {@link android.view.View.AttachInfo} to associated with 15872 * this view 15873 */ 15874 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 15875 mAttachInfo = info; 15876 if (mOverlay != null) { 15877 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 15878 } 15879 mWindowAttachCount++; 15880 // We will need to evaluate the drawable state at least once. 15881 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 15882 if (mFloatingTreeObserver != null) { 15883 info.mTreeObserver.merge(mFloatingTreeObserver); 15884 mFloatingTreeObserver = null; 15885 } 15886 15887 registerPendingFrameMetricsObservers(); 15888 15889 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 15890 mAttachInfo.mScrollContainers.add(this); 15891 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 15892 } 15893 // Transfer all pending runnables. 15894 if (mRunQueue != null) { 15895 mRunQueue.executeActions(info.mHandler); 15896 mRunQueue = null; 15897 } 15898 performCollectViewAttributes(mAttachInfo, visibility); 15899 onAttachedToWindow(); 15900 15901 ListenerInfo li = mListenerInfo; 15902 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 15903 li != null ? li.mOnAttachStateChangeListeners : null; 15904 if (listeners != null && listeners.size() > 0) { 15905 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 15906 // perform the dispatching. The iterator is a safe guard against listeners that 15907 // could mutate the list by calling the various add/remove methods. This prevents 15908 // the array from being modified while we iterate it. 15909 for (OnAttachStateChangeListener listener : listeners) { 15910 listener.onViewAttachedToWindow(this); 15911 } 15912 } 15913 15914 int vis = info.mWindowVisibility; 15915 if (vis != GONE) { 15916 onWindowVisibilityChanged(vis); 15917 if (isShown()) { 15918 // Calling onVisibilityAggregated directly here since the subtree will also 15919 // receive dispatchAttachedToWindow and this same call 15920 onVisibilityAggregated(vis == VISIBLE); 15921 } 15922 } 15923 15924 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 15925 // As all views in the subtree will already receive dispatchAttachedToWindow 15926 // traversing the subtree again here is not desired. 15927 onVisibilityChanged(this, visibility); 15928 15929 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 15930 // If nobody has evaluated the drawable state yet, then do it now. 15931 refreshDrawableState(); 15932 } 15933 needGlobalAttributesUpdate(false); 15934 } 15935 15936 void dispatchDetachedFromWindow() { 15937 AttachInfo info = mAttachInfo; 15938 if (info != null) { 15939 int vis = info.mWindowVisibility; 15940 if (vis != GONE) { 15941 onWindowVisibilityChanged(GONE); 15942 if (isShown()) { 15943 // Invoking onVisibilityAggregated directly here since the subtree 15944 // will also receive detached from window 15945 onVisibilityAggregated(false); 15946 } 15947 } 15948 } 15949 15950 onDetachedFromWindow(); 15951 onDetachedFromWindowInternal(); 15952 15953 InputMethodManager imm = InputMethodManager.peekInstance(); 15954 if (imm != null) { 15955 imm.onViewDetachedFromWindow(this); 15956 } 15957 15958 ListenerInfo li = mListenerInfo; 15959 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 15960 li != null ? li.mOnAttachStateChangeListeners : null; 15961 if (listeners != null && listeners.size() > 0) { 15962 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 15963 // perform the dispatching. The iterator is a safe guard against listeners that 15964 // could mutate the list by calling the various add/remove methods. This prevents 15965 // the array from being modified while we iterate it. 15966 for (OnAttachStateChangeListener listener : listeners) { 15967 listener.onViewDetachedFromWindow(this); 15968 } 15969 } 15970 15971 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 15972 mAttachInfo.mScrollContainers.remove(this); 15973 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 15974 } 15975 15976 mAttachInfo = null; 15977 if (mOverlay != null) { 15978 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 15979 } 15980 } 15981 15982 /** 15983 * Cancel any deferred high-level input events that were previously posted to the event queue. 15984 * 15985 * <p>Many views post high-level events such as click handlers to the event queue 15986 * to run deferred in order to preserve a desired user experience - clearing visible 15987 * pressed states before executing, etc. This method will abort any events of this nature 15988 * that are currently in flight.</p> 15989 * 15990 * <p>Custom views that generate their own high-level deferred input events should override 15991 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 15992 * 15993 * <p>This will also cancel pending input events for any child views.</p> 15994 * 15995 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 15996 * This will not impact newer events posted after this call that may occur as a result of 15997 * lower-level input events still waiting in the queue. If you are trying to prevent 15998 * double-submitted events for the duration of some sort of asynchronous transaction 15999 * you should also take other steps to protect against unexpected double inputs e.g. calling 16000 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 16001 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 16002 */ 16003 public final void cancelPendingInputEvents() { 16004 dispatchCancelPendingInputEvents(); 16005 } 16006 16007 /** 16008 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 16009 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 16010 */ 16011 void dispatchCancelPendingInputEvents() { 16012 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 16013 onCancelPendingInputEvents(); 16014 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 16015 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 16016 " did not call through to super.onCancelPendingInputEvents()"); 16017 } 16018 } 16019 16020 /** 16021 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 16022 * a parent view. 16023 * 16024 * <p>This method is responsible for removing any pending high-level input events that were 16025 * posted to the event queue to run later. Custom view classes that post their own deferred 16026 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 16027 * {@link android.os.Handler} should override this method, call 16028 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 16029 * </p> 16030 */ 16031 public void onCancelPendingInputEvents() { 16032 removePerformClickCallback(); 16033 cancelLongPress(); 16034 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 16035 } 16036 16037 /** 16038 * Store this view hierarchy's frozen state into the given container. 16039 * 16040 * @param container The SparseArray in which to save the view's state. 16041 * 16042 * @see #restoreHierarchyState(android.util.SparseArray) 16043 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16044 * @see #onSaveInstanceState() 16045 */ 16046 public void saveHierarchyState(SparseArray<Parcelable> container) { 16047 dispatchSaveInstanceState(container); 16048 } 16049 16050 /** 16051 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 16052 * this view and its children. May be overridden to modify how freezing happens to a 16053 * view's children; for example, some views may want to not store state for their children. 16054 * 16055 * @param container The SparseArray in which to save the view's state. 16056 * 16057 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16058 * @see #saveHierarchyState(android.util.SparseArray) 16059 * @see #onSaveInstanceState() 16060 */ 16061 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 16062 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 16063 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 16064 Parcelable state = onSaveInstanceState(); 16065 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 16066 throw new IllegalStateException( 16067 "Derived class did not call super.onSaveInstanceState()"); 16068 } 16069 if (state != null) { 16070 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 16071 // + ": " + state); 16072 container.put(mID, state); 16073 } 16074 } 16075 } 16076 16077 /** 16078 * Hook allowing a view to generate a representation of its internal state 16079 * that can later be used to create a new instance with that same state. 16080 * This state should only contain information that is not persistent or can 16081 * not be reconstructed later. For example, you will never store your 16082 * current position on screen because that will be computed again when a 16083 * new instance of the view is placed in its view hierarchy. 16084 * <p> 16085 * Some examples of things you may store here: the current cursor position 16086 * in a text view (but usually not the text itself since that is stored in a 16087 * content provider or other persistent storage), the currently selected 16088 * item in a list view. 16089 * 16090 * @return Returns a Parcelable object containing the view's current dynamic 16091 * state, or null if there is nothing interesting to save. The 16092 * default implementation returns null. 16093 * @see #onRestoreInstanceState(android.os.Parcelable) 16094 * @see #saveHierarchyState(android.util.SparseArray) 16095 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16096 * @see #setSaveEnabled(boolean) 16097 */ 16098 @CallSuper 16099 protected Parcelable onSaveInstanceState() { 16100 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 16101 if (mStartActivityRequestWho != null) { 16102 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 16103 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 16104 return state; 16105 } 16106 return BaseSavedState.EMPTY_STATE; 16107 } 16108 16109 /** 16110 * Restore this view hierarchy's frozen state from the given container. 16111 * 16112 * @param container The SparseArray which holds previously frozen states. 16113 * 16114 * @see #saveHierarchyState(android.util.SparseArray) 16115 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16116 * @see #onRestoreInstanceState(android.os.Parcelable) 16117 */ 16118 public void restoreHierarchyState(SparseArray<Parcelable> container) { 16119 dispatchRestoreInstanceState(container); 16120 } 16121 16122 /** 16123 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 16124 * state for this view and its children. May be overridden to modify how restoring 16125 * happens to a view's children; for example, some views may want to not store state 16126 * for their children. 16127 * 16128 * @param container The SparseArray which holds previously saved state. 16129 * 16130 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16131 * @see #restoreHierarchyState(android.util.SparseArray) 16132 * @see #onRestoreInstanceState(android.os.Parcelable) 16133 */ 16134 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 16135 if (mID != NO_ID) { 16136 Parcelable state = container.get(mID); 16137 if (state != null) { 16138 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 16139 // + ": " + state); 16140 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 16141 onRestoreInstanceState(state); 16142 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 16143 throw new IllegalStateException( 16144 "Derived class did not call super.onRestoreInstanceState()"); 16145 } 16146 } 16147 } 16148 } 16149 16150 /** 16151 * Hook allowing a view to re-apply a representation of its internal state that had previously 16152 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 16153 * null state. 16154 * 16155 * @param state The frozen state that had previously been returned by 16156 * {@link #onSaveInstanceState}. 16157 * 16158 * @see #onSaveInstanceState() 16159 * @see #restoreHierarchyState(android.util.SparseArray) 16160 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16161 */ 16162 @CallSuper 16163 protected void onRestoreInstanceState(Parcelable state) { 16164 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 16165 if (state != null && !(state instanceof AbsSavedState)) { 16166 throw new IllegalArgumentException("Wrong state class, expecting View State but " 16167 + "received " + state.getClass().toString() + " instead. This usually happens " 16168 + "when two views of different type have the same id in the same hierarchy. " 16169 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 16170 + "other views do not use the same id."); 16171 } 16172 if (state != null && state instanceof BaseSavedState) { 16173 mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved; 16174 } 16175 } 16176 16177 /** 16178 * <p>Return the time at which the drawing of the view hierarchy started.</p> 16179 * 16180 * @return the drawing start time in milliseconds 16181 */ 16182 public long getDrawingTime() { 16183 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 16184 } 16185 16186 /** 16187 * <p>Enables or disables the duplication of the parent's state into this view. When 16188 * duplication is enabled, this view gets its drawable state from its parent rather 16189 * than from its own internal properties.</p> 16190 * 16191 * <p>Note: in the current implementation, setting this property to true after the 16192 * view was added to a ViewGroup might have no effect at all. This property should 16193 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 16194 * 16195 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 16196 * property is enabled, an exception will be thrown.</p> 16197 * 16198 * <p>Note: if the child view uses and updates additional states which are unknown to the 16199 * parent, these states should not be affected by this method.</p> 16200 * 16201 * @param enabled True to enable duplication of the parent's drawable state, false 16202 * to disable it. 16203 * 16204 * @see #getDrawableState() 16205 * @see #isDuplicateParentStateEnabled() 16206 */ 16207 public void setDuplicateParentStateEnabled(boolean enabled) { 16208 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 16209 } 16210 16211 /** 16212 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 16213 * 16214 * @return True if this view's drawable state is duplicated from the parent, 16215 * false otherwise 16216 * 16217 * @see #getDrawableState() 16218 * @see #setDuplicateParentStateEnabled(boolean) 16219 */ 16220 public boolean isDuplicateParentStateEnabled() { 16221 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 16222 } 16223 16224 /** 16225 * <p>Specifies the type of layer backing this view. The layer can be 16226 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16227 * {@link #LAYER_TYPE_HARDWARE}.</p> 16228 * 16229 * <p>A layer is associated with an optional {@link android.graphics.Paint} 16230 * instance that controls how the layer is composed on screen. The following 16231 * properties of the paint are taken into account when composing the layer:</p> 16232 * <ul> 16233 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 16234 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 16235 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 16236 * </ul> 16237 * 16238 * <p>If this view has an alpha value set to < 1.0 by calling 16239 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 16240 * by this view's alpha value.</p> 16241 * 16242 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 16243 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 16244 * for more information on when and how to use layers.</p> 16245 * 16246 * @param layerType The type of layer to use with this view, must be one of 16247 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16248 * {@link #LAYER_TYPE_HARDWARE} 16249 * @param paint The paint used to compose the layer. This argument is optional 16250 * and can be null. It is ignored when the layer type is 16251 * {@link #LAYER_TYPE_NONE} 16252 * 16253 * @see #getLayerType() 16254 * @see #LAYER_TYPE_NONE 16255 * @see #LAYER_TYPE_SOFTWARE 16256 * @see #LAYER_TYPE_HARDWARE 16257 * @see #setAlpha(float) 16258 * 16259 * @attr ref android.R.styleable#View_layerType 16260 */ 16261 public void setLayerType(int layerType, @Nullable Paint paint) { 16262 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 16263 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 16264 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 16265 } 16266 16267 boolean typeChanged = mRenderNode.setLayerType(layerType); 16268 16269 if (!typeChanged) { 16270 setLayerPaint(paint); 16271 return; 16272 } 16273 16274 if (layerType != LAYER_TYPE_SOFTWARE) { 16275 // Destroy any previous software drawing cache if present 16276 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 16277 // drawing cache created in View#draw when drawing to a SW canvas. 16278 destroyDrawingCache(); 16279 } 16280 16281 mLayerType = layerType; 16282 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 16283 mRenderNode.setLayerPaint(mLayerPaint); 16284 16285 // draw() behaves differently if we are on a layer, so we need to 16286 // invalidate() here 16287 invalidateParentCaches(); 16288 invalidate(true); 16289 } 16290 16291 /** 16292 * Updates the {@link Paint} object used with the current layer (used only if the current 16293 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 16294 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 16295 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 16296 * ensure that the view gets redrawn immediately. 16297 * 16298 * <p>A layer is associated with an optional {@link android.graphics.Paint} 16299 * instance that controls how the layer is composed on screen. The following 16300 * properties of the paint are taken into account when composing the layer:</p> 16301 * <ul> 16302 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 16303 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 16304 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 16305 * </ul> 16306 * 16307 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 16308 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 16309 * 16310 * @param paint The paint used to compose the layer. This argument is optional 16311 * and can be null. It is ignored when the layer type is 16312 * {@link #LAYER_TYPE_NONE} 16313 * 16314 * @see #setLayerType(int, android.graphics.Paint) 16315 */ 16316 public void setLayerPaint(@Nullable Paint paint) { 16317 int layerType = getLayerType(); 16318 if (layerType != LAYER_TYPE_NONE) { 16319 mLayerPaint = paint; 16320 if (layerType == LAYER_TYPE_HARDWARE) { 16321 if (mRenderNode.setLayerPaint(paint)) { 16322 invalidateViewProperty(false, false); 16323 } 16324 } else { 16325 invalidate(); 16326 } 16327 } 16328 } 16329 16330 /** 16331 * Indicates what type of layer is currently associated with this view. By default 16332 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 16333 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 16334 * for more information on the different types of layers. 16335 * 16336 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16337 * {@link #LAYER_TYPE_HARDWARE} 16338 * 16339 * @see #setLayerType(int, android.graphics.Paint) 16340 * @see #buildLayer() 16341 * @see #LAYER_TYPE_NONE 16342 * @see #LAYER_TYPE_SOFTWARE 16343 * @see #LAYER_TYPE_HARDWARE 16344 */ 16345 public int getLayerType() { 16346 return mLayerType; 16347 } 16348 16349 /** 16350 * Forces this view's layer to be created and this view to be rendered 16351 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 16352 * invoking this method will have no effect. 16353 * 16354 * This method can for instance be used to render a view into its layer before 16355 * starting an animation. If this view is complex, rendering into the layer 16356 * before starting the animation will avoid skipping frames. 16357 * 16358 * @throws IllegalStateException If this view is not attached to a window 16359 * 16360 * @see #setLayerType(int, android.graphics.Paint) 16361 */ 16362 public void buildLayer() { 16363 if (mLayerType == LAYER_TYPE_NONE) return; 16364 16365 final AttachInfo attachInfo = mAttachInfo; 16366 if (attachInfo == null) { 16367 throw new IllegalStateException("This view must be attached to a window first"); 16368 } 16369 16370 if (getWidth() == 0 || getHeight() == 0) { 16371 return; 16372 } 16373 16374 switch (mLayerType) { 16375 case LAYER_TYPE_HARDWARE: 16376 updateDisplayListIfDirty(); 16377 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 16378 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 16379 } 16380 break; 16381 case LAYER_TYPE_SOFTWARE: 16382 buildDrawingCache(true); 16383 break; 16384 } 16385 } 16386 16387 /** 16388 * Destroys all hardware rendering resources. This method is invoked 16389 * when the system needs to reclaim resources. Upon execution of this 16390 * method, you should free any OpenGL resources created by the view. 16391 * 16392 * Note: you <strong>must</strong> call 16393 * <code>super.destroyHardwareResources()</code> when overriding 16394 * this method. 16395 * 16396 * @hide 16397 */ 16398 @CallSuper 16399 protected void destroyHardwareResources() { 16400 // Although the Layer will be destroyed by RenderNode, we want to release 16401 // the staging display list, which is also a signal to RenderNode that it's 16402 // safe to free its copy of the display list as it knows that we will 16403 // push an updated DisplayList if we try to draw again 16404 resetDisplayList(); 16405 } 16406 16407 /** 16408 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 16409 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 16410 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 16411 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 16412 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 16413 * null.</p> 16414 * 16415 * <p>Enabling the drawing cache is similar to 16416 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 16417 * acceleration is turned off. When hardware acceleration is turned on, enabling the 16418 * drawing cache has no effect on rendering because the system uses a different mechanism 16419 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 16420 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 16421 * for information on how to enable software and hardware layers.</p> 16422 * 16423 * <p>This API can be used to manually generate 16424 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 16425 * {@link #getDrawingCache()}.</p> 16426 * 16427 * @param enabled true to enable the drawing cache, false otherwise 16428 * 16429 * @see #isDrawingCacheEnabled() 16430 * @see #getDrawingCache() 16431 * @see #buildDrawingCache() 16432 * @see #setLayerType(int, android.graphics.Paint) 16433 */ 16434 public void setDrawingCacheEnabled(boolean enabled) { 16435 mCachingFailed = false; 16436 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 16437 } 16438 16439 /** 16440 * <p>Indicates whether the drawing cache is enabled for this view.</p> 16441 * 16442 * @return true if the drawing cache is enabled 16443 * 16444 * @see #setDrawingCacheEnabled(boolean) 16445 * @see #getDrawingCache() 16446 */ 16447 @ViewDebug.ExportedProperty(category = "drawing") 16448 public boolean isDrawingCacheEnabled() { 16449 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 16450 } 16451 16452 /** 16453 * Debugging utility which recursively outputs the dirty state of a view and its 16454 * descendants. 16455 * 16456 * @hide 16457 */ 16458 @SuppressWarnings({"UnusedDeclaration"}) 16459 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 16460 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 16461 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 16462 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 16463 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 16464 if (clear) { 16465 mPrivateFlags &= clearMask; 16466 } 16467 if (this instanceof ViewGroup) { 16468 ViewGroup parent = (ViewGroup) this; 16469 final int count = parent.getChildCount(); 16470 for (int i = 0; i < count; i++) { 16471 final View child = parent.getChildAt(i); 16472 child.outputDirtyFlags(indent + " ", clear, clearMask); 16473 } 16474 } 16475 } 16476 16477 /** 16478 * This method is used by ViewGroup to cause its children to restore or recreate their 16479 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 16480 * to recreate its own display list, which would happen if it went through the normal 16481 * draw/dispatchDraw mechanisms. 16482 * 16483 * @hide 16484 */ 16485 protected void dispatchGetDisplayList() {} 16486 16487 /** 16488 * A view that is not attached or hardware accelerated cannot create a display list. 16489 * This method checks these conditions and returns the appropriate result. 16490 * 16491 * @return true if view has the ability to create a display list, false otherwise. 16492 * 16493 * @hide 16494 */ 16495 public boolean canHaveDisplayList() { 16496 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 16497 } 16498 16499 /** 16500 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 16501 * @hide 16502 */ 16503 @NonNull 16504 public RenderNode updateDisplayListIfDirty() { 16505 final RenderNode renderNode = mRenderNode; 16506 if (!canHaveDisplayList()) { 16507 // can't populate RenderNode, don't try 16508 return renderNode; 16509 } 16510 16511 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 16512 || !renderNode.isValid() 16513 || (mRecreateDisplayList)) { 16514 // Don't need to recreate the display list, just need to tell our 16515 // children to restore/recreate theirs 16516 if (renderNode.isValid() 16517 && !mRecreateDisplayList) { 16518 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16519 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16520 dispatchGetDisplayList(); 16521 16522 return renderNode; // no work needed 16523 } 16524 16525 // If we got here, we're recreating it. Mark it as such to ensure that 16526 // we copy in child display lists into ours in drawChild() 16527 mRecreateDisplayList = true; 16528 16529 int width = mRight - mLeft; 16530 int height = mBottom - mTop; 16531 int layerType = getLayerType(); 16532 16533 final DisplayListCanvas canvas = renderNode.start(width, height); 16534 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 16535 16536 try { 16537 if (layerType == LAYER_TYPE_SOFTWARE) { 16538 buildDrawingCache(true); 16539 Bitmap cache = getDrawingCache(true); 16540 if (cache != null) { 16541 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 16542 } 16543 } else { 16544 computeScroll(); 16545 16546 canvas.translate(-mScrollX, -mScrollY); 16547 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16548 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16549 16550 // Fast path for layouts with no backgrounds 16551 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16552 dispatchDraw(canvas); 16553 if (mOverlay != null && !mOverlay.isEmpty()) { 16554 mOverlay.getOverlayView().draw(canvas); 16555 } 16556 if (debugDraw()) { 16557 debugDrawFocus(canvas); 16558 } 16559 } else { 16560 draw(canvas); 16561 } 16562 } 16563 } finally { 16564 renderNode.end(canvas); 16565 setDisplayListProperties(renderNode); 16566 } 16567 } else { 16568 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16569 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16570 } 16571 return renderNode; 16572 } 16573 16574 private void resetDisplayList() { 16575 if (mRenderNode.isValid()) { 16576 mRenderNode.discardDisplayList(); 16577 } 16578 16579 if (mBackgroundRenderNode != null && mBackgroundRenderNode.isValid()) { 16580 mBackgroundRenderNode.discardDisplayList(); 16581 } 16582 } 16583 16584 /** 16585 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 16586 * 16587 * @return A non-scaled bitmap representing this view or null if cache is disabled. 16588 * 16589 * @see #getDrawingCache(boolean) 16590 */ 16591 public Bitmap getDrawingCache() { 16592 return getDrawingCache(false); 16593 } 16594 16595 /** 16596 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 16597 * is null when caching is disabled. If caching is enabled and the cache is not ready, 16598 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 16599 * draw from the cache when the cache is enabled. To benefit from the cache, you must 16600 * request the drawing cache by calling this method and draw it on screen if the 16601 * returned bitmap is not null.</p> 16602 * 16603 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16604 * this method will create a bitmap of the same size as this view. Because this bitmap 16605 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16606 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16607 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16608 * size than the view. This implies that your application must be able to handle this 16609 * size.</p> 16610 * 16611 * @param autoScale Indicates whether the generated bitmap should be scaled based on 16612 * the current density of the screen when the application is in compatibility 16613 * mode. 16614 * 16615 * @return A bitmap representing this view or null if cache is disabled. 16616 * 16617 * @see #setDrawingCacheEnabled(boolean) 16618 * @see #isDrawingCacheEnabled() 16619 * @see #buildDrawingCache(boolean) 16620 * @see #destroyDrawingCache() 16621 */ 16622 public Bitmap getDrawingCache(boolean autoScale) { 16623 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 16624 return null; 16625 } 16626 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 16627 buildDrawingCache(autoScale); 16628 } 16629 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 16630 } 16631 16632 /** 16633 * <p>Frees the resources used by the drawing cache. If you call 16634 * {@link #buildDrawingCache()} manually without calling 16635 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16636 * should cleanup the cache with this method afterwards.</p> 16637 * 16638 * @see #setDrawingCacheEnabled(boolean) 16639 * @see #buildDrawingCache() 16640 * @see #getDrawingCache() 16641 */ 16642 public void destroyDrawingCache() { 16643 if (mDrawingCache != null) { 16644 mDrawingCache.recycle(); 16645 mDrawingCache = null; 16646 } 16647 if (mUnscaledDrawingCache != null) { 16648 mUnscaledDrawingCache.recycle(); 16649 mUnscaledDrawingCache = null; 16650 } 16651 } 16652 16653 /** 16654 * Setting a solid background color for the drawing cache's bitmaps will improve 16655 * performance and memory usage. Note, though that this should only be used if this 16656 * view will always be drawn on top of a solid color. 16657 * 16658 * @param color The background color to use for the drawing cache's bitmap 16659 * 16660 * @see #setDrawingCacheEnabled(boolean) 16661 * @see #buildDrawingCache() 16662 * @see #getDrawingCache() 16663 */ 16664 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 16665 if (color != mDrawingCacheBackgroundColor) { 16666 mDrawingCacheBackgroundColor = color; 16667 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16668 } 16669 } 16670 16671 /** 16672 * @see #setDrawingCacheBackgroundColor(int) 16673 * 16674 * @return The background color to used for the drawing cache's bitmap 16675 */ 16676 @ColorInt 16677 public int getDrawingCacheBackgroundColor() { 16678 return mDrawingCacheBackgroundColor; 16679 } 16680 16681 /** 16682 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 16683 * 16684 * @see #buildDrawingCache(boolean) 16685 */ 16686 public void buildDrawingCache() { 16687 buildDrawingCache(false); 16688 } 16689 16690 /** 16691 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 16692 * 16693 * <p>If you call {@link #buildDrawingCache()} manually without calling 16694 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16695 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 16696 * 16697 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16698 * this method will create a bitmap of the same size as this view. Because this bitmap 16699 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16700 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16701 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16702 * size than the view. This implies that your application must be able to handle this 16703 * size.</p> 16704 * 16705 * <p>You should avoid calling this method when hardware acceleration is enabled. If 16706 * you do not need the drawing cache bitmap, calling this method will increase memory 16707 * usage and cause the view to be rendered in software once, thus negatively impacting 16708 * performance.</p> 16709 * 16710 * @see #getDrawingCache() 16711 * @see #destroyDrawingCache() 16712 */ 16713 public void buildDrawingCache(boolean autoScale) { 16714 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 16715 mDrawingCache == null : mUnscaledDrawingCache == null)) { 16716 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 16717 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 16718 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 16719 } 16720 try { 16721 buildDrawingCacheImpl(autoScale); 16722 } finally { 16723 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 16724 } 16725 } 16726 } 16727 16728 /** 16729 * private, internal implementation of buildDrawingCache, used to enable tracing 16730 */ 16731 private void buildDrawingCacheImpl(boolean autoScale) { 16732 mCachingFailed = false; 16733 16734 int width = mRight - mLeft; 16735 int height = mBottom - mTop; 16736 16737 final AttachInfo attachInfo = mAttachInfo; 16738 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 16739 16740 if (autoScale && scalingRequired) { 16741 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 16742 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 16743 } 16744 16745 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 16746 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 16747 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 16748 16749 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 16750 final long drawingCacheSize = 16751 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 16752 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 16753 if (width > 0 && height > 0) { 16754 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 16755 + " too large to fit into a software layer (or drawing cache), needs " 16756 + projectedBitmapSize + " bytes, only " 16757 + drawingCacheSize + " available"); 16758 } 16759 destroyDrawingCache(); 16760 mCachingFailed = true; 16761 return; 16762 } 16763 16764 boolean clear = true; 16765 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 16766 16767 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 16768 Bitmap.Config quality; 16769 if (!opaque) { 16770 // Never pick ARGB_4444 because it looks awful 16771 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 16772 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 16773 case DRAWING_CACHE_QUALITY_AUTO: 16774 case DRAWING_CACHE_QUALITY_LOW: 16775 case DRAWING_CACHE_QUALITY_HIGH: 16776 default: 16777 quality = Bitmap.Config.ARGB_8888; 16778 break; 16779 } 16780 } else { 16781 // Optimization for translucent windows 16782 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 16783 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 16784 } 16785 16786 // Try to cleanup memory 16787 if (bitmap != null) bitmap.recycle(); 16788 16789 try { 16790 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 16791 width, height, quality); 16792 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 16793 if (autoScale) { 16794 mDrawingCache = bitmap; 16795 } else { 16796 mUnscaledDrawingCache = bitmap; 16797 } 16798 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 16799 } catch (OutOfMemoryError e) { 16800 // If there is not enough memory to create the bitmap cache, just 16801 // ignore the issue as bitmap caches are not required to draw the 16802 // view hierarchy 16803 if (autoScale) { 16804 mDrawingCache = null; 16805 } else { 16806 mUnscaledDrawingCache = null; 16807 } 16808 mCachingFailed = true; 16809 return; 16810 } 16811 16812 clear = drawingCacheBackgroundColor != 0; 16813 } 16814 16815 Canvas canvas; 16816 if (attachInfo != null) { 16817 canvas = attachInfo.mCanvas; 16818 if (canvas == null) { 16819 canvas = new Canvas(); 16820 } 16821 canvas.setBitmap(bitmap); 16822 // Temporarily clobber the cached Canvas in case one of our children 16823 // is also using a drawing cache. Without this, the children would 16824 // steal the canvas by attaching their own bitmap to it and bad, bad 16825 // thing would happen (invisible views, corrupted drawings, etc.) 16826 attachInfo.mCanvas = null; 16827 } else { 16828 // This case should hopefully never or seldom happen 16829 canvas = new Canvas(bitmap); 16830 } 16831 16832 if (clear) { 16833 bitmap.eraseColor(drawingCacheBackgroundColor); 16834 } 16835 16836 computeScroll(); 16837 final int restoreCount = canvas.save(); 16838 16839 if (autoScale && scalingRequired) { 16840 final float scale = attachInfo.mApplicationScale; 16841 canvas.scale(scale, scale); 16842 } 16843 16844 canvas.translate(-mScrollX, -mScrollY); 16845 16846 mPrivateFlags |= PFLAG_DRAWN; 16847 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 16848 mLayerType != LAYER_TYPE_NONE) { 16849 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 16850 } 16851 16852 // Fast path for layouts with no backgrounds 16853 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16854 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16855 dispatchDraw(canvas); 16856 if (mOverlay != null && !mOverlay.isEmpty()) { 16857 mOverlay.getOverlayView().draw(canvas); 16858 } 16859 } else { 16860 draw(canvas); 16861 } 16862 16863 canvas.restoreToCount(restoreCount); 16864 canvas.setBitmap(null); 16865 16866 if (attachInfo != null) { 16867 // Restore the cached Canvas for our siblings 16868 attachInfo.mCanvas = canvas; 16869 } 16870 } 16871 16872 /** 16873 * Create a snapshot of the view into a bitmap. We should probably make 16874 * some form of this public, but should think about the API. 16875 * 16876 * @hide 16877 */ 16878 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 16879 int width = mRight - mLeft; 16880 int height = mBottom - mTop; 16881 16882 final AttachInfo attachInfo = mAttachInfo; 16883 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 16884 width = (int) ((width * scale) + 0.5f); 16885 height = (int) ((height * scale) + 0.5f); 16886 16887 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 16888 width > 0 ? width : 1, height > 0 ? height : 1, quality); 16889 if (bitmap == null) { 16890 throw new OutOfMemoryError(); 16891 } 16892 16893 Resources resources = getResources(); 16894 if (resources != null) { 16895 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 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 // things 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 ((backgroundColor & 0xff000000) != 0) { 16916 bitmap.eraseColor(backgroundColor); 16917 } 16918 16919 computeScroll(); 16920 final int restoreCount = canvas.save(); 16921 canvas.scale(scale, scale); 16922 canvas.translate(-mScrollX, -mScrollY); 16923 16924 // Temporarily remove the dirty mask 16925 int flags = mPrivateFlags; 16926 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16927 16928 // Fast path for layouts with no backgrounds 16929 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16930 dispatchDraw(canvas); 16931 if (mOverlay != null && !mOverlay.isEmpty()) { 16932 mOverlay.getOverlayView().draw(canvas); 16933 } 16934 } else { 16935 draw(canvas); 16936 } 16937 16938 mPrivateFlags = flags; 16939 16940 canvas.restoreToCount(restoreCount); 16941 canvas.setBitmap(null); 16942 16943 if (attachInfo != null) { 16944 // Restore the cached Canvas for our siblings 16945 attachInfo.mCanvas = canvas; 16946 } 16947 16948 return bitmap; 16949 } 16950 16951 /** 16952 * Indicates whether this View is currently in edit mode. A View is usually 16953 * in edit mode when displayed within a developer tool. For instance, if 16954 * this View is being drawn by a visual user interface builder, this method 16955 * should return true. 16956 * 16957 * Subclasses should check the return value of this method to provide 16958 * different behaviors if their normal behavior might interfere with the 16959 * host environment. For instance: the class spawns a thread in its 16960 * constructor, the drawing code relies on device-specific features, etc. 16961 * 16962 * This method is usually checked in the drawing code of custom widgets. 16963 * 16964 * @return True if this View is in edit mode, false otherwise. 16965 */ 16966 public boolean isInEditMode() { 16967 return false; 16968 } 16969 16970 /** 16971 * If the View draws content inside its padding and enables fading edges, 16972 * it needs to support padding offsets. Padding offsets are added to the 16973 * fading edges to extend the length of the fade so that it covers pixels 16974 * drawn inside the padding. 16975 * 16976 * Subclasses of this class should override this method if they need 16977 * to draw content inside the padding. 16978 * 16979 * @return True if padding offset must be applied, false otherwise. 16980 * 16981 * @see #getLeftPaddingOffset() 16982 * @see #getRightPaddingOffset() 16983 * @see #getTopPaddingOffset() 16984 * @see #getBottomPaddingOffset() 16985 * 16986 * @since CURRENT 16987 */ 16988 protected boolean isPaddingOffsetRequired() { 16989 return false; 16990 } 16991 16992 /** 16993 * Amount by which to extend the left fading region. Called only when 16994 * {@link #isPaddingOffsetRequired()} returns true. 16995 * 16996 * @return The left padding offset in pixels. 16997 * 16998 * @see #isPaddingOffsetRequired() 16999 * 17000 * @since CURRENT 17001 */ 17002 protected int getLeftPaddingOffset() { 17003 return 0; 17004 } 17005 17006 /** 17007 * Amount by which to extend the right fading region. Called only when 17008 * {@link #isPaddingOffsetRequired()} returns true. 17009 * 17010 * @return The right padding offset in pixels. 17011 * 17012 * @see #isPaddingOffsetRequired() 17013 * 17014 * @since CURRENT 17015 */ 17016 protected int getRightPaddingOffset() { 17017 return 0; 17018 } 17019 17020 /** 17021 * Amount by which to extend the top fading region. Called only when 17022 * {@link #isPaddingOffsetRequired()} returns true. 17023 * 17024 * @return The top padding offset in pixels. 17025 * 17026 * @see #isPaddingOffsetRequired() 17027 * 17028 * @since CURRENT 17029 */ 17030 protected int getTopPaddingOffset() { 17031 return 0; 17032 } 17033 17034 /** 17035 * Amount by which to extend the bottom fading region. Called only when 17036 * {@link #isPaddingOffsetRequired()} returns true. 17037 * 17038 * @return The bottom padding offset in pixels. 17039 * 17040 * @see #isPaddingOffsetRequired() 17041 * 17042 * @since CURRENT 17043 */ 17044 protected int getBottomPaddingOffset() { 17045 return 0; 17046 } 17047 17048 /** 17049 * @hide 17050 * @param offsetRequired 17051 */ 17052 protected int getFadeTop(boolean offsetRequired) { 17053 int top = mPaddingTop; 17054 if (offsetRequired) top += getTopPaddingOffset(); 17055 return top; 17056 } 17057 17058 /** 17059 * @hide 17060 * @param offsetRequired 17061 */ 17062 protected int getFadeHeight(boolean offsetRequired) { 17063 int padding = mPaddingTop; 17064 if (offsetRequired) padding += getTopPaddingOffset(); 17065 return mBottom - mTop - mPaddingBottom - padding; 17066 } 17067 17068 /** 17069 * <p>Indicates whether this view is attached to a hardware accelerated 17070 * window or not.</p> 17071 * 17072 * <p>Even if this method returns true, it does not mean that every call 17073 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 17074 * accelerated {@link android.graphics.Canvas}. For instance, if this view 17075 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 17076 * window is hardware accelerated, 17077 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 17078 * return false, and this method will return true.</p> 17079 * 17080 * @return True if the view is attached to a window and the window is 17081 * hardware accelerated; false in any other case. 17082 */ 17083 @ViewDebug.ExportedProperty(category = "drawing") 17084 public boolean isHardwareAccelerated() { 17085 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 17086 } 17087 17088 /** 17089 * Sets a rectangular area on this view to which the view will be clipped 17090 * when it is drawn. Setting the value to null will remove the clip bounds 17091 * and the view will draw normally, using its full bounds. 17092 * 17093 * @param clipBounds The rectangular area, in the local coordinates of 17094 * this view, to which future drawing operations will be clipped. 17095 */ 17096 public void setClipBounds(Rect clipBounds) { 17097 if (clipBounds == mClipBounds 17098 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 17099 return; 17100 } 17101 if (clipBounds != null) { 17102 if (mClipBounds == null) { 17103 mClipBounds = new Rect(clipBounds); 17104 } else { 17105 mClipBounds.set(clipBounds); 17106 } 17107 } else { 17108 mClipBounds = null; 17109 } 17110 mRenderNode.setClipBounds(mClipBounds); 17111 invalidateViewProperty(false, false); 17112 } 17113 17114 /** 17115 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 17116 * 17117 * @return A copy of the current clip bounds if clip bounds are set, 17118 * otherwise null. 17119 */ 17120 public Rect getClipBounds() { 17121 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 17122 } 17123 17124 17125 /** 17126 * Populates an output rectangle with the clip bounds of the view, 17127 * returning {@code true} if successful or {@code false} if the view's 17128 * clip bounds are {@code null}. 17129 * 17130 * @param outRect rectangle in which to place the clip bounds of the view 17131 * @return {@code true} if successful or {@code false} if the view's 17132 * clip bounds are {@code null} 17133 */ 17134 public boolean getClipBounds(Rect outRect) { 17135 if (mClipBounds != null) { 17136 outRect.set(mClipBounds); 17137 return true; 17138 } 17139 return false; 17140 } 17141 17142 /** 17143 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 17144 * case of an active Animation being run on the view. 17145 */ 17146 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 17147 Animation a, boolean scalingRequired) { 17148 Transformation invalidationTransform; 17149 final int flags = parent.mGroupFlags; 17150 final boolean initialized = a.isInitialized(); 17151 if (!initialized) { 17152 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 17153 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 17154 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 17155 onAnimationStart(); 17156 } 17157 17158 final Transformation t = parent.getChildTransformation(); 17159 boolean more = a.getTransformation(drawingTime, t, 1f); 17160 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 17161 if (parent.mInvalidationTransformation == null) { 17162 parent.mInvalidationTransformation = new Transformation(); 17163 } 17164 invalidationTransform = parent.mInvalidationTransformation; 17165 a.getTransformation(drawingTime, invalidationTransform, 1f); 17166 } else { 17167 invalidationTransform = t; 17168 } 17169 17170 if (more) { 17171 if (!a.willChangeBounds()) { 17172 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 17173 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 17174 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 17175 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 17176 // The child need to draw an animation, potentially offscreen, so 17177 // make sure we do not cancel invalidate requests 17178 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17179 parent.invalidate(mLeft, mTop, mRight, mBottom); 17180 } 17181 } else { 17182 if (parent.mInvalidateRegion == null) { 17183 parent.mInvalidateRegion = new RectF(); 17184 } 17185 final RectF region = parent.mInvalidateRegion; 17186 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 17187 invalidationTransform); 17188 17189 // The child need to draw an animation, potentially offscreen, so 17190 // make sure we do not cancel invalidate requests 17191 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17192 17193 final int left = mLeft + (int) region.left; 17194 final int top = mTop + (int) region.top; 17195 parent.invalidate(left, top, left + (int) (region.width() + .5f), 17196 top + (int) (region.height() + .5f)); 17197 } 17198 } 17199 return more; 17200 } 17201 17202 /** 17203 * This method is called by getDisplayList() when a display list is recorded for a View. 17204 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 17205 */ 17206 void setDisplayListProperties(RenderNode renderNode) { 17207 if (renderNode != null) { 17208 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 17209 renderNode.setClipToBounds(mParent instanceof ViewGroup 17210 && ((ViewGroup) mParent).getClipChildren()); 17211 17212 float alpha = 1; 17213 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 17214 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17215 ViewGroup parentVG = (ViewGroup) mParent; 17216 final Transformation t = parentVG.getChildTransformation(); 17217 if (parentVG.getChildStaticTransformation(this, t)) { 17218 final int transformType = t.getTransformationType(); 17219 if (transformType != Transformation.TYPE_IDENTITY) { 17220 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 17221 alpha = t.getAlpha(); 17222 } 17223 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 17224 renderNode.setStaticMatrix(t.getMatrix()); 17225 } 17226 } 17227 } 17228 } 17229 if (mTransformationInfo != null) { 17230 alpha *= getFinalAlpha(); 17231 if (alpha < 1) { 17232 final int multipliedAlpha = (int) (255 * alpha); 17233 if (onSetAlpha(multipliedAlpha)) { 17234 alpha = 1; 17235 } 17236 } 17237 renderNode.setAlpha(alpha); 17238 } else if (alpha < 1) { 17239 renderNode.setAlpha(alpha); 17240 } 17241 } 17242 } 17243 17244 /** 17245 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 17246 * 17247 * This is where the View specializes rendering behavior based on layer type, 17248 * and hardware acceleration. 17249 */ 17250 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 17251 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 17252 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 17253 * 17254 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 17255 * HW accelerated, it can't handle drawing RenderNodes. 17256 */ 17257 boolean drawingWithRenderNode = mAttachInfo != null 17258 && mAttachInfo.mHardwareAccelerated 17259 && hardwareAcceleratedCanvas; 17260 17261 boolean more = false; 17262 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 17263 final int parentFlags = parent.mGroupFlags; 17264 17265 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 17266 parent.getChildTransformation().clear(); 17267 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17268 } 17269 17270 Transformation transformToApply = null; 17271 boolean concatMatrix = false; 17272 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 17273 final Animation a = getAnimation(); 17274 if (a != null) { 17275 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 17276 concatMatrix = a.willChangeTransformationMatrix(); 17277 if (concatMatrix) { 17278 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17279 } 17280 transformToApply = parent.getChildTransformation(); 17281 } else { 17282 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 17283 // No longer animating: clear out old animation matrix 17284 mRenderNode.setAnimationMatrix(null); 17285 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17286 } 17287 if (!drawingWithRenderNode 17288 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17289 final Transformation t = parent.getChildTransformation(); 17290 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 17291 if (hasTransform) { 17292 final int transformType = t.getTransformationType(); 17293 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 17294 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 17295 } 17296 } 17297 } 17298 17299 concatMatrix |= !childHasIdentityMatrix; 17300 17301 // Sets the flag as early as possible to allow draw() implementations 17302 // to call invalidate() successfully when doing animations 17303 mPrivateFlags |= PFLAG_DRAWN; 17304 17305 if (!concatMatrix && 17306 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 17307 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 17308 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 17309 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 17310 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 17311 return more; 17312 } 17313 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 17314 17315 if (hardwareAcceleratedCanvas) { 17316 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 17317 // retain the flag's value temporarily in the mRecreateDisplayList flag 17318 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 17319 mPrivateFlags &= ~PFLAG_INVALIDATED; 17320 } 17321 17322 RenderNode renderNode = null; 17323 Bitmap cache = null; 17324 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 17325 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 17326 if (layerType != LAYER_TYPE_NONE) { 17327 // If not drawing with RenderNode, treat HW layers as SW 17328 layerType = LAYER_TYPE_SOFTWARE; 17329 buildDrawingCache(true); 17330 } 17331 cache = getDrawingCache(true); 17332 } 17333 17334 if (drawingWithRenderNode) { 17335 // Delay getting the display list until animation-driven alpha values are 17336 // set up and possibly passed on to the view 17337 renderNode = updateDisplayListIfDirty(); 17338 if (!renderNode.isValid()) { 17339 // Uncommon, but possible. If a view is removed from the hierarchy during the call 17340 // to getDisplayList(), the display list will be marked invalid and we should not 17341 // try to use it again. 17342 renderNode = null; 17343 drawingWithRenderNode = false; 17344 } 17345 } 17346 17347 int sx = 0; 17348 int sy = 0; 17349 if (!drawingWithRenderNode) { 17350 computeScroll(); 17351 sx = mScrollX; 17352 sy = mScrollY; 17353 } 17354 17355 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 17356 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 17357 17358 int restoreTo = -1; 17359 if (!drawingWithRenderNode || transformToApply != null) { 17360 restoreTo = canvas.save(); 17361 } 17362 if (offsetForScroll) { 17363 canvas.translate(mLeft - sx, mTop - sy); 17364 } else { 17365 if (!drawingWithRenderNode) { 17366 canvas.translate(mLeft, mTop); 17367 } 17368 if (scalingRequired) { 17369 if (drawingWithRenderNode) { 17370 // TODO: Might not need this if we put everything inside the DL 17371 restoreTo = canvas.save(); 17372 } 17373 // mAttachInfo cannot be null, otherwise scalingRequired == false 17374 final float scale = 1.0f / mAttachInfo.mApplicationScale; 17375 canvas.scale(scale, scale); 17376 } 17377 } 17378 17379 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 17380 if (transformToApply != null 17381 || alpha < 1 17382 || !hasIdentityMatrix() 17383 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17384 if (transformToApply != null || !childHasIdentityMatrix) { 17385 int transX = 0; 17386 int transY = 0; 17387 17388 if (offsetForScroll) { 17389 transX = -sx; 17390 transY = -sy; 17391 } 17392 17393 if (transformToApply != null) { 17394 if (concatMatrix) { 17395 if (drawingWithRenderNode) { 17396 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 17397 } else { 17398 // Undo the scroll translation, apply the transformation matrix, 17399 // then redo the scroll translate to get the correct result. 17400 canvas.translate(-transX, -transY); 17401 canvas.concat(transformToApply.getMatrix()); 17402 canvas.translate(transX, transY); 17403 } 17404 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17405 } 17406 17407 float transformAlpha = transformToApply.getAlpha(); 17408 if (transformAlpha < 1) { 17409 alpha *= transformAlpha; 17410 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17411 } 17412 } 17413 17414 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 17415 canvas.translate(-transX, -transY); 17416 canvas.concat(getMatrix()); 17417 canvas.translate(transX, transY); 17418 } 17419 } 17420 17421 // Deal with alpha if it is or used to be <1 17422 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17423 if (alpha < 1) { 17424 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17425 } else { 17426 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17427 } 17428 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17429 if (!drawingWithDrawingCache) { 17430 final int multipliedAlpha = (int) (255 * alpha); 17431 if (!onSetAlpha(multipliedAlpha)) { 17432 if (drawingWithRenderNode) { 17433 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 17434 } else if (layerType == LAYER_TYPE_NONE) { 17435 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 17436 multipliedAlpha); 17437 } 17438 } else { 17439 // Alpha is handled by the child directly, clobber the layer's alpha 17440 mPrivateFlags |= PFLAG_ALPHA_SET; 17441 } 17442 } 17443 } 17444 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17445 onSetAlpha(255); 17446 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17447 } 17448 17449 if (!drawingWithRenderNode) { 17450 // apply clips directly, since RenderNode won't do it for this draw 17451 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 17452 if (offsetForScroll) { 17453 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 17454 } else { 17455 if (!scalingRequired || cache == null) { 17456 canvas.clipRect(0, 0, getWidth(), getHeight()); 17457 } else { 17458 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 17459 } 17460 } 17461 } 17462 17463 if (mClipBounds != null) { 17464 // clip bounds ignore scroll 17465 canvas.clipRect(mClipBounds); 17466 } 17467 } 17468 17469 if (!drawingWithDrawingCache) { 17470 if (drawingWithRenderNode) { 17471 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17472 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 17473 } else { 17474 // Fast path for layouts with no backgrounds 17475 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17476 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17477 dispatchDraw(canvas); 17478 } else { 17479 draw(canvas); 17480 } 17481 } 17482 } else if (cache != null) { 17483 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17484 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 17485 // no layer paint, use temporary paint to draw bitmap 17486 Paint cachePaint = parent.mCachePaint; 17487 if (cachePaint == null) { 17488 cachePaint = new Paint(); 17489 cachePaint.setDither(false); 17490 parent.mCachePaint = cachePaint; 17491 } 17492 cachePaint.setAlpha((int) (alpha * 255)); 17493 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 17494 } else { 17495 // use layer paint to draw the bitmap, merging the two alphas, but also restore 17496 int layerPaintAlpha = mLayerPaint.getAlpha(); 17497 if (alpha < 1) { 17498 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 17499 } 17500 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 17501 if (alpha < 1) { 17502 mLayerPaint.setAlpha(layerPaintAlpha); 17503 } 17504 } 17505 } 17506 17507 if (restoreTo >= 0) { 17508 canvas.restoreToCount(restoreTo); 17509 } 17510 17511 if (a != null && !more) { 17512 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 17513 onSetAlpha(255); 17514 } 17515 parent.finishAnimatingView(this, a); 17516 } 17517 17518 if (more && hardwareAcceleratedCanvas) { 17519 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17520 // alpha animations should cause the child to recreate its display list 17521 invalidate(true); 17522 } 17523 } 17524 17525 mRecreateDisplayList = false; 17526 17527 return more; 17528 } 17529 17530 static Paint getDebugPaint() { 17531 if (sDebugPaint == null) { 17532 sDebugPaint = new Paint(); 17533 sDebugPaint.setAntiAlias(false); 17534 } 17535 return sDebugPaint; 17536 } 17537 17538 final int dipsToPixels(int dips) { 17539 float scale = getContext().getResources().getDisplayMetrics().density; 17540 return (int) (dips * scale + 0.5f); 17541 } 17542 17543 final private void debugDrawFocus(Canvas canvas) { 17544 if (isFocused()) { 17545 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 17546 final int l = mScrollX; 17547 final int r = l + mRight - mLeft; 17548 final int t = mScrollY; 17549 final int b = t + mBottom - mTop; 17550 17551 final Paint paint = getDebugPaint(); 17552 paint.setColor(DEBUG_CORNERS_COLOR); 17553 17554 // Draw squares in corners. 17555 paint.setStyle(Paint.Style.FILL); 17556 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 17557 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 17558 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 17559 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 17560 17561 // Draw big X across the view. 17562 paint.setStyle(Paint.Style.STROKE); 17563 canvas.drawLine(l, t, r, b, paint); 17564 canvas.drawLine(l, b, r, t, paint); 17565 } 17566 } 17567 17568 /** 17569 * Manually render this view (and all of its children) to the given Canvas. 17570 * The view must have already done a full layout before this function is 17571 * called. When implementing a view, implement 17572 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 17573 * If you do need to override this method, call the superclass version. 17574 * 17575 * @param canvas The Canvas to which the View is rendered. 17576 */ 17577 @CallSuper 17578 public void draw(Canvas canvas) { 17579 final int privateFlags = mPrivateFlags; 17580 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 17581 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 17582 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 17583 17584 /* 17585 * Draw traversal performs several drawing steps which must be executed 17586 * in the appropriate order: 17587 * 17588 * 1. Draw the background 17589 * 2. If necessary, save the canvas' layers to prepare for fading 17590 * 3. Draw view's content 17591 * 4. Draw children 17592 * 5. If necessary, draw the fading edges and restore layers 17593 * 6. Draw decorations (scrollbars for instance) 17594 */ 17595 17596 // Step 1, draw the background, if needed 17597 int saveCount; 17598 17599 if (!dirtyOpaque) { 17600 drawBackground(canvas); 17601 } 17602 17603 // skip step 2 & 5 if possible (common case) 17604 final int viewFlags = mViewFlags; 17605 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 17606 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 17607 if (!verticalEdges && !horizontalEdges) { 17608 // Step 3, draw the content 17609 if (!dirtyOpaque) onDraw(canvas); 17610 17611 // Step 4, draw the children 17612 dispatchDraw(canvas); 17613 17614 // Overlay is part of the content and draws beneath Foreground 17615 if (mOverlay != null && !mOverlay.isEmpty()) { 17616 mOverlay.getOverlayView().dispatchDraw(canvas); 17617 } 17618 17619 // Step 6, draw decorations (foreground, scrollbars) 17620 onDrawForeground(canvas); 17621 17622 if (debugDraw()) { 17623 debugDrawFocus(canvas); 17624 } 17625 17626 // we're done... 17627 return; 17628 } 17629 17630 /* 17631 * Here we do the full fledged routine... 17632 * (this is an uncommon case where speed matters less, 17633 * this is why we repeat some of the tests that have been 17634 * done above) 17635 */ 17636 17637 boolean drawTop = false; 17638 boolean drawBottom = false; 17639 boolean drawLeft = false; 17640 boolean drawRight = false; 17641 17642 float topFadeStrength = 0.0f; 17643 float bottomFadeStrength = 0.0f; 17644 float leftFadeStrength = 0.0f; 17645 float rightFadeStrength = 0.0f; 17646 17647 // Step 2, save the canvas' layers 17648 int paddingLeft = mPaddingLeft; 17649 17650 final boolean offsetRequired = isPaddingOffsetRequired(); 17651 if (offsetRequired) { 17652 paddingLeft += getLeftPaddingOffset(); 17653 } 17654 17655 int left = mScrollX + paddingLeft; 17656 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 17657 int top = mScrollY + getFadeTop(offsetRequired); 17658 int bottom = top + getFadeHeight(offsetRequired); 17659 17660 if (offsetRequired) { 17661 right += getRightPaddingOffset(); 17662 bottom += getBottomPaddingOffset(); 17663 } 17664 17665 final ScrollabilityCache scrollabilityCache = mScrollCache; 17666 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 17667 int length = (int) fadeHeight; 17668 17669 // clip the fade length if top and bottom fades overlap 17670 // overlapping fades produce odd-looking artifacts 17671 if (verticalEdges && (top + length > bottom - length)) { 17672 length = (bottom - top) / 2; 17673 } 17674 17675 // also clip horizontal fades if necessary 17676 if (horizontalEdges && (left + length > right - length)) { 17677 length = (right - left) / 2; 17678 } 17679 17680 if (verticalEdges) { 17681 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 17682 drawTop = topFadeStrength * fadeHeight > 1.0f; 17683 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 17684 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 17685 } 17686 17687 if (horizontalEdges) { 17688 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 17689 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 17690 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 17691 drawRight = rightFadeStrength * fadeHeight > 1.0f; 17692 } 17693 17694 saveCount = canvas.getSaveCount(); 17695 17696 int solidColor = getSolidColor(); 17697 if (solidColor == 0) { 17698 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 17699 17700 if (drawTop) { 17701 canvas.saveLayer(left, top, right, top + length, null, flags); 17702 } 17703 17704 if (drawBottom) { 17705 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 17706 } 17707 17708 if (drawLeft) { 17709 canvas.saveLayer(left, top, left + length, bottom, null, flags); 17710 } 17711 17712 if (drawRight) { 17713 canvas.saveLayer(right - length, top, right, bottom, null, flags); 17714 } 17715 } else { 17716 scrollabilityCache.setFadeColor(solidColor); 17717 } 17718 17719 // Step 3, draw the content 17720 if (!dirtyOpaque) onDraw(canvas); 17721 17722 // Step 4, draw the children 17723 dispatchDraw(canvas); 17724 17725 // Step 5, draw the fade effect and restore layers 17726 final Paint p = scrollabilityCache.paint; 17727 final Matrix matrix = scrollabilityCache.matrix; 17728 final Shader fade = scrollabilityCache.shader; 17729 17730 if (drawTop) { 17731 matrix.setScale(1, fadeHeight * topFadeStrength); 17732 matrix.postTranslate(left, top); 17733 fade.setLocalMatrix(matrix); 17734 p.setShader(fade); 17735 canvas.drawRect(left, top, right, top + length, p); 17736 } 17737 17738 if (drawBottom) { 17739 matrix.setScale(1, fadeHeight * bottomFadeStrength); 17740 matrix.postRotate(180); 17741 matrix.postTranslate(left, bottom); 17742 fade.setLocalMatrix(matrix); 17743 p.setShader(fade); 17744 canvas.drawRect(left, bottom - length, right, bottom, p); 17745 } 17746 17747 if (drawLeft) { 17748 matrix.setScale(1, fadeHeight * leftFadeStrength); 17749 matrix.postRotate(-90); 17750 matrix.postTranslate(left, top); 17751 fade.setLocalMatrix(matrix); 17752 p.setShader(fade); 17753 canvas.drawRect(left, top, left + length, bottom, p); 17754 } 17755 17756 if (drawRight) { 17757 matrix.setScale(1, fadeHeight * rightFadeStrength); 17758 matrix.postRotate(90); 17759 matrix.postTranslate(right, top); 17760 fade.setLocalMatrix(matrix); 17761 p.setShader(fade); 17762 canvas.drawRect(right - length, top, right, bottom, p); 17763 } 17764 17765 canvas.restoreToCount(saveCount); 17766 17767 // Overlay is part of the content and draws beneath Foreground 17768 if (mOverlay != null && !mOverlay.isEmpty()) { 17769 mOverlay.getOverlayView().dispatchDraw(canvas); 17770 } 17771 17772 // Step 6, draw decorations (foreground, scrollbars) 17773 onDrawForeground(canvas); 17774 17775 if (debugDraw()) { 17776 debugDrawFocus(canvas); 17777 } 17778 } 17779 17780 /** 17781 * Draws the background onto the specified canvas. 17782 * 17783 * @param canvas Canvas on which to draw the background 17784 */ 17785 private void drawBackground(Canvas canvas) { 17786 final Drawable background = mBackground; 17787 if (background == null) { 17788 return; 17789 } 17790 17791 setBackgroundBounds(); 17792 17793 // Attempt to use a display list if requested. 17794 if (canvas.isHardwareAccelerated() && mAttachInfo != null 17795 && mAttachInfo.mThreadedRenderer != null) { 17796 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 17797 17798 final RenderNode renderNode = mBackgroundRenderNode; 17799 if (renderNode != null && renderNode.isValid()) { 17800 setBackgroundRenderNodeProperties(renderNode); 17801 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 17802 return; 17803 } 17804 } 17805 17806 final int scrollX = mScrollX; 17807 final int scrollY = mScrollY; 17808 if ((scrollX | scrollY) == 0) { 17809 background.draw(canvas); 17810 } else { 17811 canvas.translate(scrollX, scrollY); 17812 background.draw(canvas); 17813 canvas.translate(-scrollX, -scrollY); 17814 } 17815 } 17816 17817 /** 17818 * Sets the correct background bounds and rebuilds the outline, if needed. 17819 * <p/> 17820 * This is called by LayoutLib. 17821 */ 17822 void setBackgroundBounds() { 17823 if (mBackgroundSizeChanged && mBackground != null) { 17824 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 17825 mBackgroundSizeChanged = false; 17826 rebuildOutline(); 17827 } 17828 } 17829 17830 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 17831 renderNode.setTranslationX(mScrollX); 17832 renderNode.setTranslationY(mScrollY); 17833 } 17834 17835 /** 17836 * Creates a new display list or updates the existing display list for the 17837 * specified Drawable. 17838 * 17839 * @param drawable Drawable for which to create a display list 17840 * @param renderNode Existing RenderNode, or {@code null} 17841 * @return A valid display list for the specified drawable 17842 */ 17843 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 17844 if (renderNode == null) { 17845 renderNode = RenderNode.create(drawable.getClass().getName(), this); 17846 } 17847 17848 final Rect bounds = drawable.getBounds(); 17849 final int width = bounds.width(); 17850 final int height = bounds.height(); 17851 final DisplayListCanvas canvas = renderNode.start(width, height); 17852 17853 // Reverse left/top translation done by drawable canvas, which will 17854 // instead be applied by rendernode's LTRB bounds below. This way, the 17855 // drawable's bounds match with its rendernode bounds and its content 17856 // will lie within those bounds in the rendernode tree. 17857 canvas.translate(-bounds.left, -bounds.top); 17858 17859 try { 17860 drawable.draw(canvas); 17861 } finally { 17862 renderNode.end(canvas); 17863 } 17864 17865 // Set up drawable properties that are view-independent. 17866 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 17867 renderNode.setProjectBackwards(drawable.isProjected()); 17868 renderNode.setProjectionReceiver(true); 17869 renderNode.setClipToBounds(false); 17870 return renderNode; 17871 } 17872 17873 /** 17874 * Returns the overlay for this view, creating it if it does not yet exist. 17875 * Adding drawables to the overlay will cause them to be displayed whenever 17876 * the view itself is redrawn. Objects in the overlay should be actively 17877 * managed: remove them when they should not be displayed anymore. The 17878 * overlay will always have the same size as its host view. 17879 * 17880 * <p>Note: Overlays do not currently work correctly with {@link 17881 * SurfaceView} or {@link TextureView}; contents in overlays for these 17882 * types of views may not display correctly.</p> 17883 * 17884 * @return The ViewOverlay object for this view. 17885 * @see ViewOverlay 17886 */ 17887 public ViewOverlay getOverlay() { 17888 if (mOverlay == null) { 17889 mOverlay = new ViewOverlay(mContext, this); 17890 } 17891 return mOverlay; 17892 } 17893 17894 /** 17895 * Override this if your view is known to always be drawn on top of a solid color background, 17896 * and needs to draw fading edges. Returning a non-zero color enables the view system to 17897 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 17898 * should be set to 0xFF. 17899 * 17900 * @see #setVerticalFadingEdgeEnabled(boolean) 17901 * @see #setHorizontalFadingEdgeEnabled(boolean) 17902 * 17903 * @return The known solid color background for this view, or 0 if the color may vary 17904 */ 17905 @ViewDebug.ExportedProperty(category = "drawing") 17906 @ColorInt 17907 public int getSolidColor() { 17908 return 0; 17909 } 17910 17911 /** 17912 * Build a human readable string representation of the specified view flags. 17913 * 17914 * @param flags the view flags to convert to a string 17915 * @return a String representing the supplied flags 17916 */ 17917 private static String printFlags(int flags) { 17918 String output = ""; 17919 int numFlags = 0; 17920 if ((flags & FOCUSABLE_MASK) == FOCUSABLE) { 17921 output += "TAKES_FOCUS"; 17922 numFlags++; 17923 } 17924 17925 switch (flags & VISIBILITY_MASK) { 17926 case INVISIBLE: 17927 if (numFlags > 0) { 17928 output += " "; 17929 } 17930 output += "INVISIBLE"; 17931 // USELESS HERE numFlags++; 17932 break; 17933 case GONE: 17934 if (numFlags > 0) { 17935 output += " "; 17936 } 17937 output += "GONE"; 17938 // USELESS HERE numFlags++; 17939 break; 17940 default: 17941 break; 17942 } 17943 return output; 17944 } 17945 17946 /** 17947 * Build a human readable string representation of the specified private 17948 * view flags. 17949 * 17950 * @param privateFlags the private view flags to convert to a string 17951 * @return a String representing the supplied flags 17952 */ 17953 private static String printPrivateFlags(int privateFlags) { 17954 String output = ""; 17955 int numFlags = 0; 17956 17957 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 17958 output += "WANTS_FOCUS"; 17959 numFlags++; 17960 } 17961 17962 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 17963 if (numFlags > 0) { 17964 output += " "; 17965 } 17966 output += "FOCUSED"; 17967 numFlags++; 17968 } 17969 17970 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 17971 if (numFlags > 0) { 17972 output += " "; 17973 } 17974 output += "SELECTED"; 17975 numFlags++; 17976 } 17977 17978 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 17979 if (numFlags > 0) { 17980 output += " "; 17981 } 17982 output += "IS_ROOT_NAMESPACE"; 17983 numFlags++; 17984 } 17985 17986 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 17987 if (numFlags > 0) { 17988 output += " "; 17989 } 17990 output += "HAS_BOUNDS"; 17991 numFlags++; 17992 } 17993 17994 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 17995 if (numFlags > 0) { 17996 output += " "; 17997 } 17998 output += "DRAWN"; 17999 // USELESS HERE numFlags++; 18000 } 18001 return output; 18002 } 18003 18004 /** 18005 * <p>Indicates whether or not this view's layout will be requested during 18006 * the next hierarchy layout pass.</p> 18007 * 18008 * @return true if the layout will be forced during next layout pass 18009 */ 18010 public boolean isLayoutRequested() { 18011 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 18012 } 18013 18014 /** 18015 * Return true if o is a ViewGroup that is laying out using optical bounds. 18016 * @hide 18017 */ 18018 public static boolean isLayoutModeOptical(Object o) { 18019 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 18020 } 18021 18022 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 18023 Insets parentInsets = mParent instanceof View ? 18024 ((View) mParent).getOpticalInsets() : Insets.NONE; 18025 Insets childInsets = getOpticalInsets(); 18026 return setFrame( 18027 left + parentInsets.left - childInsets.left, 18028 top + parentInsets.top - childInsets.top, 18029 right + parentInsets.left + childInsets.right, 18030 bottom + parentInsets.top + childInsets.bottom); 18031 } 18032 18033 /** 18034 * Assign a size and position to a view and all of its 18035 * descendants 18036 * 18037 * <p>This is the second phase of the layout mechanism. 18038 * (The first is measuring). In this phase, each parent calls 18039 * layout on all of its children to position them. 18040 * This is typically done using the child measurements 18041 * that were stored in the measure pass().</p> 18042 * 18043 * <p>Derived classes should not override this method. 18044 * Derived classes with children should override 18045 * onLayout. In that method, they should 18046 * call layout on each of their children.</p> 18047 * 18048 * @param l Left position, relative to parent 18049 * @param t Top position, relative to parent 18050 * @param r Right position, relative to parent 18051 * @param b Bottom position, relative to parent 18052 */ 18053 @SuppressWarnings({"unchecked"}) 18054 public void layout(int l, int t, int r, int b) { 18055 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 18056 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 18057 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 18058 } 18059 18060 int oldL = mLeft; 18061 int oldT = mTop; 18062 int oldB = mBottom; 18063 int oldR = mRight; 18064 18065 boolean changed = isLayoutModeOptical(mParent) ? 18066 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 18067 18068 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 18069 onLayout(changed, l, t, r, b); 18070 18071 if (shouldDrawRoundScrollbar()) { 18072 if(mRoundScrollbarRenderer == null) { 18073 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 18074 } 18075 } else { 18076 mRoundScrollbarRenderer = null; 18077 } 18078 18079 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 18080 18081 ListenerInfo li = mListenerInfo; 18082 if (li != null && li.mOnLayoutChangeListeners != null) { 18083 ArrayList<OnLayoutChangeListener> listenersCopy = 18084 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 18085 int numListeners = listenersCopy.size(); 18086 for (int i = 0; i < numListeners; ++i) { 18087 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 18088 } 18089 } 18090 } 18091 18092 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 18093 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 18094 } 18095 18096 /** 18097 * Called from layout when this view should 18098 * assign a size and position to each of its children. 18099 * 18100 * Derived classes with children should override 18101 * this method and call layout on each of 18102 * their children. 18103 * @param changed This is a new size or position for this view 18104 * @param left Left position, relative to parent 18105 * @param top Top position, relative to parent 18106 * @param right Right position, relative to parent 18107 * @param bottom Bottom position, relative to parent 18108 */ 18109 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 18110 } 18111 18112 /** 18113 * Assign a size and position to this view. 18114 * 18115 * This is called from layout. 18116 * 18117 * @param left Left position, relative to parent 18118 * @param top Top position, relative to parent 18119 * @param right Right position, relative to parent 18120 * @param bottom Bottom position, relative to parent 18121 * @return true if the new size and position are different than the 18122 * previous ones 18123 * {@hide} 18124 */ 18125 protected boolean setFrame(int left, int top, int right, int bottom) { 18126 boolean changed = false; 18127 18128 if (DBG) { 18129 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 18130 + right + "," + bottom + ")"); 18131 } 18132 18133 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 18134 changed = true; 18135 18136 // Remember our drawn bit 18137 int drawn = mPrivateFlags & PFLAG_DRAWN; 18138 18139 int oldWidth = mRight - mLeft; 18140 int oldHeight = mBottom - mTop; 18141 int newWidth = right - left; 18142 int newHeight = bottom - top; 18143 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 18144 18145 // Invalidate our old position 18146 invalidate(sizeChanged); 18147 18148 mLeft = left; 18149 mTop = top; 18150 mRight = right; 18151 mBottom = bottom; 18152 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 18153 18154 mPrivateFlags |= PFLAG_HAS_BOUNDS; 18155 18156 18157 if (sizeChanged) { 18158 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 18159 } 18160 18161 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 18162 // If we are visible, force the DRAWN bit to on so that 18163 // this invalidate will go through (at least to our parent). 18164 // This is because someone may have invalidated this view 18165 // before this call to setFrame came in, thereby clearing 18166 // the DRAWN bit. 18167 mPrivateFlags |= PFLAG_DRAWN; 18168 invalidate(sizeChanged); 18169 // parent display list may need to be recreated based on a change in the bounds 18170 // of any child 18171 invalidateParentCaches(); 18172 } 18173 18174 // Reset drawn bit to original value (invalidate turns it off) 18175 mPrivateFlags |= drawn; 18176 18177 mBackgroundSizeChanged = true; 18178 if (mForegroundInfo != null) { 18179 mForegroundInfo.mBoundsChanged = true; 18180 } 18181 18182 notifySubtreeAccessibilityStateChangedIfNeeded(); 18183 } 18184 return changed; 18185 } 18186 18187 /** 18188 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 18189 * @hide 18190 */ 18191 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 18192 setFrame(left, top, right, bottom); 18193 } 18194 18195 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 18196 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 18197 if (mOverlay != null) { 18198 mOverlay.getOverlayView().setRight(newWidth); 18199 mOverlay.getOverlayView().setBottom(newHeight); 18200 } 18201 rebuildOutline(); 18202 } 18203 18204 /** 18205 * Finalize inflating a view from XML. This is called as the last phase 18206 * of inflation, after all child views have been added. 18207 * 18208 * <p>Even if the subclass overrides onFinishInflate, they should always be 18209 * sure to call the super method, so that we get called. 18210 */ 18211 @CallSuper 18212 protected void onFinishInflate() { 18213 } 18214 18215 /** 18216 * Returns the resources associated with this view. 18217 * 18218 * @return Resources object. 18219 */ 18220 public Resources getResources() { 18221 return mResources; 18222 } 18223 18224 /** 18225 * Invalidates the specified Drawable. 18226 * 18227 * @param drawable the drawable to invalidate 18228 */ 18229 @Override 18230 public void invalidateDrawable(@NonNull Drawable drawable) { 18231 if (verifyDrawable(drawable)) { 18232 final Rect dirty = drawable.getDirtyBounds(); 18233 final int scrollX = mScrollX; 18234 final int scrollY = mScrollY; 18235 18236 invalidate(dirty.left + scrollX, dirty.top + scrollY, 18237 dirty.right + scrollX, dirty.bottom + scrollY); 18238 rebuildOutline(); 18239 } 18240 } 18241 18242 /** 18243 * Schedules an action on a drawable to occur at a specified time. 18244 * 18245 * @param who the recipient of the action 18246 * @param what the action to run on the drawable 18247 * @param when the time at which the action must occur. Uses the 18248 * {@link SystemClock#uptimeMillis} timebase. 18249 */ 18250 @Override 18251 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 18252 if (verifyDrawable(who) && what != null) { 18253 final long delay = when - SystemClock.uptimeMillis(); 18254 if (mAttachInfo != null) { 18255 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 18256 Choreographer.CALLBACK_ANIMATION, what, who, 18257 Choreographer.subtractFrameDelay(delay)); 18258 } else { 18259 // Postpone the runnable until we know 18260 // on which thread it needs to run. 18261 getRunQueue().postDelayed(what, delay); 18262 } 18263 } 18264 } 18265 18266 /** 18267 * Cancels a scheduled action on a drawable. 18268 * 18269 * @param who the recipient of the action 18270 * @param what the action to cancel 18271 */ 18272 @Override 18273 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 18274 if (verifyDrawable(who) && what != null) { 18275 if (mAttachInfo != null) { 18276 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18277 Choreographer.CALLBACK_ANIMATION, what, who); 18278 } 18279 getRunQueue().removeCallbacks(what); 18280 } 18281 } 18282 18283 /** 18284 * Unschedule any events associated with the given Drawable. This can be 18285 * used when selecting a new Drawable into a view, so that the previous 18286 * one is completely unscheduled. 18287 * 18288 * @param who The Drawable to unschedule. 18289 * 18290 * @see #drawableStateChanged 18291 */ 18292 public void unscheduleDrawable(Drawable who) { 18293 if (mAttachInfo != null && who != null) { 18294 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18295 Choreographer.CALLBACK_ANIMATION, null, who); 18296 } 18297 } 18298 18299 /** 18300 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 18301 * that the View directionality can and will be resolved before its Drawables. 18302 * 18303 * Will call {@link View#onResolveDrawables} when resolution is done. 18304 * 18305 * @hide 18306 */ 18307 protected void resolveDrawables() { 18308 // Drawables resolution may need to happen before resolving the layout direction (which is 18309 // done only during the measure() call). 18310 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 18311 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 18312 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 18313 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 18314 // direction to be resolved as its resolved value will be the same as its raw value. 18315 if (!isLayoutDirectionResolved() && 18316 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 18317 return; 18318 } 18319 18320 final int layoutDirection = isLayoutDirectionResolved() ? 18321 getLayoutDirection() : getRawLayoutDirection(); 18322 18323 if (mBackground != null) { 18324 mBackground.setLayoutDirection(layoutDirection); 18325 } 18326 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18327 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 18328 } 18329 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 18330 onResolveDrawables(layoutDirection); 18331 } 18332 18333 boolean areDrawablesResolved() { 18334 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 18335 } 18336 18337 /** 18338 * Called when layout direction has been resolved. 18339 * 18340 * The default implementation does nothing. 18341 * 18342 * @param layoutDirection The resolved layout direction. 18343 * 18344 * @see #LAYOUT_DIRECTION_LTR 18345 * @see #LAYOUT_DIRECTION_RTL 18346 * 18347 * @hide 18348 */ 18349 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 18350 } 18351 18352 /** 18353 * @hide 18354 */ 18355 protected void resetResolvedDrawables() { 18356 resetResolvedDrawablesInternal(); 18357 } 18358 18359 void resetResolvedDrawablesInternal() { 18360 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 18361 } 18362 18363 /** 18364 * If your view subclass is displaying its own Drawable objects, it should 18365 * override this function and return true for any Drawable it is 18366 * displaying. This allows animations for those drawables to be 18367 * scheduled. 18368 * 18369 * <p>Be sure to call through to the super class when overriding this 18370 * function. 18371 * 18372 * @param who The Drawable to verify. Return true if it is one you are 18373 * displaying, else return the result of calling through to the 18374 * super class. 18375 * 18376 * @return boolean If true than the Drawable is being displayed in the 18377 * view; else false and it is not allowed to animate. 18378 * 18379 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 18380 * @see #drawableStateChanged() 18381 */ 18382 @CallSuper 18383 protected boolean verifyDrawable(@NonNull Drawable who) { 18384 // Avoid verifying the scroll bar drawable so that we don't end up in 18385 // an invalidation loop. This effectively prevents the scroll bar 18386 // drawable from triggering invalidations and scheduling runnables. 18387 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); 18388 } 18389 18390 /** 18391 * This function is called whenever the state of the view changes in such 18392 * a way that it impacts the state of drawables being shown. 18393 * <p> 18394 * If the View has a StateListAnimator, it will also be called to run necessary state 18395 * change animations. 18396 * <p> 18397 * Be sure to call through to the superclass when overriding this function. 18398 * 18399 * @see Drawable#setState(int[]) 18400 */ 18401 @CallSuper 18402 protected void drawableStateChanged() { 18403 final int[] state = getDrawableState(); 18404 boolean changed = false; 18405 18406 final Drawable bg = mBackground; 18407 if (bg != null && bg.isStateful()) { 18408 changed |= bg.setState(state); 18409 } 18410 18411 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 18412 if (fg != null && fg.isStateful()) { 18413 changed |= fg.setState(state); 18414 } 18415 18416 if (mScrollCache != null) { 18417 final Drawable scrollBar = mScrollCache.scrollBar; 18418 if (scrollBar != null && scrollBar.isStateful()) { 18419 changed |= scrollBar.setState(state) 18420 && mScrollCache.state != ScrollabilityCache.OFF; 18421 } 18422 } 18423 18424 if (mStateListAnimator != null) { 18425 mStateListAnimator.setState(state); 18426 } 18427 18428 if (changed) { 18429 invalidate(); 18430 } 18431 } 18432 18433 /** 18434 * This function is called whenever the view hotspot changes and needs to 18435 * be propagated to drawables or child views managed by the view. 18436 * <p> 18437 * Dispatching to child views is handled by 18438 * {@link #dispatchDrawableHotspotChanged(float, float)}. 18439 * <p> 18440 * Be sure to call through to the superclass when overriding this function. 18441 * 18442 * @param x hotspot x coordinate 18443 * @param y hotspot y coordinate 18444 */ 18445 @CallSuper 18446 public void drawableHotspotChanged(float x, float y) { 18447 if (mBackground != null) { 18448 mBackground.setHotspot(x, y); 18449 } 18450 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18451 mForegroundInfo.mDrawable.setHotspot(x, y); 18452 } 18453 18454 dispatchDrawableHotspotChanged(x, y); 18455 } 18456 18457 /** 18458 * Dispatches drawableHotspotChanged to all of this View's children. 18459 * 18460 * @param x hotspot x coordinate 18461 * @param y hotspot y coordinate 18462 * @see #drawableHotspotChanged(float, float) 18463 */ 18464 public void dispatchDrawableHotspotChanged(float x, float y) { 18465 } 18466 18467 /** 18468 * Call this to force a view to update its drawable state. This will cause 18469 * drawableStateChanged to be called on this view. Views that are interested 18470 * in the new state should call getDrawableState. 18471 * 18472 * @see #drawableStateChanged 18473 * @see #getDrawableState 18474 */ 18475 public void refreshDrawableState() { 18476 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 18477 drawableStateChanged(); 18478 18479 ViewParent parent = mParent; 18480 if (parent != null) { 18481 parent.childDrawableStateChanged(this); 18482 } 18483 } 18484 18485 /** 18486 * Return an array of resource IDs of the drawable states representing the 18487 * current state of the view. 18488 * 18489 * @return The current drawable state 18490 * 18491 * @see Drawable#setState(int[]) 18492 * @see #drawableStateChanged() 18493 * @see #onCreateDrawableState(int) 18494 */ 18495 public final int[] getDrawableState() { 18496 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 18497 return mDrawableState; 18498 } else { 18499 mDrawableState = onCreateDrawableState(0); 18500 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 18501 return mDrawableState; 18502 } 18503 } 18504 18505 /** 18506 * Generate the new {@link android.graphics.drawable.Drawable} state for 18507 * this view. This is called by the view 18508 * system when the cached Drawable state is determined to be invalid. To 18509 * retrieve the current state, you should use {@link #getDrawableState}. 18510 * 18511 * @param extraSpace if non-zero, this is the number of extra entries you 18512 * would like in the returned array in which you can place your own 18513 * states. 18514 * 18515 * @return Returns an array holding the current {@link Drawable} state of 18516 * the view. 18517 * 18518 * @see #mergeDrawableStates(int[], int[]) 18519 */ 18520 protected int[] onCreateDrawableState(int extraSpace) { 18521 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 18522 mParent instanceof View) { 18523 return ((View) mParent).onCreateDrawableState(extraSpace); 18524 } 18525 18526 int[] drawableState; 18527 18528 int privateFlags = mPrivateFlags; 18529 18530 int viewStateIndex = 0; 18531 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 18532 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 18533 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 18534 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 18535 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 18536 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 18537 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 18538 ThreadedRenderer.isAvailable()) { 18539 // This is set if HW acceleration is requested, even if the current 18540 // process doesn't allow it. This is just to allow app preview 18541 // windows to better match their app. 18542 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 18543 } 18544 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 18545 18546 final int privateFlags2 = mPrivateFlags2; 18547 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 18548 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 18549 } 18550 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 18551 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 18552 } 18553 18554 drawableState = StateSet.get(viewStateIndex); 18555 18556 //noinspection ConstantIfStatement 18557 if (false) { 18558 Log.i("View", "drawableStateIndex=" + viewStateIndex); 18559 Log.i("View", toString() 18560 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 18561 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 18562 + " fo=" + hasFocus() 18563 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 18564 + " wf=" + hasWindowFocus() 18565 + ": " + Arrays.toString(drawableState)); 18566 } 18567 18568 if (extraSpace == 0) { 18569 return drawableState; 18570 } 18571 18572 final int[] fullState; 18573 if (drawableState != null) { 18574 fullState = new int[drawableState.length + extraSpace]; 18575 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 18576 } else { 18577 fullState = new int[extraSpace]; 18578 } 18579 18580 return fullState; 18581 } 18582 18583 /** 18584 * Merge your own state values in <var>additionalState</var> into the base 18585 * state values <var>baseState</var> that were returned by 18586 * {@link #onCreateDrawableState(int)}. 18587 * 18588 * @param baseState The base state values returned by 18589 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 18590 * own additional state values. 18591 * 18592 * @param additionalState The additional state values you would like 18593 * added to <var>baseState</var>; this array is not modified. 18594 * 18595 * @return As a convenience, the <var>baseState</var> array you originally 18596 * passed into the function is returned. 18597 * 18598 * @see #onCreateDrawableState(int) 18599 */ 18600 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 18601 final int N = baseState.length; 18602 int i = N - 1; 18603 while (i >= 0 && baseState[i] == 0) { 18604 i--; 18605 } 18606 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 18607 return baseState; 18608 } 18609 18610 /** 18611 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 18612 * on all Drawable objects associated with this view. 18613 * <p> 18614 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 18615 * attached to this view. 18616 */ 18617 @CallSuper 18618 public void jumpDrawablesToCurrentState() { 18619 if (mBackground != null) { 18620 mBackground.jumpToCurrentState(); 18621 } 18622 if (mStateListAnimator != null) { 18623 mStateListAnimator.jumpToCurrentState(); 18624 } 18625 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18626 mForegroundInfo.mDrawable.jumpToCurrentState(); 18627 } 18628 } 18629 18630 /** 18631 * Sets the background color for this view. 18632 * @param color the color of the background 18633 */ 18634 @RemotableViewMethod 18635 public void setBackgroundColor(@ColorInt int color) { 18636 if (mBackground instanceof ColorDrawable) { 18637 ((ColorDrawable) mBackground.mutate()).setColor(color); 18638 computeOpaqueFlags(); 18639 mBackgroundResource = 0; 18640 } else { 18641 setBackground(new ColorDrawable(color)); 18642 } 18643 } 18644 18645 /** 18646 * Set the background to a given resource. The resource should refer to 18647 * a Drawable object or 0 to remove the background. 18648 * @param resid The identifier of the resource. 18649 * 18650 * @attr ref android.R.styleable#View_background 18651 */ 18652 @RemotableViewMethod 18653 public void setBackgroundResource(@DrawableRes int resid) { 18654 if (resid != 0 && resid == mBackgroundResource) { 18655 return; 18656 } 18657 18658 Drawable d = null; 18659 if (resid != 0) { 18660 d = mContext.getDrawable(resid); 18661 } 18662 setBackground(d); 18663 18664 mBackgroundResource = resid; 18665 } 18666 18667 /** 18668 * Set the background to a given Drawable, or remove the background. If the 18669 * background has padding, this View's padding is set to the background's 18670 * padding. However, when a background is removed, this View's padding isn't 18671 * touched. If setting the padding is desired, please use 18672 * {@link #setPadding(int, int, int, int)}. 18673 * 18674 * @param background The Drawable to use as the background, or null to remove the 18675 * background 18676 */ 18677 public void setBackground(Drawable background) { 18678 //noinspection deprecation 18679 setBackgroundDrawable(background); 18680 } 18681 18682 /** 18683 * @deprecated use {@link #setBackground(Drawable)} instead 18684 */ 18685 @Deprecated 18686 public void setBackgroundDrawable(Drawable background) { 18687 computeOpaqueFlags(); 18688 18689 if (background == mBackground) { 18690 return; 18691 } 18692 18693 boolean requestLayout = false; 18694 18695 mBackgroundResource = 0; 18696 18697 /* 18698 * Regardless of whether we're setting a new background or not, we want 18699 * to clear the previous drawable. setVisible first while we still have the callback set. 18700 */ 18701 if (mBackground != null) { 18702 if (isAttachedToWindow()) { 18703 mBackground.setVisible(false, false); 18704 } 18705 mBackground.setCallback(null); 18706 unscheduleDrawable(mBackground); 18707 } 18708 18709 if (background != null) { 18710 Rect padding = sThreadLocal.get(); 18711 if (padding == null) { 18712 padding = new Rect(); 18713 sThreadLocal.set(padding); 18714 } 18715 resetResolvedDrawablesInternal(); 18716 background.setLayoutDirection(getLayoutDirection()); 18717 if (background.getPadding(padding)) { 18718 resetResolvedPaddingInternal(); 18719 switch (background.getLayoutDirection()) { 18720 case LAYOUT_DIRECTION_RTL: 18721 mUserPaddingLeftInitial = padding.right; 18722 mUserPaddingRightInitial = padding.left; 18723 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 18724 break; 18725 case LAYOUT_DIRECTION_LTR: 18726 default: 18727 mUserPaddingLeftInitial = padding.left; 18728 mUserPaddingRightInitial = padding.right; 18729 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 18730 } 18731 mLeftPaddingDefined = false; 18732 mRightPaddingDefined = false; 18733 } 18734 18735 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 18736 // if it has a different minimum size, we should layout again 18737 if (mBackground == null 18738 || mBackground.getMinimumHeight() != background.getMinimumHeight() 18739 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 18740 requestLayout = true; 18741 } 18742 18743 // Set mBackground before we set this as the callback and start making other 18744 // background drawable state change calls. In particular, the setVisible call below 18745 // can result in drawables attempting to start animations or otherwise invalidate, 18746 // which requires the view set as the callback (us) to recognize the drawable as 18747 // belonging to it as per verifyDrawable. 18748 mBackground = background; 18749 if (background.isStateful()) { 18750 background.setState(getDrawableState()); 18751 } 18752 if (isAttachedToWindow()) { 18753 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 18754 } 18755 18756 applyBackgroundTint(); 18757 18758 // Set callback last, since the view may still be initializing. 18759 background.setCallback(this); 18760 18761 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 18762 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 18763 requestLayout = true; 18764 } 18765 } else { 18766 /* Remove the background */ 18767 mBackground = null; 18768 if ((mViewFlags & WILL_NOT_DRAW) != 0 18769 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 18770 mPrivateFlags |= PFLAG_SKIP_DRAW; 18771 } 18772 18773 /* 18774 * When the background is set, we try to apply its padding to this 18775 * View. When the background is removed, we don't touch this View's 18776 * padding. This is noted in the Javadocs. Hence, we don't need to 18777 * requestLayout(), the invalidate() below is sufficient. 18778 */ 18779 18780 // The old background's minimum size could have affected this 18781 // View's layout, so let's requestLayout 18782 requestLayout = true; 18783 } 18784 18785 computeOpaqueFlags(); 18786 18787 if (requestLayout) { 18788 requestLayout(); 18789 } 18790 18791 mBackgroundSizeChanged = true; 18792 invalidate(true); 18793 invalidateOutline(); 18794 } 18795 18796 /** 18797 * Gets the background drawable 18798 * 18799 * @return The drawable used as the background for this view, if any. 18800 * 18801 * @see #setBackground(Drawable) 18802 * 18803 * @attr ref android.R.styleable#View_background 18804 */ 18805 public Drawable getBackground() { 18806 return mBackground; 18807 } 18808 18809 /** 18810 * Applies a tint to the background drawable. Does not modify the current tint 18811 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 18812 * <p> 18813 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 18814 * mutate the drawable and apply the specified tint and tint mode using 18815 * {@link Drawable#setTintList(ColorStateList)}. 18816 * 18817 * @param tint the tint to apply, may be {@code null} to clear tint 18818 * 18819 * @attr ref android.R.styleable#View_backgroundTint 18820 * @see #getBackgroundTintList() 18821 * @see Drawable#setTintList(ColorStateList) 18822 */ 18823 public void setBackgroundTintList(@Nullable ColorStateList tint) { 18824 if (mBackgroundTint == null) { 18825 mBackgroundTint = new TintInfo(); 18826 } 18827 mBackgroundTint.mTintList = tint; 18828 mBackgroundTint.mHasTintList = true; 18829 18830 applyBackgroundTint(); 18831 } 18832 18833 /** 18834 * Return the tint applied to the background drawable, if specified. 18835 * 18836 * @return the tint applied to the background drawable 18837 * @attr ref android.R.styleable#View_backgroundTint 18838 * @see #setBackgroundTintList(ColorStateList) 18839 */ 18840 @Nullable 18841 public ColorStateList getBackgroundTintList() { 18842 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 18843 } 18844 18845 /** 18846 * Specifies the blending mode used to apply the tint specified by 18847 * {@link #setBackgroundTintList(ColorStateList)}} to the background 18848 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 18849 * 18850 * @param tintMode the blending mode used to apply the tint, may be 18851 * {@code null} to clear tint 18852 * @attr ref android.R.styleable#View_backgroundTintMode 18853 * @see #getBackgroundTintMode() 18854 * @see Drawable#setTintMode(PorterDuff.Mode) 18855 */ 18856 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 18857 if (mBackgroundTint == null) { 18858 mBackgroundTint = new TintInfo(); 18859 } 18860 mBackgroundTint.mTintMode = tintMode; 18861 mBackgroundTint.mHasTintMode = true; 18862 18863 applyBackgroundTint(); 18864 } 18865 18866 /** 18867 * Return the blending mode used to apply the tint to the background 18868 * drawable, if specified. 18869 * 18870 * @return the blending mode used to apply the tint to the background 18871 * drawable 18872 * @attr ref android.R.styleable#View_backgroundTintMode 18873 * @see #setBackgroundTintMode(PorterDuff.Mode) 18874 */ 18875 @Nullable 18876 public PorterDuff.Mode getBackgroundTintMode() { 18877 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 18878 } 18879 18880 private void applyBackgroundTint() { 18881 if (mBackground != null && mBackgroundTint != null) { 18882 final TintInfo tintInfo = mBackgroundTint; 18883 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 18884 mBackground = mBackground.mutate(); 18885 18886 if (tintInfo.mHasTintList) { 18887 mBackground.setTintList(tintInfo.mTintList); 18888 } 18889 18890 if (tintInfo.mHasTintMode) { 18891 mBackground.setTintMode(tintInfo.mTintMode); 18892 } 18893 18894 // The drawable (or one of its children) may not have been 18895 // stateful before applying the tint, so let's try again. 18896 if (mBackground.isStateful()) { 18897 mBackground.setState(getDrawableState()); 18898 } 18899 } 18900 } 18901 } 18902 18903 /** 18904 * Returns the drawable used as the foreground of this View. The 18905 * foreground drawable, if non-null, is always drawn on top of the view's content. 18906 * 18907 * @return a Drawable or null if no foreground was set 18908 * 18909 * @see #onDrawForeground(Canvas) 18910 */ 18911 public Drawable getForeground() { 18912 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 18913 } 18914 18915 /** 18916 * Supply a Drawable that is to be rendered on top of all of the content in the view. 18917 * 18918 * @param foreground the Drawable to be drawn on top of the children 18919 * 18920 * @attr ref android.R.styleable#View_foreground 18921 */ 18922 public void setForeground(Drawable foreground) { 18923 if (mForegroundInfo == null) { 18924 if (foreground == null) { 18925 // Nothing to do. 18926 return; 18927 } 18928 mForegroundInfo = new ForegroundInfo(); 18929 } 18930 18931 if (foreground == mForegroundInfo.mDrawable) { 18932 // Nothing to do 18933 return; 18934 } 18935 18936 if (mForegroundInfo.mDrawable != null) { 18937 if (isAttachedToWindow()) { 18938 mForegroundInfo.mDrawable.setVisible(false, false); 18939 } 18940 mForegroundInfo.mDrawable.setCallback(null); 18941 unscheduleDrawable(mForegroundInfo.mDrawable); 18942 } 18943 18944 mForegroundInfo.mDrawable = foreground; 18945 mForegroundInfo.mBoundsChanged = true; 18946 if (foreground != null) { 18947 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 18948 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 18949 } 18950 foreground.setLayoutDirection(getLayoutDirection()); 18951 if (foreground.isStateful()) { 18952 foreground.setState(getDrawableState()); 18953 } 18954 applyForegroundTint(); 18955 if (isAttachedToWindow()) { 18956 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 18957 } 18958 // Set callback last, since the view may still be initializing. 18959 foreground.setCallback(this); 18960 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) { 18961 mPrivateFlags |= PFLAG_SKIP_DRAW; 18962 } 18963 requestLayout(); 18964 invalidate(); 18965 } 18966 18967 /** 18968 * Magic bit used to support features of framework-internal window decor implementation details. 18969 * This used to live exclusively in FrameLayout. 18970 * 18971 * @return true if the foreground should draw inside the padding region or false 18972 * if it should draw inset by the view's padding 18973 * @hide internal use only; only used by FrameLayout and internal screen layouts. 18974 */ 18975 public boolean isForegroundInsidePadding() { 18976 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 18977 } 18978 18979 /** 18980 * Describes how the foreground is positioned. 18981 * 18982 * @return foreground gravity. 18983 * 18984 * @see #setForegroundGravity(int) 18985 * 18986 * @attr ref android.R.styleable#View_foregroundGravity 18987 */ 18988 public int getForegroundGravity() { 18989 return mForegroundInfo != null ? mForegroundInfo.mGravity 18990 : Gravity.START | Gravity.TOP; 18991 } 18992 18993 /** 18994 * Describes how the foreground is positioned. Defaults to START and TOP. 18995 * 18996 * @param gravity see {@link android.view.Gravity} 18997 * 18998 * @see #getForegroundGravity() 18999 * 19000 * @attr ref android.R.styleable#View_foregroundGravity 19001 */ 19002 public void setForegroundGravity(int gravity) { 19003 if (mForegroundInfo == null) { 19004 mForegroundInfo = new ForegroundInfo(); 19005 } 19006 19007 if (mForegroundInfo.mGravity != gravity) { 19008 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 19009 gravity |= Gravity.START; 19010 } 19011 19012 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 19013 gravity |= Gravity.TOP; 19014 } 19015 19016 mForegroundInfo.mGravity = gravity; 19017 requestLayout(); 19018 } 19019 } 19020 19021 /** 19022 * Applies a tint to the foreground drawable. Does not modify the current tint 19023 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19024 * <p> 19025 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 19026 * mutate the drawable and apply the specified tint and tint mode using 19027 * {@link Drawable#setTintList(ColorStateList)}. 19028 * 19029 * @param tint the tint to apply, may be {@code null} to clear tint 19030 * 19031 * @attr ref android.R.styleable#View_foregroundTint 19032 * @see #getForegroundTintList() 19033 * @see Drawable#setTintList(ColorStateList) 19034 */ 19035 public void setForegroundTintList(@Nullable ColorStateList tint) { 19036 if (mForegroundInfo == null) { 19037 mForegroundInfo = new ForegroundInfo(); 19038 } 19039 if (mForegroundInfo.mTintInfo == null) { 19040 mForegroundInfo.mTintInfo = new TintInfo(); 19041 } 19042 mForegroundInfo.mTintInfo.mTintList = tint; 19043 mForegroundInfo.mTintInfo.mHasTintList = true; 19044 19045 applyForegroundTint(); 19046 } 19047 19048 /** 19049 * Return the tint applied to the foreground drawable, if specified. 19050 * 19051 * @return the tint applied to the foreground drawable 19052 * @attr ref android.R.styleable#View_foregroundTint 19053 * @see #setForegroundTintList(ColorStateList) 19054 */ 19055 @Nullable 19056 public ColorStateList getForegroundTintList() { 19057 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19058 ? mForegroundInfo.mTintInfo.mTintList : null; 19059 } 19060 19061 /** 19062 * Specifies the blending mode used to apply the tint specified by 19063 * {@link #setForegroundTintList(ColorStateList)}} to the background 19064 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19065 * 19066 * @param tintMode the blending mode used to apply the tint, may be 19067 * {@code null} to clear tint 19068 * @attr ref android.R.styleable#View_foregroundTintMode 19069 * @see #getForegroundTintMode() 19070 * @see Drawable#setTintMode(PorterDuff.Mode) 19071 */ 19072 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19073 if (mForegroundInfo == null) { 19074 mForegroundInfo = new ForegroundInfo(); 19075 } 19076 if (mForegroundInfo.mTintInfo == null) { 19077 mForegroundInfo.mTintInfo = new TintInfo(); 19078 } 19079 mForegroundInfo.mTintInfo.mTintMode = tintMode; 19080 mForegroundInfo.mTintInfo.mHasTintMode = true; 19081 19082 applyForegroundTint(); 19083 } 19084 19085 /** 19086 * Return the blending mode used to apply the tint to the foreground 19087 * drawable, if specified. 19088 * 19089 * @return the blending mode used to apply the tint to the foreground 19090 * drawable 19091 * @attr ref android.R.styleable#View_foregroundTintMode 19092 * @see #setForegroundTintMode(PorterDuff.Mode) 19093 */ 19094 @Nullable 19095 public PorterDuff.Mode getForegroundTintMode() { 19096 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19097 ? mForegroundInfo.mTintInfo.mTintMode : null; 19098 } 19099 19100 private void applyForegroundTint() { 19101 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 19102 && mForegroundInfo.mTintInfo != null) { 19103 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 19104 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19105 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 19106 19107 if (tintInfo.mHasTintList) { 19108 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 19109 } 19110 19111 if (tintInfo.mHasTintMode) { 19112 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 19113 } 19114 19115 // The drawable (or one of its children) may not have been 19116 // stateful before applying the tint, so let's try again. 19117 if (mForegroundInfo.mDrawable.isStateful()) { 19118 mForegroundInfo.mDrawable.setState(getDrawableState()); 19119 } 19120 } 19121 } 19122 } 19123 19124 /** 19125 * Draw any foreground content for this view. 19126 * 19127 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 19128 * drawable or other view-specific decorations. The foreground is drawn on top of the 19129 * primary view content.</p> 19130 * 19131 * @param canvas canvas to draw into 19132 */ 19133 public void onDrawForeground(Canvas canvas) { 19134 onDrawScrollIndicators(canvas); 19135 onDrawScrollBars(canvas); 19136 19137 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19138 if (foreground != null) { 19139 if (mForegroundInfo.mBoundsChanged) { 19140 mForegroundInfo.mBoundsChanged = false; 19141 final Rect selfBounds = mForegroundInfo.mSelfBounds; 19142 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 19143 19144 if (mForegroundInfo.mInsidePadding) { 19145 selfBounds.set(0, 0, getWidth(), getHeight()); 19146 } else { 19147 selfBounds.set(getPaddingLeft(), getPaddingTop(), 19148 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 19149 } 19150 19151 final int ld = getLayoutDirection(); 19152 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 19153 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 19154 foreground.setBounds(overlayBounds); 19155 } 19156 19157 foreground.draw(canvas); 19158 } 19159 } 19160 19161 /** 19162 * Sets the padding. The view may add on the space required to display 19163 * the scrollbars, depending on the style and visibility of the scrollbars. 19164 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 19165 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 19166 * from the values set in this call. 19167 * 19168 * @attr ref android.R.styleable#View_padding 19169 * @attr ref android.R.styleable#View_paddingBottom 19170 * @attr ref android.R.styleable#View_paddingLeft 19171 * @attr ref android.R.styleable#View_paddingRight 19172 * @attr ref android.R.styleable#View_paddingTop 19173 * @param left the left padding in pixels 19174 * @param top the top padding in pixels 19175 * @param right the right padding in pixels 19176 * @param bottom the bottom padding in pixels 19177 */ 19178 public void setPadding(int left, int top, int right, int bottom) { 19179 resetResolvedPaddingInternal(); 19180 19181 mUserPaddingStart = UNDEFINED_PADDING; 19182 mUserPaddingEnd = UNDEFINED_PADDING; 19183 19184 mUserPaddingLeftInitial = left; 19185 mUserPaddingRightInitial = right; 19186 19187 mLeftPaddingDefined = true; 19188 mRightPaddingDefined = true; 19189 19190 internalSetPadding(left, top, right, bottom); 19191 } 19192 19193 /** 19194 * @hide 19195 */ 19196 protected void internalSetPadding(int left, int top, int right, int bottom) { 19197 mUserPaddingLeft = left; 19198 mUserPaddingRight = right; 19199 mUserPaddingBottom = bottom; 19200 19201 final int viewFlags = mViewFlags; 19202 boolean changed = false; 19203 19204 // Common case is there are no scroll bars. 19205 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 19206 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 19207 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 19208 ? 0 : getVerticalScrollbarWidth(); 19209 switch (mVerticalScrollbarPosition) { 19210 case SCROLLBAR_POSITION_DEFAULT: 19211 if (isLayoutRtl()) { 19212 left += offset; 19213 } else { 19214 right += offset; 19215 } 19216 break; 19217 case SCROLLBAR_POSITION_RIGHT: 19218 right += offset; 19219 break; 19220 case SCROLLBAR_POSITION_LEFT: 19221 left += offset; 19222 break; 19223 } 19224 } 19225 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 19226 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 19227 ? 0 : getHorizontalScrollbarHeight(); 19228 } 19229 } 19230 19231 if (mPaddingLeft != left) { 19232 changed = true; 19233 mPaddingLeft = left; 19234 } 19235 if (mPaddingTop != top) { 19236 changed = true; 19237 mPaddingTop = top; 19238 } 19239 if (mPaddingRight != right) { 19240 changed = true; 19241 mPaddingRight = right; 19242 } 19243 if (mPaddingBottom != bottom) { 19244 changed = true; 19245 mPaddingBottom = bottom; 19246 } 19247 19248 if (changed) { 19249 requestLayout(); 19250 invalidateOutline(); 19251 } 19252 } 19253 19254 /** 19255 * Sets the relative padding. The view may add on the space required to display 19256 * the scrollbars, depending on the style and visibility of the scrollbars. 19257 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 19258 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 19259 * from the values set in this call. 19260 * 19261 * @attr ref android.R.styleable#View_padding 19262 * @attr ref android.R.styleable#View_paddingBottom 19263 * @attr ref android.R.styleable#View_paddingStart 19264 * @attr ref android.R.styleable#View_paddingEnd 19265 * @attr ref android.R.styleable#View_paddingTop 19266 * @param start the start padding in pixels 19267 * @param top the top padding in pixels 19268 * @param end the end padding in pixels 19269 * @param bottom the bottom padding in pixels 19270 */ 19271 public void setPaddingRelative(int start, int top, int end, int bottom) { 19272 resetResolvedPaddingInternal(); 19273 19274 mUserPaddingStart = start; 19275 mUserPaddingEnd = end; 19276 mLeftPaddingDefined = true; 19277 mRightPaddingDefined = true; 19278 19279 switch(getLayoutDirection()) { 19280 case LAYOUT_DIRECTION_RTL: 19281 mUserPaddingLeftInitial = end; 19282 mUserPaddingRightInitial = start; 19283 internalSetPadding(end, top, start, bottom); 19284 break; 19285 case LAYOUT_DIRECTION_LTR: 19286 default: 19287 mUserPaddingLeftInitial = start; 19288 mUserPaddingRightInitial = end; 19289 internalSetPadding(start, top, end, bottom); 19290 } 19291 } 19292 19293 /** 19294 * Returns the top padding of this view. 19295 * 19296 * @return the top padding in pixels 19297 */ 19298 public int getPaddingTop() { 19299 return mPaddingTop; 19300 } 19301 19302 /** 19303 * Returns the bottom padding of this view. If there are inset and enabled 19304 * scrollbars, this value may include the space required to display the 19305 * scrollbars as well. 19306 * 19307 * @return the bottom padding in pixels 19308 */ 19309 public int getPaddingBottom() { 19310 return mPaddingBottom; 19311 } 19312 19313 /** 19314 * Returns the left padding of this view. If there are inset and enabled 19315 * scrollbars, this value may include the space required to display the 19316 * scrollbars as well. 19317 * 19318 * @return the left padding in pixels 19319 */ 19320 public int getPaddingLeft() { 19321 if (!isPaddingResolved()) { 19322 resolvePadding(); 19323 } 19324 return mPaddingLeft; 19325 } 19326 19327 /** 19328 * Returns the start padding of this view depending on its resolved layout direction. 19329 * If there are inset and enabled scrollbars, this value may include the space 19330 * required to display the scrollbars as well. 19331 * 19332 * @return the start padding in pixels 19333 */ 19334 public int getPaddingStart() { 19335 if (!isPaddingResolved()) { 19336 resolvePadding(); 19337 } 19338 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19339 mPaddingRight : mPaddingLeft; 19340 } 19341 19342 /** 19343 * Returns the right padding of this view. If there are inset and enabled 19344 * scrollbars, this value may include the space required to display the 19345 * scrollbars as well. 19346 * 19347 * @return the right padding in pixels 19348 */ 19349 public int getPaddingRight() { 19350 if (!isPaddingResolved()) { 19351 resolvePadding(); 19352 } 19353 return mPaddingRight; 19354 } 19355 19356 /** 19357 * Returns the end padding of this view depending on its resolved layout direction. 19358 * If there are inset and enabled scrollbars, this value may include the space 19359 * required to display the scrollbars as well. 19360 * 19361 * @return the end padding in pixels 19362 */ 19363 public int getPaddingEnd() { 19364 if (!isPaddingResolved()) { 19365 resolvePadding(); 19366 } 19367 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19368 mPaddingLeft : mPaddingRight; 19369 } 19370 19371 /** 19372 * Return if the padding has been set through relative values 19373 * {@link #setPaddingRelative(int, int, int, int)} or through 19374 * @attr ref android.R.styleable#View_paddingStart or 19375 * @attr ref android.R.styleable#View_paddingEnd 19376 * 19377 * @return true if the padding is relative or false if it is not. 19378 */ 19379 public boolean isPaddingRelative() { 19380 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 19381 } 19382 19383 Insets computeOpticalInsets() { 19384 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 19385 } 19386 19387 /** 19388 * @hide 19389 */ 19390 public void resetPaddingToInitialValues() { 19391 if (isRtlCompatibilityMode()) { 19392 mPaddingLeft = mUserPaddingLeftInitial; 19393 mPaddingRight = mUserPaddingRightInitial; 19394 return; 19395 } 19396 if (isLayoutRtl()) { 19397 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 19398 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 19399 } else { 19400 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 19401 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 19402 } 19403 } 19404 19405 /** 19406 * @hide 19407 */ 19408 public Insets getOpticalInsets() { 19409 if (mLayoutInsets == null) { 19410 mLayoutInsets = computeOpticalInsets(); 19411 } 19412 return mLayoutInsets; 19413 } 19414 19415 /** 19416 * Set this view's optical insets. 19417 * 19418 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 19419 * property. Views that compute their own optical insets should call it as part of measurement. 19420 * This method does not request layout. If you are setting optical insets outside of 19421 * measure/layout itself you will want to call requestLayout() yourself. 19422 * </p> 19423 * @hide 19424 */ 19425 public void setOpticalInsets(Insets insets) { 19426 mLayoutInsets = insets; 19427 } 19428 19429 /** 19430 * Changes the selection state of this view. A view can be selected or not. 19431 * Note that selection is not the same as focus. Views are typically 19432 * selected in the context of an AdapterView like ListView or GridView; 19433 * the selected view is the view that is highlighted. 19434 * 19435 * @param selected true if the view must be selected, false otherwise 19436 */ 19437 public void setSelected(boolean selected) { 19438 //noinspection DoubleNegation 19439 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 19440 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 19441 if (!selected) resetPressedState(); 19442 invalidate(true); 19443 refreshDrawableState(); 19444 dispatchSetSelected(selected); 19445 if (selected) { 19446 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 19447 } else { 19448 notifyViewAccessibilityStateChangedIfNeeded( 19449 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 19450 } 19451 } 19452 } 19453 19454 /** 19455 * Dispatch setSelected to all of this View's children. 19456 * 19457 * @see #setSelected(boolean) 19458 * 19459 * @param selected The new selected state 19460 */ 19461 protected void dispatchSetSelected(boolean selected) { 19462 } 19463 19464 /** 19465 * Indicates the selection state of this view. 19466 * 19467 * @return true if the view is selected, false otherwise 19468 */ 19469 @ViewDebug.ExportedProperty 19470 public boolean isSelected() { 19471 return (mPrivateFlags & PFLAG_SELECTED) != 0; 19472 } 19473 19474 /** 19475 * Changes the activated state of this view. A view can be activated or not. 19476 * Note that activation is not the same as selection. Selection is 19477 * a transient property, representing the view (hierarchy) the user is 19478 * currently interacting with. Activation is a longer-term state that the 19479 * user can move views in and out of. For example, in a list view with 19480 * single or multiple selection enabled, the views in the current selection 19481 * set are activated. (Um, yeah, we are deeply sorry about the terminology 19482 * here.) The activated state is propagated down to children of the view it 19483 * is set on. 19484 * 19485 * @param activated true if the view must be activated, false otherwise 19486 */ 19487 public void setActivated(boolean activated) { 19488 //noinspection DoubleNegation 19489 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 19490 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 19491 invalidate(true); 19492 refreshDrawableState(); 19493 dispatchSetActivated(activated); 19494 } 19495 } 19496 19497 /** 19498 * Dispatch setActivated to all of this View's children. 19499 * 19500 * @see #setActivated(boolean) 19501 * 19502 * @param activated The new activated state 19503 */ 19504 protected void dispatchSetActivated(boolean activated) { 19505 } 19506 19507 /** 19508 * Indicates the activation state of this view. 19509 * 19510 * @return true if the view is activated, false otherwise 19511 */ 19512 @ViewDebug.ExportedProperty 19513 public boolean isActivated() { 19514 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 19515 } 19516 19517 /** 19518 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 19519 * observer can be used to get notifications when global events, like 19520 * layout, happen. 19521 * 19522 * The returned ViewTreeObserver observer is not guaranteed to remain 19523 * valid for the lifetime of this View. If the caller of this method keeps 19524 * a long-lived reference to ViewTreeObserver, it should always check for 19525 * the return value of {@link ViewTreeObserver#isAlive()}. 19526 * 19527 * @return The ViewTreeObserver for this view's hierarchy. 19528 */ 19529 public ViewTreeObserver getViewTreeObserver() { 19530 if (mAttachInfo != null) { 19531 return mAttachInfo.mTreeObserver; 19532 } 19533 if (mFloatingTreeObserver == null) { 19534 mFloatingTreeObserver = new ViewTreeObserver(mContext); 19535 } 19536 return mFloatingTreeObserver; 19537 } 19538 19539 /** 19540 * <p>Finds the topmost view in the current view hierarchy.</p> 19541 * 19542 * @return the topmost view containing this view 19543 */ 19544 public View getRootView() { 19545 if (mAttachInfo != null) { 19546 final View v = mAttachInfo.mRootView; 19547 if (v != null) { 19548 return v; 19549 } 19550 } 19551 19552 View parent = this; 19553 19554 while (parent.mParent != null && parent.mParent instanceof View) { 19555 parent = (View) parent.mParent; 19556 } 19557 19558 return parent; 19559 } 19560 19561 /** 19562 * Transforms a motion event from view-local coordinates to on-screen 19563 * coordinates. 19564 * 19565 * @param ev the view-local motion event 19566 * @return false if the transformation could not be applied 19567 * @hide 19568 */ 19569 public boolean toGlobalMotionEvent(MotionEvent ev) { 19570 final AttachInfo info = mAttachInfo; 19571 if (info == null) { 19572 return false; 19573 } 19574 19575 final Matrix m = info.mTmpMatrix; 19576 m.set(Matrix.IDENTITY_MATRIX); 19577 transformMatrixToGlobal(m); 19578 ev.transform(m); 19579 return true; 19580 } 19581 19582 /** 19583 * Transforms a motion event from on-screen coordinates to view-local 19584 * coordinates. 19585 * 19586 * @param ev the on-screen motion event 19587 * @return false if the transformation could not be applied 19588 * @hide 19589 */ 19590 public boolean toLocalMotionEvent(MotionEvent ev) { 19591 final AttachInfo info = mAttachInfo; 19592 if (info == null) { 19593 return false; 19594 } 19595 19596 final Matrix m = info.mTmpMatrix; 19597 m.set(Matrix.IDENTITY_MATRIX); 19598 transformMatrixToLocal(m); 19599 ev.transform(m); 19600 return true; 19601 } 19602 19603 /** 19604 * Modifies the input matrix such that it maps view-local coordinates to 19605 * on-screen coordinates. 19606 * 19607 * @param m input matrix to modify 19608 * @hide 19609 */ 19610 public void transformMatrixToGlobal(Matrix m) { 19611 final ViewParent parent = mParent; 19612 if (parent instanceof View) { 19613 final View vp = (View) parent; 19614 vp.transformMatrixToGlobal(m); 19615 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 19616 } else if (parent instanceof ViewRootImpl) { 19617 final ViewRootImpl vr = (ViewRootImpl) parent; 19618 vr.transformMatrixToGlobal(m); 19619 m.preTranslate(0, -vr.mCurScrollY); 19620 } 19621 19622 m.preTranslate(mLeft, mTop); 19623 19624 if (!hasIdentityMatrix()) { 19625 m.preConcat(getMatrix()); 19626 } 19627 } 19628 19629 /** 19630 * Modifies the input matrix such that it maps on-screen coordinates to 19631 * view-local coordinates. 19632 * 19633 * @param m input matrix to modify 19634 * @hide 19635 */ 19636 public void transformMatrixToLocal(Matrix m) { 19637 final ViewParent parent = mParent; 19638 if (parent instanceof View) { 19639 final View vp = (View) parent; 19640 vp.transformMatrixToLocal(m); 19641 m.postTranslate(vp.mScrollX, vp.mScrollY); 19642 } else if (parent instanceof ViewRootImpl) { 19643 final ViewRootImpl vr = (ViewRootImpl) parent; 19644 vr.transformMatrixToLocal(m); 19645 m.postTranslate(0, vr.mCurScrollY); 19646 } 19647 19648 m.postTranslate(-mLeft, -mTop); 19649 19650 if (!hasIdentityMatrix()) { 19651 m.postConcat(getInverseMatrix()); 19652 } 19653 } 19654 19655 /** 19656 * @hide 19657 */ 19658 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 19659 @ViewDebug.IntToString(from = 0, to = "x"), 19660 @ViewDebug.IntToString(from = 1, to = "y") 19661 }) 19662 public int[] getLocationOnScreen() { 19663 int[] location = new int[2]; 19664 getLocationOnScreen(location); 19665 return location; 19666 } 19667 19668 /** 19669 * <p>Computes the coordinates of this view on the screen. The argument 19670 * must be an array of two integers. After the method returns, the array 19671 * contains the x and y location in that order.</p> 19672 * 19673 * @param outLocation an array of two integers in which to hold the coordinates 19674 */ 19675 public void getLocationOnScreen(@Size(2) int[] outLocation) { 19676 getLocationInWindow(outLocation); 19677 19678 final AttachInfo info = mAttachInfo; 19679 if (info != null) { 19680 outLocation[0] += info.mWindowLeft; 19681 outLocation[1] += info.mWindowTop; 19682 } 19683 } 19684 19685 /** 19686 * <p>Computes the coordinates of this view in its window. The argument 19687 * must be an array of two integers. After the method returns, the array 19688 * contains the x and y location in that order.</p> 19689 * 19690 * @param outLocation an array of two integers in which to hold the coordinates 19691 */ 19692 public void getLocationInWindow(@Size(2) int[] outLocation) { 19693 if (outLocation == null || outLocation.length < 2) { 19694 throw new IllegalArgumentException("outLocation must be an array of two integers"); 19695 } 19696 19697 outLocation[0] = 0; 19698 outLocation[1] = 0; 19699 19700 transformFromViewToWindowSpace(outLocation); 19701 } 19702 19703 /** @hide */ 19704 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 19705 if (inOutLocation == null || inOutLocation.length < 2) { 19706 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 19707 } 19708 19709 if (mAttachInfo == null) { 19710 // When the view is not attached to a window, this method does not make sense 19711 inOutLocation[0] = inOutLocation[1] = 0; 19712 return; 19713 } 19714 19715 float position[] = mAttachInfo.mTmpTransformLocation; 19716 position[0] = inOutLocation[0]; 19717 position[1] = inOutLocation[1]; 19718 19719 if (!hasIdentityMatrix()) { 19720 getMatrix().mapPoints(position); 19721 } 19722 19723 position[0] += mLeft; 19724 position[1] += mTop; 19725 19726 ViewParent viewParent = mParent; 19727 while (viewParent instanceof View) { 19728 final View view = (View) viewParent; 19729 19730 position[0] -= view.mScrollX; 19731 position[1] -= view.mScrollY; 19732 19733 if (!view.hasIdentityMatrix()) { 19734 view.getMatrix().mapPoints(position); 19735 } 19736 19737 position[0] += view.mLeft; 19738 position[1] += view.mTop; 19739 19740 viewParent = view.mParent; 19741 } 19742 19743 if (viewParent instanceof ViewRootImpl) { 19744 // *cough* 19745 final ViewRootImpl vr = (ViewRootImpl) viewParent; 19746 position[1] -= vr.mCurScrollY; 19747 } 19748 19749 inOutLocation[0] = Math.round(position[0]); 19750 inOutLocation[1] = Math.round(position[1]); 19751 } 19752 19753 /** 19754 * {@hide} 19755 * @param id the id of the view to be found 19756 * @return the view of the specified id, null if cannot be found 19757 */ 19758 protected View findViewTraversal(@IdRes int id) { 19759 if (id == mID) { 19760 return this; 19761 } 19762 return null; 19763 } 19764 19765 /** 19766 * {@hide} 19767 * @param tag the tag of the view to be found 19768 * @return the view of specified tag, null if cannot be found 19769 */ 19770 protected View findViewWithTagTraversal(Object tag) { 19771 if (tag != null && tag.equals(mTag)) { 19772 return this; 19773 } 19774 return null; 19775 } 19776 19777 /** 19778 * {@hide} 19779 * @param predicate The predicate to evaluate. 19780 * @param childToSkip If not null, ignores this child during the recursive traversal. 19781 * @return The first view that matches the predicate or null. 19782 */ 19783 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 19784 if (predicate.apply(this)) { 19785 return this; 19786 } 19787 return null; 19788 } 19789 19790 /** 19791 * Look for a child view with the given id. If this view has the given 19792 * id, return this view. 19793 * 19794 * @param id The id to search for. 19795 * @return The view that has the given id in the hierarchy or null 19796 */ 19797 @Nullable 19798 public final View findViewById(@IdRes int id) { 19799 if (id < 0) { 19800 return null; 19801 } 19802 return findViewTraversal(id); 19803 } 19804 19805 /** 19806 * Finds a view by its unuque and stable accessibility id. 19807 * 19808 * @param accessibilityId The searched accessibility id. 19809 * @return The found view. 19810 */ 19811 final View findViewByAccessibilityId(int accessibilityId) { 19812 if (accessibilityId < 0) { 19813 return null; 19814 } 19815 View view = findViewByAccessibilityIdTraversal(accessibilityId); 19816 if (view != null) { 19817 return view.includeForAccessibility() ? view : null; 19818 } 19819 return null; 19820 } 19821 19822 /** 19823 * Performs the traversal to find a view by its unuque and stable accessibility id. 19824 * 19825 * <strong>Note:</strong>This method does not stop at the root namespace 19826 * boundary since the user can touch the screen at an arbitrary location 19827 * potentially crossing the root namespace bounday which will send an 19828 * accessibility event to accessibility services and they should be able 19829 * to obtain the event source. Also accessibility ids are guaranteed to be 19830 * unique in the window. 19831 * 19832 * @param accessibilityId The accessibility id. 19833 * @return The found view. 19834 * 19835 * @hide 19836 */ 19837 public View findViewByAccessibilityIdTraversal(int accessibilityId) { 19838 if (getAccessibilityViewId() == accessibilityId) { 19839 return this; 19840 } 19841 return null; 19842 } 19843 19844 /** 19845 * Look for a child view with the given tag. If this view has the given 19846 * tag, return this view. 19847 * 19848 * @param tag The tag to search for, using "tag.equals(getTag())". 19849 * @return The View that has the given tag in the hierarchy or null 19850 */ 19851 public final View findViewWithTag(Object tag) { 19852 if (tag == null) { 19853 return null; 19854 } 19855 return findViewWithTagTraversal(tag); 19856 } 19857 19858 /** 19859 * {@hide} 19860 * Look for a child view that matches the specified predicate. 19861 * If this view matches the predicate, return this view. 19862 * 19863 * @param predicate The predicate to evaluate. 19864 * @return The first view that matches the predicate or null. 19865 */ 19866 public final View findViewByPredicate(Predicate<View> predicate) { 19867 return findViewByPredicateTraversal(predicate, null); 19868 } 19869 19870 /** 19871 * {@hide} 19872 * Look for a child view that matches the specified predicate, 19873 * starting with the specified view and its descendents and then 19874 * recusively searching the ancestors and siblings of that view 19875 * until this view is reached. 19876 * 19877 * This method is useful in cases where the predicate does not match 19878 * a single unique view (perhaps multiple views use the same id) 19879 * and we are trying to find the view that is "closest" in scope to the 19880 * starting view. 19881 * 19882 * @param start The view to start from. 19883 * @param predicate The predicate to evaluate. 19884 * @return The first view that matches the predicate or null. 19885 */ 19886 public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) { 19887 View childToSkip = null; 19888 for (;;) { 19889 View view = start.findViewByPredicateTraversal(predicate, childToSkip); 19890 if (view != null || start == this) { 19891 return view; 19892 } 19893 19894 ViewParent parent = start.getParent(); 19895 if (parent == null || !(parent instanceof View)) { 19896 return null; 19897 } 19898 19899 childToSkip = start; 19900 start = (View) parent; 19901 } 19902 } 19903 19904 /** 19905 * Sets the identifier for this view. The identifier does not have to be 19906 * unique in this view's hierarchy. The identifier should be a positive 19907 * number. 19908 * 19909 * @see #NO_ID 19910 * @see #getId() 19911 * @see #findViewById(int) 19912 * 19913 * @param id a number used to identify the view 19914 * 19915 * @attr ref android.R.styleable#View_id 19916 */ 19917 public void setId(@IdRes int id) { 19918 mID = id; 19919 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 19920 mID = generateViewId(); 19921 } 19922 } 19923 19924 /** 19925 * {@hide} 19926 * 19927 * @param isRoot true if the view belongs to the root namespace, false 19928 * otherwise 19929 */ 19930 public void setIsRootNamespace(boolean isRoot) { 19931 if (isRoot) { 19932 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 19933 } else { 19934 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 19935 } 19936 } 19937 19938 /** 19939 * {@hide} 19940 * 19941 * @return true if the view belongs to the root namespace, false otherwise 19942 */ 19943 public boolean isRootNamespace() { 19944 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 19945 } 19946 19947 /** 19948 * Returns this view's identifier. 19949 * 19950 * @return a positive integer used to identify the view or {@link #NO_ID} 19951 * if the view has no ID 19952 * 19953 * @see #setId(int) 19954 * @see #findViewById(int) 19955 * @attr ref android.R.styleable#View_id 19956 */ 19957 @IdRes 19958 @ViewDebug.CapturedViewProperty 19959 public int getId() { 19960 return mID; 19961 } 19962 19963 /** 19964 * Returns this view's tag. 19965 * 19966 * @return the Object stored in this view as a tag, or {@code null} if not 19967 * set 19968 * 19969 * @see #setTag(Object) 19970 * @see #getTag(int) 19971 */ 19972 @ViewDebug.ExportedProperty 19973 public Object getTag() { 19974 return mTag; 19975 } 19976 19977 /** 19978 * Sets the tag associated with this view. A tag can be used to mark 19979 * a view in its hierarchy and does not have to be unique within the 19980 * hierarchy. Tags can also be used to store data within a view without 19981 * resorting to another data structure. 19982 * 19983 * @param tag an Object to tag the view with 19984 * 19985 * @see #getTag() 19986 * @see #setTag(int, Object) 19987 */ 19988 public void setTag(final Object tag) { 19989 mTag = tag; 19990 } 19991 19992 /** 19993 * Returns the tag associated with this view and the specified key. 19994 * 19995 * @param key The key identifying the tag 19996 * 19997 * @return the Object stored in this view as a tag, or {@code null} if not 19998 * set 19999 * 20000 * @see #setTag(int, Object) 20001 * @see #getTag() 20002 */ 20003 public Object getTag(int key) { 20004 if (mKeyedTags != null) return mKeyedTags.get(key); 20005 return null; 20006 } 20007 20008 /** 20009 * Sets a tag associated with this view and a key. A tag can be used 20010 * to mark a view in its hierarchy and does not have to be unique within 20011 * the hierarchy. Tags can also be used to store data within a view 20012 * without resorting to another data structure. 20013 * 20014 * The specified key should be an id declared in the resources of the 20015 * application to ensure it is unique (see the <a 20016 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 20017 * Keys identified as belonging to 20018 * the Android framework or not associated with any package will cause 20019 * an {@link IllegalArgumentException} to be thrown. 20020 * 20021 * @param key The key identifying the tag 20022 * @param tag An Object to tag the view with 20023 * 20024 * @throws IllegalArgumentException If they specified key is not valid 20025 * 20026 * @see #setTag(Object) 20027 * @see #getTag(int) 20028 */ 20029 public void setTag(int key, final Object tag) { 20030 // If the package id is 0x00 or 0x01, it's either an undefined package 20031 // or a framework id 20032 if ((key >>> 24) < 2) { 20033 throw new IllegalArgumentException("The key must be an application-specific " 20034 + "resource id."); 20035 } 20036 20037 setKeyedTag(key, tag); 20038 } 20039 20040 /** 20041 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 20042 * framework id. 20043 * 20044 * @hide 20045 */ 20046 public void setTagInternal(int key, Object tag) { 20047 if ((key >>> 24) != 0x1) { 20048 throw new IllegalArgumentException("The key must be a framework-specific " 20049 + "resource id."); 20050 } 20051 20052 setKeyedTag(key, tag); 20053 } 20054 20055 private void setKeyedTag(int key, Object tag) { 20056 if (mKeyedTags == null) { 20057 mKeyedTags = new SparseArray<Object>(2); 20058 } 20059 20060 mKeyedTags.put(key, tag); 20061 } 20062 20063 /** 20064 * Prints information about this view in the log output, with the tag 20065 * {@link #VIEW_LOG_TAG}. 20066 * 20067 * @hide 20068 */ 20069 public void debug() { 20070 debug(0); 20071 } 20072 20073 /** 20074 * Prints information about this view in the log output, with the tag 20075 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 20076 * indentation defined by the <code>depth</code>. 20077 * 20078 * @param depth the indentation level 20079 * 20080 * @hide 20081 */ 20082 protected void debug(int depth) { 20083 String output = debugIndent(depth - 1); 20084 20085 output += "+ " + this; 20086 int id = getId(); 20087 if (id != -1) { 20088 output += " (id=" + id + ")"; 20089 } 20090 Object tag = getTag(); 20091 if (tag != null) { 20092 output += " (tag=" + tag + ")"; 20093 } 20094 Log.d(VIEW_LOG_TAG, output); 20095 20096 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 20097 output = debugIndent(depth) + " FOCUSED"; 20098 Log.d(VIEW_LOG_TAG, output); 20099 } 20100 20101 output = debugIndent(depth); 20102 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 20103 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 20104 + "} "; 20105 Log.d(VIEW_LOG_TAG, output); 20106 20107 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 20108 || mPaddingBottom != 0) { 20109 output = debugIndent(depth); 20110 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 20111 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 20112 Log.d(VIEW_LOG_TAG, output); 20113 } 20114 20115 output = debugIndent(depth); 20116 output += "mMeasureWidth=" + mMeasuredWidth + 20117 " mMeasureHeight=" + mMeasuredHeight; 20118 Log.d(VIEW_LOG_TAG, output); 20119 20120 output = debugIndent(depth); 20121 if (mLayoutParams == null) { 20122 output += "BAD! no layout params"; 20123 } else { 20124 output = mLayoutParams.debug(output); 20125 } 20126 Log.d(VIEW_LOG_TAG, output); 20127 20128 output = debugIndent(depth); 20129 output += "flags={"; 20130 output += View.printFlags(mViewFlags); 20131 output += "}"; 20132 Log.d(VIEW_LOG_TAG, output); 20133 20134 output = debugIndent(depth); 20135 output += "privateFlags={"; 20136 output += View.printPrivateFlags(mPrivateFlags); 20137 output += "}"; 20138 Log.d(VIEW_LOG_TAG, output); 20139 } 20140 20141 /** 20142 * Creates a string of whitespaces used for indentation. 20143 * 20144 * @param depth the indentation level 20145 * @return a String containing (depth * 2 + 3) * 2 white spaces 20146 * 20147 * @hide 20148 */ 20149 protected static String debugIndent(int depth) { 20150 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 20151 for (int i = 0; i < (depth * 2) + 3; i++) { 20152 spaces.append(' ').append(' '); 20153 } 20154 return spaces.toString(); 20155 } 20156 20157 /** 20158 * <p>Return the offset of the widget's text baseline from the widget's top 20159 * boundary. If this widget does not support baseline alignment, this 20160 * method returns -1. </p> 20161 * 20162 * @return the offset of the baseline within the widget's bounds or -1 20163 * if baseline alignment is not supported 20164 */ 20165 @ViewDebug.ExportedProperty(category = "layout") 20166 public int getBaseline() { 20167 return -1; 20168 } 20169 20170 /** 20171 * Returns whether the view hierarchy is currently undergoing a layout pass. This 20172 * information is useful to avoid situations such as calling {@link #requestLayout()} during 20173 * a layout pass. 20174 * 20175 * @return whether the view hierarchy is currently undergoing a layout pass 20176 */ 20177 public boolean isInLayout() { 20178 ViewRootImpl viewRoot = getViewRootImpl(); 20179 return (viewRoot != null && viewRoot.isInLayout()); 20180 } 20181 20182 /** 20183 * Call this when something has changed which has invalidated the 20184 * layout of this view. This will schedule a layout pass of the view 20185 * tree. This should not be called while the view hierarchy is currently in a layout 20186 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 20187 * end of the current layout pass (and then layout will run again) or after the current 20188 * frame is drawn and the next layout occurs. 20189 * 20190 * <p>Subclasses which override this method should call the superclass method to 20191 * handle possible request-during-layout errors correctly.</p> 20192 */ 20193 @CallSuper 20194 public void requestLayout() { 20195 if (mMeasureCache != null) mMeasureCache.clear(); 20196 20197 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 20198 // Only trigger request-during-layout logic if this is the view requesting it, 20199 // not the views in its parent hierarchy 20200 ViewRootImpl viewRoot = getViewRootImpl(); 20201 if (viewRoot != null && viewRoot.isInLayout()) { 20202 if (!viewRoot.requestLayoutDuringLayout(this)) { 20203 return; 20204 } 20205 } 20206 mAttachInfo.mViewRequestingLayout = this; 20207 } 20208 20209 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20210 mPrivateFlags |= PFLAG_INVALIDATED; 20211 20212 if (mParent != null && !mParent.isLayoutRequested()) { 20213 mParent.requestLayout(); 20214 } 20215 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 20216 mAttachInfo.mViewRequestingLayout = null; 20217 } 20218 } 20219 20220 /** 20221 * Forces this view to be laid out during the next layout pass. 20222 * This method does not call requestLayout() or forceLayout() 20223 * on the parent. 20224 */ 20225 public void forceLayout() { 20226 if (mMeasureCache != null) mMeasureCache.clear(); 20227 20228 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20229 mPrivateFlags |= PFLAG_INVALIDATED; 20230 } 20231 20232 /** 20233 * <p> 20234 * This is called to find out how big a view should be. The parent 20235 * supplies constraint information in the width and height parameters. 20236 * </p> 20237 * 20238 * <p> 20239 * The actual measurement work of a view is performed in 20240 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 20241 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 20242 * </p> 20243 * 20244 * 20245 * @param widthMeasureSpec Horizontal space requirements as imposed by the 20246 * parent 20247 * @param heightMeasureSpec Vertical space requirements as imposed by the 20248 * parent 20249 * 20250 * @see #onMeasure(int, int) 20251 */ 20252 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 20253 boolean optical = isLayoutModeOptical(this); 20254 if (optical != isLayoutModeOptical(mParent)) { 20255 Insets insets = getOpticalInsets(); 20256 int oWidth = insets.left + insets.right; 20257 int oHeight = insets.top + insets.bottom; 20258 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 20259 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 20260 } 20261 20262 // Suppress sign extension for the low bytes 20263 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 20264 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 20265 20266 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 20267 20268 // Optimize layout by avoiding an extra EXACTLY pass when the view is 20269 // already measured as the correct size. In API 23 and below, this 20270 // extra pass is required to make LinearLayout re-distribute weight. 20271 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 20272 || heightMeasureSpec != mOldHeightMeasureSpec; 20273 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 20274 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 20275 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 20276 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 20277 final boolean needsLayout = specChanged 20278 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 20279 20280 if (forceLayout || needsLayout) { 20281 // first clears the measured dimension flag 20282 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 20283 20284 resolveRtlPropertiesIfNeeded(); 20285 20286 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 20287 if (cacheIndex < 0 || sIgnoreMeasureCache) { 20288 // measure ourselves, this should set the measured dimension flag back 20289 onMeasure(widthMeasureSpec, heightMeasureSpec); 20290 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20291 } else { 20292 long value = mMeasureCache.valueAt(cacheIndex); 20293 // Casting a long to int drops the high 32 bits, no mask needed 20294 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 20295 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20296 } 20297 20298 // flag not set, setMeasuredDimension() was not invoked, we raise 20299 // an exception to warn the developer 20300 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 20301 throw new IllegalStateException("View with id " + getId() + ": " 20302 + getClass().getName() + "#onMeasure() did not set the" 20303 + " measured dimension by calling" 20304 + " setMeasuredDimension()"); 20305 } 20306 20307 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 20308 } 20309 20310 mOldWidthMeasureSpec = widthMeasureSpec; 20311 mOldHeightMeasureSpec = heightMeasureSpec; 20312 20313 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 20314 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 20315 } 20316 20317 /** 20318 * <p> 20319 * Measure the view and its content to determine the measured width and the 20320 * measured height. This method is invoked by {@link #measure(int, int)} and 20321 * should be overridden by subclasses to provide accurate and efficient 20322 * measurement of their contents. 20323 * </p> 20324 * 20325 * <p> 20326 * <strong>CONTRACT:</strong> When overriding this method, you 20327 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 20328 * measured width and height of this view. Failure to do so will trigger an 20329 * <code>IllegalStateException</code>, thrown by 20330 * {@link #measure(int, int)}. Calling the superclass' 20331 * {@link #onMeasure(int, int)} is a valid use. 20332 * </p> 20333 * 20334 * <p> 20335 * The base class implementation of measure defaults to the background size, 20336 * unless a larger size is allowed by the MeasureSpec. Subclasses should 20337 * override {@link #onMeasure(int, int)} to provide better measurements of 20338 * their content. 20339 * </p> 20340 * 20341 * <p> 20342 * If this method is overridden, it is the subclass's responsibility to make 20343 * sure the measured height and width are at least the view's minimum height 20344 * and width ({@link #getSuggestedMinimumHeight()} and 20345 * {@link #getSuggestedMinimumWidth()}). 20346 * </p> 20347 * 20348 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 20349 * The requirements are encoded with 20350 * {@link android.view.View.MeasureSpec}. 20351 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 20352 * The requirements are encoded with 20353 * {@link android.view.View.MeasureSpec}. 20354 * 20355 * @see #getMeasuredWidth() 20356 * @see #getMeasuredHeight() 20357 * @see #setMeasuredDimension(int, int) 20358 * @see #getSuggestedMinimumHeight() 20359 * @see #getSuggestedMinimumWidth() 20360 * @see android.view.View.MeasureSpec#getMode(int) 20361 * @see android.view.View.MeasureSpec#getSize(int) 20362 */ 20363 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 20364 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 20365 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 20366 } 20367 20368 /** 20369 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 20370 * measured width and measured height. Failing to do so will trigger an 20371 * exception at measurement time.</p> 20372 * 20373 * @param measuredWidth The measured width of this view. May be a complex 20374 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20375 * {@link #MEASURED_STATE_TOO_SMALL}. 20376 * @param measuredHeight The measured height of this view. May be a complex 20377 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20378 * {@link #MEASURED_STATE_TOO_SMALL}. 20379 */ 20380 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 20381 boolean optical = isLayoutModeOptical(this); 20382 if (optical != isLayoutModeOptical(mParent)) { 20383 Insets insets = getOpticalInsets(); 20384 int opticalWidth = insets.left + insets.right; 20385 int opticalHeight = insets.top + insets.bottom; 20386 20387 measuredWidth += optical ? opticalWidth : -opticalWidth; 20388 measuredHeight += optical ? opticalHeight : -opticalHeight; 20389 } 20390 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 20391 } 20392 20393 /** 20394 * Sets the measured dimension without extra processing for things like optical bounds. 20395 * Useful for reapplying consistent values that have already been cooked with adjustments 20396 * for optical bounds, etc. such as those from the measurement cache. 20397 * 20398 * @param measuredWidth The measured width of this view. May be a complex 20399 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20400 * {@link #MEASURED_STATE_TOO_SMALL}. 20401 * @param measuredHeight The measured height of this view. May be a complex 20402 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20403 * {@link #MEASURED_STATE_TOO_SMALL}. 20404 */ 20405 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 20406 mMeasuredWidth = measuredWidth; 20407 mMeasuredHeight = measuredHeight; 20408 20409 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 20410 } 20411 20412 /** 20413 * Merge two states as returned by {@link #getMeasuredState()}. 20414 * @param curState The current state as returned from a view or the result 20415 * of combining multiple views. 20416 * @param newState The new view state to combine. 20417 * @return Returns a new integer reflecting the combination of the two 20418 * states. 20419 */ 20420 public static int combineMeasuredStates(int curState, int newState) { 20421 return curState | newState; 20422 } 20423 20424 /** 20425 * Version of {@link #resolveSizeAndState(int, int, int)} 20426 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 20427 */ 20428 public static int resolveSize(int size, int measureSpec) { 20429 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 20430 } 20431 20432 /** 20433 * Utility to reconcile a desired size and state, with constraints imposed 20434 * by a MeasureSpec. Will take the desired size, unless a different size 20435 * is imposed by the constraints. The returned value is a compound integer, 20436 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 20437 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 20438 * resulting size is smaller than the size the view wants to be. 20439 * 20440 * @param size How big the view wants to be. 20441 * @param measureSpec Constraints imposed by the parent. 20442 * @param childMeasuredState Size information bit mask for the view's 20443 * children. 20444 * @return Size information bit mask as defined by 20445 * {@link #MEASURED_SIZE_MASK} and 20446 * {@link #MEASURED_STATE_TOO_SMALL}. 20447 */ 20448 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 20449 final int specMode = MeasureSpec.getMode(measureSpec); 20450 final int specSize = MeasureSpec.getSize(measureSpec); 20451 final int result; 20452 switch (specMode) { 20453 case MeasureSpec.AT_MOST: 20454 if (specSize < size) { 20455 result = specSize | MEASURED_STATE_TOO_SMALL; 20456 } else { 20457 result = size; 20458 } 20459 break; 20460 case MeasureSpec.EXACTLY: 20461 result = specSize; 20462 break; 20463 case MeasureSpec.UNSPECIFIED: 20464 default: 20465 result = size; 20466 } 20467 return result | (childMeasuredState & MEASURED_STATE_MASK); 20468 } 20469 20470 /** 20471 * Utility to return a default size. Uses the supplied size if the 20472 * MeasureSpec imposed no constraints. Will get larger if allowed 20473 * by the MeasureSpec. 20474 * 20475 * @param size Default size for this view 20476 * @param measureSpec Constraints imposed by the parent 20477 * @return The size this view should be. 20478 */ 20479 public static int getDefaultSize(int size, int measureSpec) { 20480 int result = size; 20481 int specMode = MeasureSpec.getMode(measureSpec); 20482 int specSize = MeasureSpec.getSize(measureSpec); 20483 20484 switch (specMode) { 20485 case MeasureSpec.UNSPECIFIED: 20486 result = size; 20487 break; 20488 case MeasureSpec.AT_MOST: 20489 case MeasureSpec.EXACTLY: 20490 result = specSize; 20491 break; 20492 } 20493 return result; 20494 } 20495 20496 /** 20497 * Returns the suggested minimum height that the view should use. This 20498 * returns the maximum of the view's minimum height 20499 * and the background's minimum height 20500 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 20501 * <p> 20502 * When being used in {@link #onMeasure(int, int)}, the caller should still 20503 * ensure the returned height is within the requirements of the parent. 20504 * 20505 * @return The suggested minimum height of the view. 20506 */ 20507 protected int getSuggestedMinimumHeight() { 20508 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 20509 20510 } 20511 20512 /** 20513 * Returns the suggested minimum width that the view should use. This 20514 * returns the maximum of the view's minimum width 20515 * and the background's minimum width 20516 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 20517 * <p> 20518 * When being used in {@link #onMeasure(int, int)}, the caller should still 20519 * ensure the returned width is within the requirements of the parent. 20520 * 20521 * @return The suggested minimum width of the view. 20522 */ 20523 protected int getSuggestedMinimumWidth() { 20524 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 20525 } 20526 20527 /** 20528 * Returns the minimum height of the view. 20529 * 20530 * @return the minimum height the view will try to be, in pixels 20531 * 20532 * @see #setMinimumHeight(int) 20533 * 20534 * @attr ref android.R.styleable#View_minHeight 20535 */ 20536 public int getMinimumHeight() { 20537 return mMinHeight; 20538 } 20539 20540 /** 20541 * Sets the minimum height of the view. It is not guaranteed the view will 20542 * be able to achieve this minimum height (for example, if its parent layout 20543 * constrains it with less available height). 20544 * 20545 * @param minHeight The minimum height the view will try to be, in pixels 20546 * 20547 * @see #getMinimumHeight() 20548 * 20549 * @attr ref android.R.styleable#View_minHeight 20550 */ 20551 @RemotableViewMethod 20552 public void setMinimumHeight(int minHeight) { 20553 mMinHeight = minHeight; 20554 requestLayout(); 20555 } 20556 20557 /** 20558 * Returns the minimum width of the view. 20559 * 20560 * @return the minimum width the view will try to be, in pixels 20561 * 20562 * @see #setMinimumWidth(int) 20563 * 20564 * @attr ref android.R.styleable#View_minWidth 20565 */ 20566 public int getMinimumWidth() { 20567 return mMinWidth; 20568 } 20569 20570 /** 20571 * Sets the minimum width of the view. It is not guaranteed the view will 20572 * be able to achieve this minimum width (for example, if its parent layout 20573 * constrains it with less available width). 20574 * 20575 * @param minWidth The minimum width the view will try to be, in pixels 20576 * 20577 * @see #getMinimumWidth() 20578 * 20579 * @attr ref android.R.styleable#View_minWidth 20580 */ 20581 public void setMinimumWidth(int minWidth) { 20582 mMinWidth = minWidth; 20583 requestLayout(); 20584 20585 } 20586 20587 /** 20588 * Get the animation currently associated with this view. 20589 * 20590 * @return The animation that is currently playing or 20591 * scheduled to play for this view. 20592 */ 20593 public Animation getAnimation() { 20594 return mCurrentAnimation; 20595 } 20596 20597 /** 20598 * Start the specified animation now. 20599 * 20600 * @param animation the animation to start now 20601 */ 20602 public void startAnimation(Animation animation) { 20603 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 20604 setAnimation(animation); 20605 invalidateParentCaches(); 20606 invalidate(true); 20607 } 20608 20609 /** 20610 * Cancels any animations for this view. 20611 */ 20612 public void clearAnimation() { 20613 if (mCurrentAnimation != null) { 20614 mCurrentAnimation.detach(); 20615 } 20616 mCurrentAnimation = null; 20617 invalidateParentIfNeeded(); 20618 } 20619 20620 /** 20621 * Sets the next animation to play for this view. 20622 * If you want the animation to play immediately, use 20623 * {@link #startAnimation(android.view.animation.Animation)} instead. 20624 * This method provides allows fine-grained 20625 * control over the start time and invalidation, but you 20626 * must make sure that 1) the animation has a start time set, and 20627 * 2) the view's parent (which controls animations on its children) 20628 * will be invalidated when the animation is supposed to 20629 * start. 20630 * 20631 * @param animation The next animation, or null. 20632 */ 20633 public void setAnimation(Animation animation) { 20634 mCurrentAnimation = animation; 20635 20636 if (animation != null) { 20637 // If the screen is off assume the animation start time is now instead of 20638 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 20639 // would cause the animation to start when the screen turns back on 20640 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 20641 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 20642 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 20643 } 20644 animation.reset(); 20645 } 20646 } 20647 20648 /** 20649 * Invoked by a parent ViewGroup to notify the start of the animation 20650 * currently associated with this view. If you override this method, 20651 * always call super.onAnimationStart(); 20652 * 20653 * @see #setAnimation(android.view.animation.Animation) 20654 * @see #getAnimation() 20655 */ 20656 @CallSuper 20657 protected void onAnimationStart() { 20658 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 20659 } 20660 20661 /** 20662 * Invoked by a parent ViewGroup to notify the end of the animation 20663 * currently associated with this view. If you override this method, 20664 * always call super.onAnimationEnd(); 20665 * 20666 * @see #setAnimation(android.view.animation.Animation) 20667 * @see #getAnimation() 20668 */ 20669 @CallSuper 20670 protected void onAnimationEnd() { 20671 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 20672 } 20673 20674 /** 20675 * Invoked if there is a Transform that involves alpha. Subclass that can 20676 * draw themselves with the specified alpha should return true, and then 20677 * respect that alpha when their onDraw() is called. If this returns false 20678 * then the view may be redirected to draw into an offscreen buffer to 20679 * fulfill the request, which will look fine, but may be slower than if the 20680 * subclass handles it internally. The default implementation returns false. 20681 * 20682 * @param alpha The alpha (0..255) to apply to the view's drawing 20683 * @return true if the view can draw with the specified alpha. 20684 */ 20685 protected boolean onSetAlpha(int alpha) { 20686 return false; 20687 } 20688 20689 /** 20690 * This is used by the RootView to perform an optimization when 20691 * the view hierarchy contains one or several SurfaceView. 20692 * SurfaceView is always considered transparent, but its children are not, 20693 * therefore all View objects remove themselves from the global transparent 20694 * region (passed as a parameter to this function). 20695 * 20696 * @param region The transparent region for this ViewAncestor (window). 20697 * 20698 * @return Returns true if the effective visibility of the view at this 20699 * point is opaque, regardless of the transparent region; returns false 20700 * if it is possible for underlying windows to be seen behind the view. 20701 * 20702 * {@hide} 20703 */ 20704 public boolean gatherTransparentRegion(Region region) { 20705 final AttachInfo attachInfo = mAttachInfo; 20706 if (region != null && attachInfo != null) { 20707 final int pflags = mPrivateFlags; 20708 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 20709 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 20710 // remove it from the transparent region. 20711 final int[] location = attachInfo.mTransparentLocation; 20712 getLocationInWindow(location); 20713 // When a view has Z value, then it will be better to leave some area below the view 20714 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 20715 // the bottom part needs more offset than the left, top and right parts due to the 20716 // spot light effects. 20717 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 20718 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 20719 location[0] + mRight - mLeft + shadowOffset, 20720 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 20721 } else { 20722 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 20723 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 20724 // the background drawable's non-transparent parts from this transparent region. 20725 applyDrawableToTransparentRegion(mBackground, region); 20726 } 20727 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20728 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 20729 // Similarly, we remove the foreground drawable's non-transparent parts. 20730 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 20731 } 20732 } 20733 } 20734 return true; 20735 } 20736 20737 /** 20738 * Play a sound effect for this view. 20739 * 20740 * <p>The framework will play sound effects for some built in actions, such as 20741 * clicking, but you may wish to play these effects in your widget, 20742 * for instance, for internal navigation. 20743 * 20744 * <p>The sound effect will only be played if sound effects are enabled by the user, and 20745 * {@link #isSoundEffectsEnabled()} is true. 20746 * 20747 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 20748 */ 20749 public void playSoundEffect(int soundConstant) { 20750 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 20751 return; 20752 } 20753 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 20754 } 20755 20756 /** 20757 * BZZZTT!!1! 20758 * 20759 * <p>Provide haptic feedback to the user for this view. 20760 * 20761 * <p>The framework will provide haptic feedback for some built in actions, 20762 * such as long presses, but you may wish to provide feedback for your 20763 * own widget. 20764 * 20765 * <p>The feedback will only be performed if 20766 * {@link #isHapticFeedbackEnabled()} is true. 20767 * 20768 * @param feedbackConstant One of the constants defined in 20769 * {@link HapticFeedbackConstants} 20770 */ 20771 public boolean performHapticFeedback(int feedbackConstant) { 20772 return performHapticFeedback(feedbackConstant, 0); 20773 } 20774 20775 /** 20776 * BZZZTT!!1! 20777 * 20778 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 20779 * 20780 * @param feedbackConstant One of the constants defined in 20781 * {@link HapticFeedbackConstants} 20782 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 20783 */ 20784 public boolean performHapticFeedback(int feedbackConstant, int flags) { 20785 if (mAttachInfo == null) { 20786 return false; 20787 } 20788 //noinspection SimplifiableIfStatement 20789 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 20790 && !isHapticFeedbackEnabled()) { 20791 return false; 20792 } 20793 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 20794 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 20795 } 20796 20797 /** 20798 * Request that the visibility of the status bar or other screen/window 20799 * decorations be changed. 20800 * 20801 * <p>This method is used to put the over device UI into temporary modes 20802 * where the user's attention is focused more on the application content, 20803 * by dimming or hiding surrounding system affordances. This is typically 20804 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 20805 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 20806 * to be placed behind the action bar (and with these flags other system 20807 * affordances) so that smooth transitions between hiding and showing them 20808 * can be done. 20809 * 20810 * <p>Two representative examples of the use of system UI visibility is 20811 * implementing a content browsing application (like a magazine reader) 20812 * and a video playing application. 20813 * 20814 * <p>The first code shows a typical implementation of a View in a content 20815 * browsing application. In this implementation, the application goes 20816 * into a content-oriented mode by hiding the status bar and action bar, 20817 * and putting the navigation elements into lights out mode. The user can 20818 * then interact with content while in this mode. Such an application should 20819 * provide an easy way for the user to toggle out of the mode (such as to 20820 * check information in the status bar or access notifications). In the 20821 * implementation here, this is done simply by tapping on the content. 20822 * 20823 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 20824 * content} 20825 * 20826 * <p>This second code sample shows a typical implementation of a View 20827 * in a video playing application. In this situation, while the video is 20828 * playing the application would like to go into a complete full-screen mode, 20829 * to use as much of the display as possible for the video. When in this state 20830 * the user can not interact with the application; the system intercepts 20831 * touching on the screen to pop the UI out of full screen mode. See 20832 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 20833 * 20834 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 20835 * content} 20836 * 20837 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 20838 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 20839 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 20840 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 20841 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 20842 */ 20843 public void setSystemUiVisibility(int visibility) { 20844 if (visibility != mSystemUiVisibility) { 20845 mSystemUiVisibility = visibility; 20846 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 20847 mParent.recomputeViewAttributes(this); 20848 } 20849 } 20850 } 20851 20852 /** 20853 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 20854 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 20855 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 20856 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 20857 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 20858 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 20859 */ 20860 public int getSystemUiVisibility() { 20861 return mSystemUiVisibility; 20862 } 20863 20864 /** 20865 * Returns the current system UI visibility that is currently set for 20866 * the entire window. This is the combination of the 20867 * {@link #setSystemUiVisibility(int)} values supplied by all of the 20868 * views in the window. 20869 */ 20870 public int getWindowSystemUiVisibility() { 20871 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 20872 } 20873 20874 /** 20875 * Override to find out when the window's requested system UI visibility 20876 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 20877 * This is different from the callbacks received through 20878 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 20879 * in that this is only telling you about the local request of the window, 20880 * not the actual values applied by the system. 20881 */ 20882 public void onWindowSystemUiVisibilityChanged(int visible) { 20883 } 20884 20885 /** 20886 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 20887 * the view hierarchy. 20888 */ 20889 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 20890 onWindowSystemUiVisibilityChanged(visible); 20891 } 20892 20893 /** 20894 * Set a listener to receive callbacks when the visibility of the system bar changes. 20895 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 20896 */ 20897 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 20898 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 20899 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 20900 mParent.recomputeViewAttributes(this); 20901 } 20902 } 20903 20904 /** 20905 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 20906 * the view hierarchy. 20907 */ 20908 public void dispatchSystemUiVisibilityChanged(int visibility) { 20909 ListenerInfo li = mListenerInfo; 20910 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 20911 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 20912 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 20913 } 20914 } 20915 20916 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 20917 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 20918 if (val != mSystemUiVisibility) { 20919 setSystemUiVisibility(val); 20920 return true; 20921 } 20922 return false; 20923 } 20924 20925 /** @hide */ 20926 public void setDisabledSystemUiVisibility(int flags) { 20927 if (mAttachInfo != null) { 20928 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 20929 mAttachInfo.mDisabledSystemUiVisibility = flags; 20930 if (mParent != null) { 20931 mParent.recomputeViewAttributes(this); 20932 } 20933 } 20934 } 20935 } 20936 20937 /** 20938 * Creates an image that the system displays during the drag and drop 20939 * operation. This is called a "drag shadow". The default implementation 20940 * for a DragShadowBuilder based on a View returns an image that has exactly the same 20941 * appearance as the given View. The default also positions the center of the drag shadow 20942 * directly under the touch point. If no View is provided (the constructor with no parameters 20943 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 20944 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 20945 * default is an invisible drag shadow. 20946 * <p> 20947 * You are not required to use the View you provide to the constructor as the basis of the 20948 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 20949 * anything you want as the drag shadow. 20950 * </p> 20951 * <p> 20952 * You pass a DragShadowBuilder object to the system when you start the drag. The system 20953 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 20954 * size and position of the drag shadow. It uses this data to construct a 20955 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 20956 * so that your application can draw the shadow image in the Canvas. 20957 * </p> 20958 * 20959 * <div class="special reference"> 20960 * <h3>Developer Guides</h3> 20961 * <p>For a guide to implementing drag and drop features, read the 20962 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 20963 * </div> 20964 */ 20965 public static class DragShadowBuilder { 20966 private final WeakReference<View> mView; 20967 20968 /** 20969 * Constructs a shadow image builder based on a View. By default, the resulting drag 20970 * shadow will have the same appearance and dimensions as the View, with the touch point 20971 * over the center of the View. 20972 * @param view A View. Any View in scope can be used. 20973 */ 20974 public DragShadowBuilder(View view) { 20975 mView = new WeakReference<View>(view); 20976 } 20977 20978 /** 20979 * Construct a shadow builder object with no associated View. This 20980 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 20981 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 20982 * to supply the drag shadow's dimensions and appearance without 20983 * reference to any View object. If they are not overridden, then the result is an 20984 * invisible drag shadow. 20985 */ 20986 public DragShadowBuilder() { 20987 mView = new WeakReference<View>(null); 20988 } 20989 20990 /** 20991 * Returns the View object that had been passed to the 20992 * {@link #View.DragShadowBuilder(View)} 20993 * constructor. If that View parameter was {@code null} or if the 20994 * {@link #View.DragShadowBuilder()} 20995 * constructor was used to instantiate the builder object, this method will return 20996 * null. 20997 * 20998 * @return The View object associate with this builder object. 20999 */ 21000 @SuppressWarnings({"JavadocReference"}) 21001 final public View getView() { 21002 return mView.get(); 21003 } 21004 21005 /** 21006 * Provides the metrics for the shadow image. These include the dimensions of 21007 * the shadow image, and the point within that shadow that should 21008 * be centered under the touch location while dragging. 21009 * <p> 21010 * The default implementation sets the dimensions of the shadow to be the 21011 * same as the dimensions of the View itself and centers the shadow under 21012 * the touch point. 21013 * </p> 21014 * 21015 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 21016 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 21017 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 21018 * image. 21019 * 21020 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 21021 * shadow image that should be underneath the touch point during the drag and drop 21022 * operation. Your application must set {@link android.graphics.Point#x} to the 21023 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 21024 */ 21025 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 21026 final View view = mView.get(); 21027 if (view != null) { 21028 outShadowSize.set(view.getWidth(), view.getHeight()); 21029 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 21030 } else { 21031 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 21032 } 21033 } 21034 21035 /** 21036 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 21037 * based on the dimensions it received from the 21038 * {@link #onProvideShadowMetrics(Point, Point)} callback. 21039 * 21040 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 21041 */ 21042 public void onDrawShadow(Canvas canvas) { 21043 final View view = mView.get(); 21044 if (view != null) { 21045 view.draw(canvas); 21046 } else { 21047 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 21048 } 21049 } 21050 } 21051 21052 /** 21053 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 21054 * startDragAndDrop()} for newer platform versions. 21055 */ 21056 @Deprecated 21057 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 21058 Object myLocalState, int flags) { 21059 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 21060 } 21061 21062 /** 21063 * Starts a drag and drop operation. When your application calls this method, it passes a 21064 * {@link android.view.View.DragShadowBuilder} object to the system. The 21065 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 21066 * to get metrics for the drag shadow, and then calls the object's 21067 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 21068 * <p> 21069 * Once the system has the drag shadow, it begins the drag and drop operation by sending 21070 * drag events to all the View objects in your application that are currently visible. It does 21071 * this either by calling the View object's drag listener (an implementation of 21072 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 21073 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 21074 * Both are passed a {@link android.view.DragEvent} object that has a 21075 * {@link android.view.DragEvent#getAction()} value of 21076 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 21077 * </p> 21078 * <p> 21079 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 21080 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 21081 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 21082 * to the View the user selected for dragging. 21083 * </p> 21084 * @param data A {@link android.content.ClipData} object pointing to the data to be 21085 * transferred by the drag and drop operation. 21086 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21087 * drag shadow. 21088 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 21089 * drop operation. When dispatching drag events to views in the same activity this object 21090 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 21091 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 21092 * will return null). 21093 * <p> 21094 * myLocalState is a lightweight mechanism for the sending information from the dragged View 21095 * to the target Views. For example, it can contain flags that differentiate between a 21096 * a copy operation and a move operation. 21097 * </p> 21098 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 21099 * flags, or any combination of the following: 21100 * <ul> 21101 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 21102 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 21103 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 21104 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 21105 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 21106 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 21107 * </ul> 21108 * @return {@code true} if the method completes successfully, or 21109 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 21110 * do a drag, and so no drag operation is in progress. 21111 */ 21112 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 21113 Object myLocalState, int flags) { 21114 if (ViewDebug.DEBUG_DRAG) { 21115 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 21116 } 21117 if (mAttachInfo == null) { 21118 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 21119 return false; 21120 } 21121 21122 if (data != null) { 21123 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 21124 } 21125 21126 boolean okay = false; 21127 21128 Point shadowSize = new Point(); 21129 Point shadowTouchPoint = new Point(); 21130 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 21131 21132 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 21133 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 21134 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 21135 } 21136 21137 if (ViewDebug.DEBUG_DRAG) { 21138 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 21139 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 21140 } 21141 if (mAttachInfo.mDragSurface != null) { 21142 mAttachInfo.mDragSurface.release(); 21143 } 21144 mAttachInfo.mDragSurface = new Surface(); 21145 try { 21146 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 21147 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 21148 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 21149 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 21150 if (mAttachInfo.mDragToken != null) { 21151 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21152 try { 21153 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21154 shadowBuilder.onDrawShadow(canvas); 21155 } finally { 21156 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21157 } 21158 21159 final ViewRootImpl root = getViewRootImpl(); 21160 21161 // Cache the local state object for delivery with DragEvents 21162 root.setLocalDragState(myLocalState); 21163 21164 // repurpose 'shadowSize' for the last touch point 21165 root.getLastTouchPoint(shadowSize); 21166 21167 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 21168 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 21169 shadowTouchPoint.x, shadowTouchPoint.y, data); 21170 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 21171 } 21172 } catch (Exception e) { 21173 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 21174 mAttachInfo.mDragSurface.destroy(); 21175 mAttachInfo.mDragSurface = null; 21176 } 21177 21178 return okay; 21179 } 21180 21181 /** 21182 * Cancels an ongoing drag and drop operation. 21183 * <p> 21184 * A {@link android.view.DragEvent} object with 21185 * {@link android.view.DragEvent#getAction()} value of 21186 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 21187 * {@link android.view.DragEvent#getResult()} value of {@code false} 21188 * will be sent to every 21189 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 21190 * even if they are not currently visible. 21191 * </p> 21192 * <p> 21193 * This method can be called on any View in the same window as the View on which 21194 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 21195 * was called. 21196 * </p> 21197 */ 21198 public final void cancelDragAndDrop() { 21199 if (ViewDebug.DEBUG_DRAG) { 21200 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 21201 } 21202 if (mAttachInfo == null) { 21203 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 21204 return; 21205 } 21206 if (mAttachInfo.mDragToken != null) { 21207 try { 21208 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 21209 } catch (Exception e) { 21210 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 21211 } 21212 mAttachInfo.mDragToken = null; 21213 } else { 21214 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 21215 } 21216 } 21217 21218 /** 21219 * Updates the drag shadow for the ongoing drag and drop operation. 21220 * 21221 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21222 * new drag shadow. 21223 */ 21224 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 21225 if (ViewDebug.DEBUG_DRAG) { 21226 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 21227 } 21228 if (mAttachInfo == null) { 21229 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 21230 return; 21231 } 21232 if (mAttachInfo.mDragToken != null) { 21233 try { 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 } catch (Exception e) { 21242 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 21243 } 21244 } else { 21245 Log.e(VIEW_LOG_TAG, "No active drag"); 21246 } 21247 } 21248 21249 /** 21250 * Starts a move from {startX, startY}, the amount of the movement will be the offset 21251 * between {startX, startY} and the new cursor positon. 21252 * @param startX horizontal coordinate where the move started. 21253 * @param startY vertical coordinate where the move started. 21254 * @return whether moving was started successfully. 21255 * @hide 21256 */ 21257 public final boolean startMovingTask(float startX, float startY) { 21258 if (ViewDebug.DEBUG_POSITIONING) { 21259 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 21260 } 21261 try { 21262 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 21263 } catch (RemoteException e) { 21264 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 21265 } 21266 return false; 21267 } 21268 21269 /** 21270 * Handles drag events sent by the system following a call to 21271 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 21272 * startDragAndDrop()}. 21273 *<p> 21274 * When the system calls this method, it passes a 21275 * {@link android.view.DragEvent} object. A call to 21276 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 21277 * in DragEvent. The method uses these to determine what is happening in the drag and drop 21278 * operation. 21279 * @param event The {@link android.view.DragEvent} sent by the system. 21280 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 21281 * in DragEvent, indicating the type of drag event represented by this object. 21282 * @return {@code true} if the method was successful, otherwise {@code false}. 21283 * <p> 21284 * The method should return {@code true} in response to an action type of 21285 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 21286 * operation. 21287 * </p> 21288 * <p> 21289 * The method should also return {@code true} in response to an action type of 21290 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 21291 * {@code false} if it didn't. 21292 * </p> 21293 * <p> 21294 * For all other events, the return value is ignored. 21295 * </p> 21296 */ 21297 public boolean onDragEvent(DragEvent event) { 21298 return false; 21299 } 21300 21301 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 21302 boolean dispatchDragEnterExitInPreN(DragEvent event) { 21303 return callDragEventHandler(event); 21304 } 21305 21306 /** 21307 * Detects if this View is enabled and has a drag event listener. 21308 * If both are true, then it calls the drag event listener with the 21309 * {@link android.view.DragEvent} it received. If the drag event listener returns 21310 * {@code true}, then dispatchDragEvent() returns {@code true}. 21311 * <p> 21312 * For all other cases, the method calls the 21313 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 21314 * method and returns its result. 21315 * </p> 21316 * <p> 21317 * This ensures that a drag event is always consumed, even if the View does not have a drag 21318 * event listener. However, if the View has a listener and the listener returns true, then 21319 * onDragEvent() is not called. 21320 * </p> 21321 */ 21322 public boolean dispatchDragEvent(DragEvent event) { 21323 event.mEventHandlerWasCalled = true; 21324 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 21325 event.mAction == DragEvent.ACTION_DROP) { 21326 // About to deliver an event with coordinates to this view. Notify that now this view 21327 // has drag focus. This will send exit/enter events as needed. 21328 getViewRootImpl().setDragFocus(this, event); 21329 } 21330 return callDragEventHandler(event); 21331 } 21332 21333 final boolean callDragEventHandler(DragEvent event) { 21334 final boolean result; 21335 21336 ListenerInfo li = mListenerInfo; 21337 //noinspection SimplifiableIfStatement 21338 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 21339 && li.mOnDragListener.onDrag(this, event)) { 21340 result = true; 21341 } else { 21342 result = onDragEvent(event); 21343 } 21344 21345 switch (event.mAction) { 21346 case DragEvent.ACTION_DRAG_ENTERED: { 21347 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 21348 refreshDrawableState(); 21349 } break; 21350 case DragEvent.ACTION_DRAG_EXITED: { 21351 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 21352 refreshDrawableState(); 21353 } break; 21354 case DragEvent.ACTION_DRAG_ENDED: { 21355 mPrivateFlags2 &= ~View.DRAG_MASK; 21356 refreshDrawableState(); 21357 } break; 21358 } 21359 21360 return result; 21361 } 21362 21363 boolean canAcceptDrag() { 21364 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 21365 } 21366 21367 /** 21368 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 21369 * it is ever exposed at all. 21370 * @hide 21371 */ 21372 public void onCloseSystemDialogs(String reason) { 21373 } 21374 21375 /** 21376 * Given a Drawable whose bounds have been set to draw into this view, 21377 * update a Region being computed for 21378 * {@link #gatherTransparentRegion(android.graphics.Region)} so 21379 * that any non-transparent parts of the Drawable are removed from the 21380 * given transparent region. 21381 * 21382 * @param dr The Drawable whose transparency is to be applied to the region. 21383 * @param region A Region holding the current transparency information, 21384 * where any parts of the region that are set are considered to be 21385 * transparent. On return, this region will be modified to have the 21386 * transparency information reduced by the corresponding parts of the 21387 * Drawable that are not transparent. 21388 * {@hide} 21389 */ 21390 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 21391 if (DBG) { 21392 Log.i("View", "Getting transparent region for: " + this); 21393 } 21394 final Region r = dr.getTransparentRegion(); 21395 final Rect db = dr.getBounds(); 21396 final AttachInfo attachInfo = mAttachInfo; 21397 if (r != null && attachInfo != null) { 21398 final int w = getRight()-getLeft(); 21399 final int h = getBottom()-getTop(); 21400 if (db.left > 0) { 21401 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 21402 r.op(0, 0, db.left, h, Region.Op.UNION); 21403 } 21404 if (db.right < w) { 21405 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 21406 r.op(db.right, 0, w, h, Region.Op.UNION); 21407 } 21408 if (db.top > 0) { 21409 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 21410 r.op(0, 0, w, db.top, Region.Op.UNION); 21411 } 21412 if (db.bottom < h) { 21413 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 21414 r.op(0, db.bottom, w, h, Region.Op.UNION); 21415 } 21416 final int[] location = attachInfo.mTransparentLocation; 21417 getLocationInWindow(location); 21418 r.translate(location[0], location[1]); 21419 region.op(r, Region.Op.INTERSECT); 21420 } else { 21421 region.op(db, Region.Op.DIFFERENCE); 21422 } 21423 } 21424 21425 private void checkForLongClick(int delayOffset, float x, float y) { 21426 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 21427 mHasPerformedLongPress = false; 21428 21429 if (mPendingCheckForLongPress == null) { 21430 mPendingCheckForLongPress = new CheckForLongPress(); 21431 } 21432 mPendingCheckForLongPress.setAnchor(x, y); 21433 mPendingCheckForLongPress.rememberWindowAttachCount(); 21434 mPendingCheckForLongPress.rememberPressedState(); 21435 postDelayed(mPendingCheckForLongPress, 21436 ViewConfiguration.getLongPressTimeout() - delayOffset); 21437 } 21438 } 21439 21440 /** 21441 * Inflate a view from an XML resource. This convenience method wraps the {@link 21442 * LayoutInflater} class, which provides a full range of options for view inflation. 21443 * 21444 * @param context The Context object for your activity or application. 21445 * @param resource The resource ID to inflate 21446 * @param root A view group that will be the parent. Used to properly inflate the 21447 * layout_* parameters. 21448 * @see LayoutInflater 21449 */ 21450 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 21451 LayoutInflater factory = LayoutInflater.from(context); 21452 return factory.inflate(resource, root); 21453 } 21454 21455 /** 21456 * Scroll the view with standard behavior for scrolling beyond the normal 21457 * content boundaries. Views that call this method should override 21458 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 21459 * results of an over-scroll operation. 21460 * 21461 * Views can use this method to handle any touch or fling-based scrolling. 21462 * 21463 * @param deltaX Change in X in pixels 21464 * @param deltaY Change in Y in pixels 21465 * @param scrollX Current X scroll value in pixels before applying deltaX 21466 * @param scrollY Current Y scroll value in pixels before applying deltaY 21467 * @param scrollRangeX Maximum content scroll range along the X axis 21468 * @param scrollRangeY Maximum content scroll range along the Y axis 21469 * @param maxOverScrollX Number of pixels to overscroll by in either direction 21470 * along the X axis. 21471 * @param maxOverScrollY Number of pixels to overscroll by in either direction 21472 * along the Y axis. 21473 * @param isTouchEvent true if this scroll operation is the result of a touch event. 21474 * @return true if scrolling was clamped to an over-scroll boundary along either 21475 * axis, false otherwise. 21476 */ 21477 @SuppressWarnings({"UnusedParameters"}) 21478 protected boolean overScrollBy(int deltaX, int deltaY, 21479 int scrollX, int scrollY, 21480 int scrollRangeX, int scrollRangeY, 21481 int maxOverScrollX, int maxOverScrollY, 21482 boolean isTouchEvent) { 21483 final int overScrollMode = mOverScrollMode; 21484 final boolean canScrollHorizontal = 21485 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 21486 final boolean canScrollVertical = 21487 computeVerticalScrollRange() > computeVerticalScrollExtent(); 21488 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 21489 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 21490 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 21491 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 21492 21493 int newScrollX = scrollX + deltaX; 21494 if (!overScrollHorizontal) { 21495 maxOverScrollX = 0; 21496 } 21497 21498 int newScrollY = scrollY + deltaY; 21499 if (!overScrollVertical) { 21500 maxOverScrollY = 0; 21501 } 21502 21503 // Clamp values if at the limits and record 21504 final int left = -maxOverScrollX; 21505 final int right = maxOverScrollX + scrollRangeX; 21506 final int top = -maxOverScrollY; 21507 final int bottom = maxOverScrollY + scrollRangeY; 21508 21509 boolean clampedX = false; 21510 if (newScrollX > right) { 21511 newScrollX = right; 21512 clampedX = true; 21513 } else if (newScrollX < left) { 21514 newScrollX = left; 21515 clampedX = true; 21516 } 21517 21518 boolean clampedY = false; 21519 if (newScrollY > bottom) { 21520 newScrollY = bottom; 21521 clampedY = true; 21522 } else if (newScrollY < top) { 21523 newScrollY = top; 21524 clampedY = true; 21525 } 21526 21527 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 21528 21529 return clampedX || clampedY; 21530 } 21531 21532 /** 21533 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 21534 * respond to the results of an over-scroll operation. 21535 * 21536 * @param scrollX New X scroll value in pixels 21537 * @param scrollY New Y scroll value in pixels 21538 * @param clampedX True if scrollX was clamped to an over-scroll boundary 21539 * @param clampedY True if scrollY was clamped to an over-scroll boundary 21540 */ 21541 protected void onOverScrolled(int scrollX, int scrollY, 21542 boolean clampedX, boolean clampedY) { 21543 // Intentionally empty. 21544 } 21545 21546 /** 21547 * Returns the over-scroll mode for this view. The result will be 21548 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21549 * (allow over-scrolling only if the view content is larger than the container), 21550 * or {@link #OVER_SCROLL_NEVER}. 21551 * 21552 * @return This view's over-scroll mode. 21553 */ 21554 public int getOverScrollMode() { 21555 return mOverScrollMode; 21556 } 21557 21558 /** 21559 * Set the over-scroll mode for this view. Valid over-scroll modes are 21560 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21561 * (allow over-scrolling only if the view content is larger than the container), 21562 * or {@link #OVER_SCROLL_NEVER}. 21563 * 21564 * Setting the over-scroll mode of a view will have an effect only if the 21565 * view is capable of scrolling. 21566 * 21567 * @param overScrollMode The new over-scroll mode for this view. 21568 */ 21569 public void setOverScrollMode(int overScrollMode) { 21570 if (overScrollMode != OVER_SCROLL_ALWAYS && 21571 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 21572 overScrollMode != OVER_SCROLL_NEVER) { 21573 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 21574 } 21575 mOverScrollMode = overScrollMode; 21576 } 21577 21578 /** 21579 * Enable or disable nested scrolling for this view. 21580 * 21581 * <p>If this property is set to true the view will be permitted to initiate nested 21582 * scrolling operations with a compatible parent view in the current hierarchy. If this 21583 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 21584 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 21585 * the nested scroll.</p> 21586 * 21587 * @param enabled true to enable nested scrolling, false to disable 21588 * 21589 * @see #isNestedScrollingEnabled() 21590 */ 21591 public void setNestedScrollingEnabled(boolean enabled) { 21592 if (enabled) { 21593 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 21594 } else { 21595 stopNestedScroll(); 21596 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 21597 } 21598 } 21599 21600 /** 21601 * Returns true if nested scrolling is enabled for this view. 21602 * 21603 * <p>If nested scrolling is enabled and this View class implementation supports it, 21604 * this view will act as a nested scrolling child view when applicable, forwarding data 21605 * about the scroll operation in progress to a compatible and cooperating nested scrolling 21606 * parent.</p> 21607 * 21608 * @return true if nested scrolling is enabled 21609 * 21610 * @see #setNestedScrollingEnabled(boolean) 21611 */ 21612 public boolean isNestedScrollingEnabled() { 21613 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 21614 PFLAG3_NESTED_SCROLLING_ENABLED; 21615 } 21616 21617 /** 21618 * Begin a nestable scroll operation along the given axes. 21619 * 21620 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 21621 * 21622 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 21623 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 21624 * In the case of touch scrolling the nested scroll will be terminated automatically in 21625 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 21626 * In the event of programmatic scrolling the caller must explicitly call 21627 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 21628 * 21629 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 21630 * If it returns false the caller may ignore the rest of this contract until the next scroll. 21631 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 21632 * 21633 * <p>At each incremental step of the scroll the caller should invoke 21634 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 21635 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 21636 * parent at least partially consumed the scroll and the caller should adjust the amount it 21637 * scrolls by.</p> 21638 * 21639 * <p>After applying the remainder of the scroll delta the caller should invoke 21640 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 21641 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 21642 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 21643 * </p> 21644 * 21645 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 21646 * {@link #SCROLL_AXIS_VERTICAL}. 21647 * @return true if a cooperative parent was found and nested scrolling has been enabled for 21648 * the current gesture. 21649 * 21650 * @see #stopNestedScroll() 21651 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21652 * @see #dispatchNestedScroll(int, int, int, int, int[]) 21653 */ 21654 public boolean startNestedScroll(int axes) { 21655 if (hasNestedScrollingParent()) { 21656 // Already in progress 21657 return true; 21658 } 21659 if (isNestedScrollingEnabled()) { 21660 ViewParent p = getParent(); 21661 View child = this; 21662 while (p != null) { 21663 try { 21664 if (p.onStartNestedScroll(child, this, axes)) { 21665 mNestedScrollingParent = p; 21666 p.onNestedScrollAccepted(child, this, axes); 21667 return true; 21668 } 21669 } catch (AbstractMethodError e) { 21670 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 21671 "method onStartNestedScroll", e); 21672 // Allow the search upward to continue 21673 } 21674 if (p instanceof View) { 21675 child = (View) p; 21676 } 21677 p = p.getParent(); 21678 } 21679 } 21680 return false; 21681 } 21682 21683 /** 21684 * Stop a nested scroll in progress. 21685 * 21686 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 21687 * 21688 * @see #startNestedScroll(int) 21689 */ 21690 public void stopNestedScroll() { 21691 if (mNestedScrollingParent != null) { 21692 mNestedScrollingParent.onStopNestedScroll(this); 21693 mNestedScrollingParent = null; 21694 } 21695 } 21696 21697 /** 21698 * Returns true if this view has a nested scrolling parent. 21699 * 21700 * <p>The presence of a nested scrolling parent indicates that this view has initiated 21701 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 21702 * 21703 * @return whether this view has a nested scrolling parent 21704 */ 21705 public boolean hasNestedScrollingParent() { 21706 return mNestedScrollingParent != null; 21707 } 21708 21709 /** 21710 * Dispatch one step of a nested scroll in progress. 21711 * 21712 * <p>Implementations of views that support nested scrolling should call this to report 21713 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 21714 * is not currently in progress or nested scrolling is not 21715 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 21716 * 21717 * <p>Compatible View implementations should also call 21718 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 21719 * consuming a component of the scroll event themselves.</p> 21720 * 21721 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 21722 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 21723 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 21724 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 21725 * @param offsetInWindow Optional. If not null, on return this will contain the offset 21726 * in local view coordinates of this view from before this operation 21727 * to after it completes. View implementations may use this to adjust 21728 * expected input coordinate tracking. 21729 * @return true if the event was dispatched, false if it could not be dispatched. 21730 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21731 */ 21732 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 21733 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 21734 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21735 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 21736 int startX = 0; 21737 int startY = 0; 21738 if (offsetInWindow != null) { 21739 getLocationInWindow(offsetInWindow); 21740 startX = offsetInWindow[0]; 21741 startY = offsetInWindow[1]; 21742 } 21743 21744 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 21745 dxUnconsumed, dyUnconsumed); 21746 21747 if (offsetInWindow != null) { 21748 getLocationInWindow(offsetInWindow); 21749 offsetInWindow[0] -= startX; 21750 offsetInWindow[1] -= startY; 21751 } 21752 return true; 21753 } else if (offsetInWindow != null) { 21754 // No motion, no dispatch. Keep offsetInWindow up to date. 21755 offsetInWindow[0] = 0; 21756 offsetInWindow[1] = 0; 21757 } 21758 } 21759 return false; 21760 } 21761 21762 /** 21763 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 21764 * 21765 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 21766 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 21767 * scrolling operation to consume some or all of the scroll operation before the child view 21768 * consumes it.</p> 21769 * 21770 * @param dx Horizontal scroll distance in pixels 21771 * @param dy Vertical scroll distance in pixels 21772 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 21773 * and consumed[1] the consumed dy. 21774 * @param offsetInWindow Optional. If not null, on return this will contain the offset 21775 * in local view coordinates of this view from before this operation 21776 * to after it completes. View implementations may use this to adjust 21777 * expected input coordinate tracking. 21778 * @return true if the parent consumed some or all of the scroll delta 21779 * @see #dispatchNestedScroll(int, int, int, int, int[]) 21780 */ 21781 public boolean dispatchNestedPreScroll(int dx, int dy, 21782 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 21783 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21784 if (dx != 0 || dy != 0) { 21785 int startX = 0; 21786 int startY = 0; 21787 if (offsetInWindow != null) { 21788 getLocationInWindow(offsetInWindow); 21789 startX = offsetInWindow[0]; 21790 startY = offsetInWindow[1]; 21791 } 21792 21793 if (consumed == null) { 21794 if (mTempNestedScrollConsumed == null) { 21795 mTempNestedScrollConsumed = new int[2]; 21796 } 21797 consumed = mTempNestedScrollConsumed; 21798 } 21799 consumed[0] = 0; 21800 consumed[1] = 0; 21801 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 21802 21803 if (offsetInWindow != null) { 21804 getLocationInWindow(offsetInWindow); 21805 offsetInWindow[0] -= startX; 21806 offsetInWindow[1] -= startY; 21807 } 21808 return consumed[0] != 0 || consumed[1] != 0; 21809 } else if (offsetInWindow != null) { 21810 offsetInWindow[0] = 0; 21811 offsetInWindow[1] = 0; 21812 } 21813 } 21814 return false; 21815 } 21816 21817 /** 21818 * Dispatch a fling to a nested scrolling parent. 21819 * 21820 * <p>This method should be used to indicate that a nested scrolling child has detected 21821 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 21822 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 21823 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 21824 * along a scrollable axis.</p> 21825 * 21826 * <p>If a nested scrolling child view would normally fling but it is at the edge of 21827 * its own content, it can use this method to delegate the fling to its nested scrolling 21828 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 21829 * 21830 * @param velocityX Horizontal fling velocity in pixels per second 21831 * @param velocityY Vertical fling velocity in pixels per second 21832 * @param consumed true if the child consumed the fling, false otherwise 21833 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 21834 */ 21835 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 21836 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21837 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 21838 } 21839 return false; 21840 } 21841 21842 /** 21843 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 21844 * 21845 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 21846 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 21847 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 21848 * before the child view consumes it. If this method returns <code>true</code>, a nested 21849 * parent view consumed the fling and this view should not scroll as a result.</p> 21850 * 21851 * <p>For a better user experience, only one view in a nested scrolling chain should consume 21852 * the fling at a time. If a parent view consumed the fling this method will return false. 21853 * Custom view implementations should account for this in two ways:</p> 21854 * 21855 * <ul> 21856 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 21857 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 21858 * position regardless.</li> 21859 * <li>If a nested parent does consume the fling, this view should not scroll at all, 21860 * even to settle back to a valid idle position.</li> 21861 * </ul> 21862 * 21863 * <p>Views should also not offer fling velocities to nested parent views along an axis 21864 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 21865 * should not offer a horizontal fling velocity to its parents since scrolling along that 21866 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 21867 * 21868 * @param velocityX Horizontal fling velocity in pixels per second 21869 * @param velocityY Vertical fling velocity in pixels per second 21870 * @return true if a nested scrolling parent consumed the fling 21871 */ 21872 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 21873 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21874 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 21875 } 21876 return false; 21877 } 21878 21879 /** 21880 * Gets a scale factor that determines the distance the view should scroll 21881 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 21882 * @return The vertical scroll scale factor. 21883 * @hide 21884 */ 21885 protected float getVerticalScrollFactor() { 21886 if (mVerticalScrollFactor == 0) { 21887 TypedValue outValue = new TypedValue(); 21888 if (!mContext.getTheme().resolveAttribute( 21889 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 21890 throw new IllegalStateException( 21891 "Expected theme to define listPreferredItemHeight."); 21892 } 21893 mVerticalScrollFactor = outValue.getDimension( 21894 mContext.getResources().getDisplayMetrics()); 21895 } 21896 return mVerticalScrollFactor; 21897 } 21898 21899 /** 21900 * Gets a scale factor that determines the distance the view should scroll 21901 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 21902 * @return The horizontal scroll scale factor. 21903 * @hide 21904 */ 21905 protected float getHorizontalScrollFactor() { 21906 // TODO: Should use something else. 21907 return getVerticalScrollFactor(); 21908 } 21909 21910 /** 21911 * Return the value specifying the text direction or policy that was set with 21912 * {@link #setTextDirection(int)}. 21913 * 21914 * @return the defined text direction. It can be one of: 21915 * 21916 * {@link #TEXT_DIRECTION_INHERIT}, 21917 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 21918 * {@link #TEXT_DIRECTION_ANY_RTL}, 21919 * {@link #TEXT_DIRECTION_LTR}, 21920 * {@link #TEXT_DIRECTION_RTL}, 21921 * {@link #TEXT_DIRECTION_LOCALE}, 21922 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 21923 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 21924 * 21925 * @attr ref android.R.styleable#View_textDirection 21926 * 21927 * @hide 21928 */ 21929 @ViewDebug.ExportedProperty(category = "text", mapping = { 21930 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 21931 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 21932 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 21933 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 21934 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 21935 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 21936 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 21937 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 21938 }) 21939 public int getRawTextDirection() { 21940 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 21941 } 21942 21943 /** 21944 * Set the text direction. 21945 * 21946 * @param textDirection the direction to set. Should be one of: 21947 * 21948 * {@link #TEXT_DIRECTION_INHERIT}, 21949 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 21950 * {@link #TEXT_DIRECTION_ANY_RTL}, 21951 * {@link #TEXT_DIRECTION_LTR}, 21952 * {@link #TEXT_DIRECTION_RTL}, 21953 * {@link #TEXT_DIRECTION_LOCALE} 21954 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 21955 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 21956 * 21957 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 21958 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 21959 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 21960 * 21961 * @attr ref android.R.styleable#View_textDirection 21962 */ 21963 public void setTextDirection(int textDirection) { 21964 if (getRawTextDirection() != textDirection) { 21965 // Reset the current text direction and the resolved one 21966 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 21967 resetResolvedTextDirection(); 21968 // Set the new text direction 21969 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 21970 // Do resolution 21971 resolveTextDirection(); 21972 // Notify change 21973 onRtlPropertiesChanged(getLayoutDirection()); 21974 // Refresh 21975 requestLayout(); 21976 invalidate(true); 21977 } 21978 } 21979 21980 /** 21981 * Return the resolved text direction. 21982 * 21983 * @return the resolved text direction. Returns one of: 21984 * 21985 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 21986 * {@link #TEXT_DIRECTION_ANY_RTL}, 21987 * {@link #TEXT_DIRECTION_LTR}, 21988 * {@link #TEXT_DIRECTION_RTL}, 21989 * {@link #TEXT_DIRECTION_LOCALE}, 21990 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 21991 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 21992 * 21993 * @attr ref android.R.styleable#View_textDirection 21994 */ 21995 @ViewDebug.ExportedProperty(category = "text", mapping = { 21996 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 21997 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 21998 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 21999 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22000 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22001 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22002 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22003 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22004 }) 22005 public int getTextDirection() { 22006 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 22007 } 22008 22009 /** 22010 * Resolve the text direction. 22011 * 22012 * @return true if resolution has been done, false otherwise. 22013 * 22014 * @hide 22015 */ 22016 public boolean resolveTextDirection() { 22017 // Reset any previous text direction resolution 22018 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22019 22020 if (hasRtlSupport()) { 22021 // Set resolved text direction flag depending on text direction flag 22022 final int textDirection = getRawTextDirection(); 22023 switch(textDirection) { 22024 case TEXT_DIRECTION_INHERIT: 22025 if (!canResolveTextDirection()) { 22026 // We cannot do the resolution if there is no parent, so use the default one 22027 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22028 // Resolution will need to happen again later 22029 return false; 22030 } 22031 22032 // Parent has not yet resolved, so we still return the default 22033 try { 22034 if (!mParent.isTextDirectionResolved()) { 22035 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22036 // Resolution will need to happen again later 22037 return false; 22038 } 22039 } catch (AbstractMethodError e) { 22040 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22041 " does not fully implement ViewParent", e); 22042 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 22043 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22044 return true; 22045 } 22046 22047 // Set current resolved direction to the same value as the parent's one 22048 int parentResolvedDirection; 22049 try { 22050 parentResolvedDirection = mParent.getTextDirection(); 22051 } catch (AbstractMethodError e) { 22052 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22053 " does not fully implement ViewParent", e); 22054 parentResolvedDirection = TEXT_DIRECTION_LTR; 22055 } 22056 switch (parentResolvedDirection) { 22057 case TEXT_DIRECTION_FIRST_STRONG: 22058 case TEXT_DIRECTION_ANY_RTL: 22059 case TEXT_DIRECTION_LTR: 22060 case TEXT_DIRECTION_RTL: 22061 case TEXT_DIRECTION_LOCALE: 22062 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22063 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22064 mPrivateFlags2 |= 22065 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22066 break; 22067 default: 22068 // Default resolved direction is "first strong" heuristic 22069 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22070 } 22071 break; 22072 case TEXT_DIRECTION_FIRST_STRONG: 22073 case TEXT_DIRECTION_ANY_RTL: 22074 case TEXT_DIRECTION_LTR: 22075 case TEXT_DIRECTION_RTL: 22076 case TEXT_DIRECTION_LOCALE: 22077 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22078 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22079 // Resolved direction is the same as text direction 22080 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22081 break; 22082 default: 22083 // Default resolved direction is "first strong" heuristic 22084 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22085 } 22086 } else { 22087 // Default resolved direction is "first strong" heuristic 22088 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22089 } 22090 22091 // Set to resolved 22092 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 22093 return true; 22094 } 22095 22096 /** 22097 * Check if text direction resolution can be done. 22098 * 22099 * @return true if text direction resolution can be done otherwise return false. 22100 */ 22101 public boolean canResolveTextDirection() { 22102 switch (getRawTextDirection()) { 22103 case TEXT_DIRECTION_INHERIT: 22104 if (mParent != null) { 22105 try { 22106 return mParent.canResolveTextDirection(); 22107 } catch (AbstractMethodError e) { 22108 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22109 " does not fully implement ViewParent", e); 22110 } 22111 } 22112 return false; 22113 22114 default: 22115 return true; 22116 } 22117 } 22118 22119 /** 22120 * Reset resolved text direction. Text direction will be resolved during a call to 22121 * {@link #onMeasure(int, int)}. 22122 * 22123 * @hide 22124 */ 22125 public void resetResolvedTextDirection() { 22126 // Reset any previous text direction resolution 22127 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22128 // Set to default value 22129 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22130 } 22131 22132 /** 22133 * @return true if text direction is inherited. 22134 * 22135 * @hide 22136 */ 22137 public boolean isTextDirectionInherited() { 22138 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 22139 } 22140 22141 /** 22142 * @return true if text direction is resolved. 22143 */ 22144 public boolean isTextDirectionResolved() { 22145 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 22146 } 22147 22148 /** 22149 * Return the value specifying the text alignment or policy that was set with 22150 * {@link #setTextAlignment(int)}. 22151 * 22152 * @return the defined text alignment. It can be one of: 22153 * 22154 * {@link #TEXT_ALIGNMENT_INHERIT}, 22155 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22156 * {@link #TEXT_ALIGNMENT_CENTER}, 22157 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22158 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22159 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22160 * {@link #TEXT_ALIGNMENT_VIEW_END} 22161 * 22162 * @attr ref android.R.styleable#View_textAlignment 22163 * 22164 * @hide 22165 */ 22166 @ViewDebug.ExportedProperty(category = "text", mapping = { 22167 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22168 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22169 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22170 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22171 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22172 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22173 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22174 }) 22175 @TextAlignment 22176 public int getRawTextAlignment() { 22177 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 22178 } 22179 22180 /** 22181 * Set the text alignment. 22182 * 22183 * @param textAlignment The text alignment to set. Should be one of 22184 * 22185 * {@link #TEXT_ALIGNMENT_INHERIT}, 22186 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22187 * {@link #TEXT_ALIGNMENT_CENTER}, 22188 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22189 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22190 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22191 * {@link #TEXT_ALIGNMENT_VIEW_END} 22192 * 22193 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 22194 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 22195 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 22196 * 22197 * @attr ref android.R.styleable#View_textAlignment 22198 */ 22199 public void setTextAlignment(@TextAlignment int textAlignment) { 22200 if (textAlignment != getRawTextAlignment()) { 22201 // Reset the current and resolved text alignment 22202 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 22203 resetResolvedTextAlignment(); 22204 // Set the new text alignment 22205 mPrivateFlags2 |= 22206 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 22207 // Do resolution 22208 resolveTextAlignment(); 22209 // Notify change 22210 onRtlPropertiesChanged(getLayoutDirection()); 22211 // Refresh 22212 requestLayout(); 22213 invalidate(true); 22214 } 22215 } 22216 22217 /** 22218 * Return the resolved text alignment. 22219 * 22220 * @return the resolved text alignment. Returns one of: 22221 * 22222 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22223 * {@link #TEXT_ALIGNMENT_CENTER}, 22224 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22225 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22226 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22227 * {@link #TEXT_ALIGNMENT_VIEW_END} 22228 * 22229 * @attr ref android.R.styleable#View_textAlignment 22230 */ 22231 @ViewDebug.ExportedProperty(category = "text", mapping = { 22232 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22233 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22234 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22235 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22236 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22237 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22238 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22239 }) 22240 @TextAlignment 22241 public int getTextAlignment() { 22242 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 22243 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 22244 } 22245 22246 /** 22247 * Resolve the text alignment. 22248 * 22249 * @return true if resolution has been done, false otherwise. 22250 * 22251 * @hide 22252 */ 22253 public boolean resolveTextAlignment() { 22254 // Reset any previous text alignment resolution 22255 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22256 22257 if (hasRtlSupport()) { 22258 // Set resolved text alignment flag depending on text alignment flag 22259 final int textAlignment = getRawTextAlignment(); 22260 switch (textAlignment) { 22261 case TEXT_ALIGNMENT_INHERIT: 22262 // Check if we can resolve the text alignment 22263 if (!canResolveTextAlignment()) { 22264 // We cannot do the resolution if there is no parent so use the default 22265 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22266 // Resolution will need to happen again later 22267 return false; 22268 } 22269 22270 // Parent has not yet resolved, so we still return the default 22271 try { 22272 if (!mParent.isTextAlignmentResolved()) { 22273 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22274 // Resolution will need to happen again later 22275 return false; 22276 } 22277 } catch (AbstractMethodError e) { 22278 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22279 " does not fully implement ViewParent", e); 22280 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 22281 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22282 return true; 22283 } 22284 22285 int parentResolvedTextAlignment; 22286 try { 22287 parentResolvedTextAlignment = mParent.getTextAlignment(); 22288 } catch (AbstractMethodError e) { 22289 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22290 " does not fully implement ViewParent", e); 22291 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 22292 } 22293 switch (parentResolvedTextAlignment) { 22294 case TEXT_ALIGNMENT_GRAVITY: 22295 case TEXT_ALIGNMENT_TEXT_START: 22296 case TEXT_ALIGNMENT_TEXT_END: 22297 case TEXT_ALIGNMENT_CENTER: 22298 case TEXT_ALIGNMENT_VIEW_START: 22299 case TEXT_ALIGNMENT_VIEW_END: 22300 // Resolved text alignment is the same as the parent resolved 22301 // text alignment 22302 mPrivateFlags2 |= 22303 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22304 break; 22305 default: 22306 // Use default resolved text alignment 22307 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22308 } 22309 break; 22310 case TEXT_ALIGNMENT_GRAVITY: 22311 case TEXT_ALIGNMENT_TEXT_START: 22312 case TEXT_ALIGNMENT_TEXT_END: 22313 case TEXT_ALIGNMENT_CENTER: 22314 case TEXT_ALIGNMENT_VIEW_START: 22315 case TEXT_ALIGNMENT_VIEW_END: 22316 // Resolved text alignment is the same as text alignment 22317 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22318 break; 22319 default: 22320 // Use default resolved text alignment 22321 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22322 } 22323 } else { 22324 // Use default resolved text alignment 22325 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22326 } 22327 22328 // Set the resolved 22329 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22330 return true; 22331 } 22332 22333 /** 22334 * Check if text alignment resolution can be done. 22335 * 22336 * @return true if text alignment resolution can be done otherwise return false. 22337 */ 22338 public boolean canResolveTextAlignment() { 22339 switch (getRawTextAlignment()) { 22340 case TEXT_DIRECTION_INHERIT: 22341 if (mParent != null) { 22342 try { 22343 return mParent.canResolveTextAlignment(); 22344 } catch (AbstractMethodError e) { 22345 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22346 " does not fully implement ViewParent", e); 22347 } 22348 } 22349 return false; 22350 22351 default: 22352 return true; 22353 } 22354 } 22355 22356 /** 22357 * Reset resolved text alignment. Text alignment will be resolved during a call to 22358 * {@link #onMeasure(int, int)}. 22359 * 22360 * @hide 22361 */ 22362 public void resetResolvedTextAlignment() { 22363 // Reset any previous text alignment resolution 22364 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22365 // Set to default 22366 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22367 } 22368 22369 /** 22370 * @return true if text alignment is inherited. 22371 * 22372 * @hide 22373 */ 22374 public boolean isTextAlignmentInherited() { 22375 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 22376 } 22377 22378 /** 22379 * @return true if text alignment is resolved. 22380 */ 22381 public boolean isTextAlignmentResolved() { 22382 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22383 } 22384 22385 /** 22386 * Generate a value suitable for use in {@link #setId(int)}. 22387 * This value will not collide with ID values generated at build time by aapt for R.id. 22388 * 22389 * @return a generated ID value 22390 */ 22391 public static int generateViewId() { 22392 for (;;) { 22393 final int result = sNextGeneratedId.get(); 22394 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 22395 int newValue = result + 1; 22396 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 22397 if (sNextGeneratedId.compareAndSet(result, newValue)) { 22398 return result; 22399 } 22400 } 22401 } 22402 22403 /** 22404 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 22405 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 22406 * a normal View or a ViewGroup with 22407 * {@link android.view.ViewGroup#isTransitionGroup()} true. 22408 * @hide 22409 */ 22410 public void captureTransitioningViews(List<View> transitioningViews) { 22411 if (getVisibility() == View.VISIBLE) { 22412 transitioningViews.add(this); 22413 } 22414 } 22415 22416 /** 22417 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 22418 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 22419 * @hide 22420 */ 22421 public void findNamedViews(Map<String, View> namedElements) { 22422 if (getVisibility() == VISIBLE || mGhostView != null) { 22423 String transitionName = getTransitionName(); 22424 if (transitionName != null) { 22425 namedElements.put(transitionName, this); 22426 } 22427 } 22428 } 22429 22430 /** 22431 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 22432 * The default implementation does not care the location or event types, but some subclasses 22433 * may use it (such as WebViews). 22434 * @param event The MotionEvent from a mouse 22435 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 22436 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 22437 * @see PointerIcon 22438 */ 22439 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 22440 final float x = event.getX(pointerIndex); 22441 final float y = event.getY(pointerIndex); 22442 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 22443 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 22444 } 22445 return mPointerIcon; 22446 } 22447 22448 /** 22449 * Set the pointer icon for the current view. 22450 * Passing {@code null} will restore the pointer icon to its default value. 22451 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 22452 */ 22453 public void setPointerIcon(PointerIcon pointerIcon) { 22454 mPointerIcon = pointerIcon; 22455 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 22456 return; 22457 } 22458 try { 22459 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 22460 } catch (RemoteException e) { 22461 } 22462 } 22463 22464 /** 22465 * Gets the pointer icon for the current view. 22466 */ 22467 public PointerIcon getPointerIcon() { 22468 return mPointerIcon; 22469 } 22470 22471 // 22472 // Properties 22473 // 22474 /** 22475 * A Property wrapper around the <code>alpha</code> functionality handled by the 22476 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 22477 */ 22478 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 22479 @Override 22480 public void setValue(View object, float value) { 22481 object.setAlpha(value); 22482 } 22483 22484 @Override 22485 public Float get(View object) { 22486 return object.getAlpha(); 22487 } 22488 }; 22489 22490 /** 22491 * A Property wrapper around the <code>translationX</code> functionality handled by the 22492 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 22493 */ 22494 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 22495 @Override 22496 public void setValue(View object, float value) { 22497 object.setTranslationX(value); 22498 } 22499 22500 @Override 22501 public Float get(View object) { 22502 return object.getTranslationX(); 22503 } 22504 }; 22505 22506 /** 22507 * A Property wrapper around the <code>translationY</code> functionality handled by the 22508 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 22509 */ 22510 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 22511 @Override 22512 public void setValue(View object, float value) { 22513 object.setTranslationY(value); 22514 } 22515 22516 @Override 22517 public Float get(View object) { 22518 return object.getTranslationY(); 22519 } 22520 }; 22521 22522 /** 22523 * A Property wrapper around the <code>translationZ</code> functionality handled by the 22524 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 22525 */ 22526 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 22527 @Override 22528 public void setValue(View object, float value) { 22529 object.setTranslationZ(value); 22530 } 22531 22532 @Override 22533 public Float get(View object) { 22534 return object.getTranslationZ(); 22535 } 22536 }; 22537 22538 /** 22539 * A Property wrapper around the <code>x</code> functionality handled by the 22540 * {@link View#setX(float)} and {@link View#getX()} methods. 22541 */ 22542 public static final Property<View, Float> X = new FloatProperty<View>("x") { 22543 @Override 22544 public void setValue(View object, float value) { 22545 object.setX(value); 22546 } 22547 22548 @Override 22549 public Float get(View object) { 22550 return object.getX(); 22551 } 22552 }; 22553 22554 /** 22555 * A Property wrapper around the <code>y</code> functionality handled by the 22556 * {@link View#setY(float)} and {@link View#getY()} methods. 22557 */ 22558 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 22559 @Override 22560 public void setValue(View object, float value) { 22561 object.setY(value); 22562 } 22563 22564 @Override 22565 public Float get(View object) { 22566 return object.getY(); 22567 } 22568 }; 22569 22570 /** 22571 * A Property wrapper around the <code>z</code> functionality handled by the 22572 * {@link View#setZ(float)} and {@link View#getZ()} methods. 22573 */ 22574 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 22575 @Override 22576 public void setValue(View object, float value) { 22577 object.setZ(value); 22578 } 22579 22580 @Override 22581 public Float get(View object) { 22582 return object.getZ(); 22583 } 22584 }; 22585 22586 /** 22587 * A Property wrapper around the <code>rotation</code> functionality handled by the 22588 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 22589 */ 22590 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 22591 @Override 22592 public void setValue(View object, float value) { 22593 object.setRotation(value); 22594 } 22595 22596 @Override 22597 public Float get(View object) { 22598 return object.getRotation(); 22599 } 22600 }; 22601 22602 /** 22603 * A Property wrapper around the <code>rotationX</code> functionality handled by the 22604 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 22605 */ 22606 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 22607 @Override 22608 public void setValue(View object, float value) { 22609 object.setRotationX(value); 22610 } 22611 22612 @Override 22613 public Float get(View object) { 22614 return object.getRotationX(); 22615 } 22616 }; 22617 22618 /** 22619 * A Property wrapper around the <code>rotationY</code> functionality handled by the 22620 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 22621 */ 22622 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 22623 @Override 22624 public void setValue(View object, float value) { 22625 object.setRotationY(value); 22626 } 22627 22628 @Override 22629 public Float get(View object) { 22630 return object.getRotationY(); 22631 } 22632 }; 22633 22634 /** 22635 * A Property wrapper around the <code>scaleX</code> functionality handled by the 22636 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 22637 */ 22638 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 22639 @Override 22640 public void setValue(View object, float value) { 22641 object.setScaleX(value); 22642 } 22643 22644 @Override 22645 public Float get(View object) { 22646 return object.getScaleX(); 22647 } 22648 }; 22649 22650 /** 22651 * A Property wrapper around the <code>scaleY</code> functionality handled by the 22652 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 22653 */ 22654 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 22655 @Override 22656 public void setValue(View object, float value) { 22657 object.setScaleY(value); 22658 } 22659 22660 @Override 22661 public Float get(View object) { 22662 return object.getScaleY(); 22663 } 22664 }; 22665 22666 /** 22667 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 22668 * Each MeasureSpec represents a requirement for either the width or the height. 22669 * A MeasureSpec is comprised of a size and a mode. There are three possible 22670 * modes: 22671 * <dl> 22672 * <dt>UNSPECIFIED</dt> 22673 * <dd> 22674 * The parent has not imposed any constraint on the child. It can be whatever size 22675 * it wants. 22676 * </dd> 22677 * 22678 * <dt>EXACTLY</dt> 22679 * <dd> 22680 * The parent has determined an exact size for the child. The child is going to be 22681 * given those bounds regardless of how big it wants to be. 22682 * </dd> 22683 * 22684 * <dt>AT_MOST</dt> 22685 * <dd> 22686 * The child can be as large as it wants up to the specified size. 22687 * </dd> 22688 * </dl> 22689 * 22690 * MeasureSpecs are implemented as ints to reduce object allocation. This class 22691 * is provided to pack and unpack the <size, mode> tuple into the int. 22692 */ 22693 public static class MeasureSpec { 22694 private static final int MODE_SHIFT = 30; 22695 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 22696 22697 /** @hide */ 22698 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 22699 @Retention(RetentionPolicy.SOURCE) 22700 public @interface MeasureSpecMode {} 22701 22702 /** 22703 * Measure specification mode: The parent has not imposed any constraint 22704 * on the child. It can be whatever size it wants. 22705 */ 22706 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 22707 22708 /** 22709 * Measure specification mode: The parent has determined an exact size 22710 * for the child. The child is going to be given those bounds regardless 22711 * of how big it wants to be. 22712 */ 22713 public static final int EXACTLY = 1 << MODE_SHIFT; 22714 22715 /** 22716 * Measure specification mode: The child can be as large as it wants up 22717 * to the specified size. 22718 */ 22719 public static final int AT_MOST = 2 << MODE_SHIFT; 22720 22721 /** 22722 * Creates a measure specification based on the supplied size and mode. 22723 * 22724 * The mode must always be one of the following: 22725 * <ul> 22726 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 22727 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 22728 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 22729 * </ul> 22730 * 22731 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 22732 * implementation was such that the order of arguments did not matter 22733 * and overflow in either value could impact the resulting MeasureSpec. 22734 * {@link android.widget.RelativeLayout} was affected by this bug. 22735 * Apps targeting API levels greater than 17 will get the fixed, more strict 22736 * behavior.</p> 22737 * 22738 * @param size the size of the measure specification 22739 * @param mode the mode of the measure specification 22740 * @return the measure specification based on size and mode 22741 */ 22742 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 22743 @MeasureSpecMode int mode) { 22744 if (sUseBrokenMakeMeasureSpec) { 22745 return size + mode; 22746 } else { 22747 return (size & ~MODE_MASK) | (mode & MODE_MASK); 22748 } 22749 } 22750 22751 /** 22752 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 22753 * will automatically get a size of 0. Older apps expect this. 22754 * 22755 * @hide internal use only for compatibility with system widgets and older apps 22756 */ 22757 public static int makeSafeMeasureSpec(int size, int mode) { 22758 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 22759 return 0; 22760 } 22761 return makeMeasureSpec(size, mode); 22762 } 22763 22764 /** 22765 * Extracts the mode from the supplied measure specification. 22766 * 22767 * @param measureSpec the measure specification to extract the mode from 22768 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 22769 * {@link android.view.View.MeasureSpec#AT_MOST} or 22770 * {@link android.view.View.MeasureSpec#EXACTLY} 22771 */ 22772 @MeasureSpecMode 22773 public static int getMode(int measureSpec) { 22774 //noinspection ResourceType 22775 return (measureSpec & MODE_MASK); 22776 } 22777 22778 /** 22779 * Extracts the size from the supplied measure specification. 22780 * 22781 * @param measureSpec the measure specification to extract the size from 22782 * @return the size in pixels defined in the supplied measure specification 22783 */ 22784 public static int getSize(int measureSpec) { 22785 return (measureSpec & ~MODE_MASK); 22786 } 22787 22788 static int adjust(int measureSpec, int delta) { 22789 final int mode = getMode(measureSpec); 22790 int size = getSize(measureSpec); 22791 if (mode == UNSPECIFIED) { 22792 // No need to adjust size for UNSPECIFIED mode. 22793 return makeMeasureSpec(size, UNSPECIFIED); 22794 } 22795 size += delta; 22796 if (size < 0) { 22797 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 22798 ") spec: " + toString(measureSpec) + " delta: " + delta); 22799 size = 0; 22800 } 22801 return makeMeasureSpec(size, mode); 22802 } 22803 22804 /** 22805 * Returns a String representation of the specified measure 22806 * specification. 22807 * 22808 * @param measureSpec the measure specification to convert to a String 22809 * @return a String with the following format: "MeasureSpec: MODE SIZE" 22810 */ 22811 public static String toString(int measureSpec) { 22812 int mode = getMode(measureSpec); 22813 int size = getSize(measureSpec); 22814 22815 StringBuilder sb = new StringBuilder("MeasureSpec: "); 22816 22817 if (mode == UNSPECIFIED) 22818 sb.append("UNSPECIFIED "); 22819 else if (mode == EXACTLY) 22820 sb.append("EXACTLY "); 22821 else if (mode == AT_MOST) 22822 sb.append("AT_MOST "); 22823 else 22824 sb.append(mode).append(" "); 22825 22826 sb.append(size); 22827 return sb.toString(); 22828 } 22829 } 22830 22831 private final class CheckForLongPress implements Runnable { 22832 private int mOriginalWindowAttachCount; 22833 private float mX; 22834 private float mY; 22835 private boolean mOriginalPressedState; 22836 22837 @Override 22838 public void run() { 22839 if ((mOriginalPressedState == isPressed()) && (mParent != null) 22840 && mOriginalWindowAttachCount == mWindowAttachCount) { 22841 if (performLongClick(mX, mY)) { 22842 mHasPerformedLongPress = true; 22843 } 22844 } 22845 } 22846 22847 public void setAnchor(float x, float y) { 22848 mX = x; 22849 mY = y; 22850 } 22851 22852 public void rememberWindowAttachCount() { 22853 mOriginalWindowAttachCount = mWindowAttachCount; 22854 } 22855 22856 public void rememberPressedState() { 22857 mOriginalPressedState = isPressed(); 22858 } 22859 } 22860 22861 private final class CheckForTap implements Runnable { 22862 public float x; 22863 public float y; 22864 22865 @Override 22866 public void run() { 22867 mPrivateFlags &= ~PFLAG_PREPRESSED; 22868 setPressed(true, x, y); 22869 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 22870 } 22871 } 22872 22873 private final class PerformClick implements Runnable { 22874 @Override 22875 public void run() { 22876 performClick(); 22877 } 22878 } 22879 22880 /** 22881 * This method returns a ViewPropertyAnimator object, which can be used to animate 22882 * specific properties on this View. 22883 * 22884 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 22885 */ 22886 public ViewPropertyAnimator animate() { 22887 if (mAnimator == null) { 22888 mAnimator = new ViewPropertyAnimator(this); 22889 } 22890 return mAnimator; 22891 } 22892 22893 /** 22894 * Sets the name of the View to be used to identify Views in Transitions. 22895 * Names should be unique in the View hierarchy. 22896 * 22897 * @param transitionName The name of the View to uniquely identify it for Transitions. 22898 */ 22899 public final void setTransitionName(String transitionName) { 22900 mTransitionName = transitionName; 22901 } 22902 22903 /** 22904 * Returns the name of the View to be used to identify Views in Transitions. 22905 * Names should be unique in the View hierarchy. 22906 * 22907 * <p>This returns null if the View has not been given a name.</p> 22908 * 22909 * @return The name used of the View to be used to identify Views in Transitions or null 22910 * if no name has been given. 22911 */ 22912 @ViewDebug.ExportedProperty 22913 public String getTransitionName() { 22914 return mTransitionName; 22915 } 22916 22917 /** 22918 * @hide 22919 */ 22920 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 22921 // Do nothing. 22922 } 22923 22924 /** 22925 * Interface definition for a callback to be invoked when a hardware key event is 22926 * dispatched to this view. The callback will be invoked before the key event is 22927 * given to the view. This is only useful for hardware keyboards; a software input 22928 * method has no obligation to trigger this listener. 22929 */ 22930 public interface OnKeyListener { 22931 /** 22932 * Called when a hardware key is dispatched to a view. This allows listeners to 22933 * get a chance to respond before the target view. 22934 * <p>Key presses in software keyboards will generally NOT trigger this method, 22935 * although some may elect to do so in some situations. Do not assume a 22936 * software input method has to be key-based; even if it is, it may use key presses 22937 * in a different way than you expect, so there is no way to reliably catch soft 22938 * input key presses. 22939 * 22940 * @param v The view the key has been dispatched to. 22941 * @param keyCode The code for the physical key that was pressed 22942 * @param event The KeyEvent object containing full information about 22943 * the event. 22944 * @return True if the listener has consumed the event, false otherwise. 22945 */ 22946 boolean onKey(View v, int keyCode, KeyEvent event); 22947 } 22948 22949 /** 22950 * Interface definition for a callback to be invoked when a touch event is 22951 * dispatched to this view. The callback will be invoked before the touch 22952 * event is given to the view. 22953 */ 22954 public interface OnTouchListener { 22955 /** 22956 * Called when a touch event is dispatched to a view. This allows listeners to 22957 * get a chance to respond before the target view. 22958 * 22959 * @param v The view the touch event has been dispatched to. 22960 * @param event The MotionEvent object containing full information about 22961 * the event. 22962 * @return True if the listener has consumed the event, false otherwise. 22963 */ 22964 boolean onTouch(View v, MotionEvent event); 22965 } 22966 22967 /** 22968 * Interface definition for a callback to be invoked when a hover event is 22969 * dispatched to this view. The callback will be invoked before the hover 22970 * event is given to the view. 22971 */ 22972 public interface OnHoverListener { 22973 /** 22974 * Called when a hover event is dispatched to a view. This allows listeners to 22975 * get a chance to respond before the target view. 22976 * 22977 * @param v The view the hover event has been dispatched to. 22978 * @param event The MotionEvent object containing full information about 22979 * the event. 22980 * @return True if the listener has consumed the event, false otherwise. 22981 */ 22982 boolean onHover(View v, MotionEvent event); 22983 } 22984 22985 /** 22986 * Interface definition for a callback to be invoked when a generic motion event is 22987 * dispatched to this view. The callback will be invoked before the generic motion 22988 * event is given to the view. 22989 */ 22990 public interface OnGenericMotionListener { 22991 /** 22992 * Called when a generic motion event is dispatched to a view. This allows listeners to 22993 * get a chance to respond before the target view. 22994 * 22995 * @param v The view the generic motion event has been dispatched to. 22996 * @param event The MotionEvent object containing full information about 22997 * the event. 22998 * @return True if the listener has consumed the event, false otherwise. 22999 */ 23000 boolean onGenericMotion(View v, MotionEvent event); 23001 } 23002 23003 /** 23004 * Interface definition for a callback to be invoked when a view has been clicked and held. 23005 */ 23006 public interface OnLongClickListener { 23007 /** 23008 * Called when a view has been clicked and held. 23009 * 23010 * @param v The view that was clicked and held. 23011 * 23012 * @return true if the callback consumed the long click, false otherwise. 23013 */ 23014 boolean onLongClick(View v); 23015 } 23016 23017 /** 23018 * Interface definition for a callback to be invoked when a drag is being dispatched 23019 * to this view. The callback will be invoked before the hosting view's own 23020 * onDrag(event) method. If the listener wants to fall back to the hosting view's 23021 * onDrag(event) behavior, it should return 'false' from this callback. 23022 * 23023 * <div class="special reference"> 23024 * <h3>Developer Guides</h3> 23025 * <p>For a guide to implementing drag and drop features, read the 23026 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 23027 * </div> 23028 */ 23029 public interface OnDragListener { 23030 /** 23031 * Called when a drag event is dispatched to a view. This allows listeners 23032 * to get a chance to override base View behavior. 23033 * 23034 * @param v The View that received the drag event. 23035 * @param event The {@link android.view.DragEvent} object for the drag event. 23036 * @return {@code true} if the drag event was handled successfully, or {@code false} 23037 * if the drag event was not handled. Note that {@code false} will trigger the View 23038 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 23039 */ 23040 boolean onDrag(View v, DragEvent event); 23041 } 23042 23043 /** 23044 * Interface definition for a callback to be invoked when the focus state of 23045 * a view changed. 23046 */ 23047 public interface OnFocusChangeListener { 23048 /** 23049 * Called when the focus state of a view has changed. 23050 * 23051 * @param v The view whose state has changed. 23052 * @param hasFocus The new focus state of v. 23053 */ 23054 void onFocusChange(View v, boolean hasFocus); 23055 } 23056 23057 /** 23058 * Interface definition for a callback to be invoked when a view is clicked. 23059 */ 23060 public interface OnClickListener { 23061 /** 23062 * Called when a view has been clicked. 23063 * 23064 * @param v The view that was clicked. 23065 */ 23066 void onClick(View v); 23067 } 23068 23069 /** 23070 * Interface definition for a callback to be invoked when a view is context clicked. 23071 */ 23072 public interface OnContextClickListener { 23073 /** 23074 * Called when a view is context clicked. 23075 * 23076 * @param v The view that has been context clicked. 23077 * @return true if the callback consumed the context click, false otherwise. 23078 */ 23079 boolean onContextClick(View v); 23080 } 23081 23082 /** 23083 * Interface definition for a callback to be invoked when the context menu 23084 * for this view is being built. 23085 */ 23086 public interface OnCreateContextMenuListener { 23087 /** 23088 * Called when the context menu for this view is being built. It is not 23089 * safe to hold onto the menu after this method returns. 23090 * 23091 * @param menu The context menu that is being built 23092 * @param v The view for which the context menu is being built 23093 * @param menuInfo Extra information about the item for which the 23094 * context menu should be shown. This information will vary 23095 * depending on the class of v. 23096 */ 23097 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 23098 } 23099 23100 /** 23101 * Interface definition for a callback to be invoked when the status bar changes 23102 * visibility. This reports <strong>global</strong> changes to the system UI 23103 * state, not what the application is requesting. 23104 * 23105 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 23106 */ 23107 public interface OnSystemUiVisibilityChangeListener { 23108 /** 23109 * Called when the status bar changes visibility because of a call to 23110 * {@link View#setSystemUiVisibility(int)}. 23111 * 23112 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 23113 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 23114 * This tells you the <strong>global</strong> state of these UI visibility 23115 * flags, not what your app is currently applying. 23116 */ 23117 public void onSystemUiVisibilityChange(int visibility); 23118 } 23119 23120 /** 23121 * Interface definition for a callback to be invoked when this view is attached 23122 * or detached from its window. 23123 */ 23124 public interface OnAttachStateChangeListener { 23125 /** 23126 * Called when the view is attached to a window. 23127 * @param v The view that was attached 23128 */ 23129 public void onViewAttachedToWindow(View v); 23130 /** 23131 * Called when the view is detached from a window. 23132 * @param v The view that was detached 23133 */ 23134 public void onViewDetachedFromWindow(View v); 23135 } 23136 23137 /** 23138 * Listener for applying window insets on a view in a custom way. 23139 * 23140 * <p>Apps may choose to implement this interface if they want to apply custom policy 23141 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 23142 * is set, its 23143 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 23144 * method will be called instead of the View's own 23145 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 23146 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 23147 * the View's normal behavior as part of its own.</p> 23148 */ 23149 public interface OnApplyWindowInsetsListener { 23150 /** 23151 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 23152 * on a View, this listener method will be called instead of the view's own 23153 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 23154 * 23155 * @param v The view applying window insets 23156 * @param insets The insets to apply 23157 * @return The insets supplied, minus any insets that were consumed 23158 */ 23159 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 23160 } 23161 23162 private final class UnsetPressedState implements Runnable { 23163 @Override 23164 public void run() { 23165 setPressed(false); 23166 } 23167 } 23168 23169 /** 23170 * Base class for derived classes that want to save and restore their own 23171 * state in {@link android.view.View#onSaveInstanceState()}. 23172 */ 23173 public static class BaseSavedState extends AbsSavedState { 23174 String mStartActivityRequestWhoSaved; 23175 23176 /** 23177 * Constructor used when reading from a parcel. Reads the state of the superclass. 23178 * 23179 * @param source parcel to read from 23180 */ 23181 public BaseSavedState(Parcel source) { 23182 this(source, null); 23183 } 23184 23185 /** 23186 * Constructor used when reading from a parcel using a given class loader. 23187 * Reads the state of the superclass. 23188 * 23189 * @param source parcel to read from 23190 * @param loader ClassLoader to use for reading 23191 */ 23192 public BaseSavedState(Parcel source, ClassLoader loader) { 23193 super(source, loader); 23194 mStartActivityRequestWhoSaved = source.readString(); 23195 } 23196 23197 /** 23198 * Constructor called by derived classes when creating their SavedState objects 23199 * 23200 * @param superState The state of the superclass of this view 23201 */ 23202 public BaseSavedState(Parcelable superState) { 23203 super(superState); 23204 } 23205 23206 @Override 23207 public void writeToParcel(Parcel out, int flags) { 23208 super.writeToParcel(out, flags); 23209 out.writeString(mStartActivityRequestWhoSaved); 23210 } 23211 23212 public static final Parcelable.Creator<BaseSavedState> CREATOR 23213 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 23214 @Override 23215 public BaseSavedState createFromParcel(Parcel in) { 23216 return new BaseSavedState(in); 23217 } 23218 23219 @Override 23220 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 23221 return new BaseSavedState(in, loader); 23222 } 23223 23224 @Override 23225 public BaseSavedState[] newArray(int size) { 23226 return new BaseSavedState[size]; 23227 } 23228 }; 23229 } 23230 23231 /** 23232 * A set of information given to a view when it is attached to its parent 23233 * window. 23234 */ 23235 final static class AttachInfo { 23236 interface Callbacks { 23237 void playSoundEffect(int effectId); 23238 boolean performHapticFeedback(int effectId, boolean always); 23239 } 23240 23241 /** 23242 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 23243 * to a Handler. This class contains the target (View) to invalidate and 23244 * the coordinates of the dirty rectangle. 23245 * 23246 * For performance purposes, this class also implements a pool of up to 23247 * POOL_LIMIT objects that get reused. This reduces memory allocations 23248 * whenever possible. 23249 */ 23250 static class InvalidateInfo { 23251 private static final int POOL_LIMIT = 10; 23252 23253 private static final SynchronizedPool<InvalidateInfo> sPool = 23254 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 23255 23256 View target; 23257 23258 int left; 23259 int top; 23260 int right; 23261 int bottom; 23262 23263 public static InvalidateInfo obtain() { 23264 InvalidateInfo instance = sPool.acquire(); 23265 return (instance != null) ? instance : new InvalidateInfo(); 23266 } 23267 23268 public void recycle() { 23269 target = null; 23270 sPool.release(this); 23271 } 23272 } 23273 23274 final IWindowSession mSession; 23275 23276 final IWindow mWindow; 23277 23278 final IBinder mWindowToken; 23279 23280 final Display mDisplay; 23281 23282 final Callbacks mRootCallbacks; 23283 23284 IWindowId mIWindowId; 23285 WindowId mWindowId; 23286 23287 /** 23288 * The top view of the hierarchy. 23289 */ 23290 View mRootView; 23291 23292 IBinder mPanelParentWindowToken; 23293 23294 boolean mHardwareAccelerated; 23295 boolean mHardwareAccelerationRequested; 23296 ThreadedRenderer mThreadedRenderer; 23297 List<RenderNode> mPendingAnimatingRenderNodes; 23298 23299 /** 23300 * The state of the display to which the window is attached, as reported 23301 * by {@link Display#getState()}. Note that the display state constants 23302 * declared by {@link Display} do not exactly line up with the screen state 23303 * constants declared by {@link View} (there are more display states than 23304 * screen states). 23305 */ 23306 int mDisplayState = Display.STATE_UNKNOWN; 23307 23308 /** 23309 * Scale factor used by the compatibility mode 23310 */ 23311 float mApplicationScale; 23312 23313 /** 23314 * Indicates whether the application is in compatibility mode 23315 */ 23316 boolean mScalingRequired; 23317 23318 /** 23319 * Left position of this view's window 23320 */ 23321 int mWindowLeft; 23322 23323 /** 23324 * Top position of this view's window 23325 */ 23326 int mWindowTop; 23327 23328 /** 23329 * Indicates whether views need to use 32-bit drawing caches 23330 */ 23331 boolean mUse32BitDrawingCache; 23332 23333 /** 23334 * For windows that are full-screen but using insets to layout inside 23335 * of the screen areas, these are the current insets to appear inside 23336 * the overscan area of the display. 23337 */ 23338 final Rect mOverscanInsets = new Rect(); 23339 23340 /** 23341 * For windows that are full-screen but using insets to layout inside 23342 * of the screen decorations, these are the current insets for the 23343 * content of the window. 23344 */ 23345 final Rect mContentInsets = new Rect(); 23346 23347 /** 23348 * For windows that are full-screen but using insets to layout inside 23349 * of the screen decorations, these are the current insets for the 23350 * actual visible parts of the window. 23351 */ 23352 final Rect mVisibleInsets = new Rect(); 23353 23354 /** 23355 * For windows that are full-screen but using insets to layout inside 23356 * of the screen decorations, these are the current insets for the 23357 * stable system windows. 23358 */ 23359 final Rect mStableInsets = new Rect(); 23360 23361 /** 23362 * For windows that include areas that are not covered by real surface these are the outsets 23363 * for real surface. 23364 */ 23365 final Rect mOutsets = new Rect(); 23366 23367 /** 23368 * In multi-window we force show the navigation bar. Because we don't want that the surface 23369 * size changes in this mode, we instead have a flag whether the navigation bar size should 23370 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 23371 */ 23372 boolean mAlwaysConsumeNavBar; 23373 23374 /** 23375 * The internal insets given by this window. This value is 23376 * supplied by the client (through 23377 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 23378 * be given to the window manager when changed to be used in laying 23379 * out windows behind it. 23380 */ 23381 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 23382 = new ViewTreeObserver.InternalInsetsInfo(); 23383 23384 /** 23385 * Set to true when mGivenInternalInsets is non-empty. 23386 */ 23387 boolean mHasNonEmptyGivenInternalInsets; 23388 23389 /** 23390 * All views in the window's hierarchy that serve as scroll containers, 23391 * used to determine if the window can be resized or must be panned 23392 * to adjust for a soft input area. 23393 */ 23394 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 23395 23396 final KeyEvent.DispatcherState mKeyDispatchState 23397 = new KeyEvent.DispatcherState(); 23398 23399 /** 23400 * Indicates whether the view's window currently has the focus. 23401 */ 23402 boolean mHasWindowFocus; 23403 23404 /** 23405 * The current visibility of the window. 23406 */ 23407 int mWindowVisibility; 23408 23409 /** 23410 * Indicates the time at which drawing started to occur. 23411 */ 23412 long mDrawingTime; 23413 23414 /** 23415 * Indicates whether or not ignoring the DIRTY_MASK flags. 23416 */ 23417 boolean mIgnoreDirtyState; 23418 23419 /** 23420 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 23421 * to avoid clearing that flag prematurely. 23422 */ 23423 boolean mSetIgnoreDirtyState = false; 23424 23425 /** 23426 * Indicates whether the view's window is currently in touch mode. 23427 */ 23428 boolean mInTouchMode; 23429 23430 /** 23431 * Indicates whether the view has requested unbuffered input dispatching for the current 23432 * event stream. 23433 */ 23434 boolean mUnbufferedDispatchRequested; 23435 23436 /** 23437 * Indicates that ViewAncestor should trigger a global layout change 23438 * the next time it performs a traversal 23439 */ 23440 boolean mRecomputeGlobalAttributes; 23441 23442 /** 23443 * Always report new attributes at next traversal. 23444 */ 23445 boolean mForceReportNewAttributes; 23446 23447 /** 23448 * Set during a traveral if any views want to keep the screen on. 23449 */ 23450 boolean mKeepScreenOn; 23451 23452 /** 23453 * Set during a traveral if the light center needs to be updated. 23454 */ 23455 boolean mNeedsUpdateLightCenter; 23456 23457 /** 23458 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 23459 */ 23460 int mSystemUiVisibility; 23461 23462 /** 23463 * Hack to force certain system UI visibility flags to be cleared. 23464 */ 23465 int mDisabledSystemUiVisibility; 23466 23467 /** 23468 * Last global system UI visibility reported by the window manager. 23469 */ 23470 int mGlobalSystemUiVisibility = -1; 23471 23472 /** 23473 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 23474 * attached. 23475 */ 23476 boolean mHasSystemUiListeners; 23477 23478 /** 23479 * Set if the window has requested to extend into the overscan region 23480 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 23481 */ 23482 boolean mOverscanRequested; 23483 23484 /** 23485 * Set if the visibility of any views has changed. 23486 */ 23487 boolean mViewVisibilityChanged; 23488 23489 /** 23490 * Set to true if a view has been scrolled. 23491 */ 23492 boolean mViewScrollChanged; 23493 23494 /** 23495 * Set to true if high contrast mode enabled 23496 */ 23497 boolean mHighContrastText; 23498 23499 /** 23500 * Set to true if a pointer event is currently being handled. 23501 */ 23502 boolean mHandlingPointerEvent; 23503 23504 /** 23505 * Global to the view hierarchy used as a temporary for dealing with 23506 * x/y points in the transparent region computations. 23507 */ 23508 final int[] mTransparentLocation = new int[2]; 23509 23510 /** 23511 * Global to the view hierarchy used as a temporary for dealing with 23512 * x/y points in the ViewGroup.invalidateChild implementation. 23513 */ 23514 final int[] mInvalidateChildLocation = new int[2]; 23515 23516 /** 23517 * Global to the view hierarchy used as a temporary for dealing with 23518 * computing absolute on-screen location. 23519 */ 23520 final int[] mTmpLocation = new int[2]; 23521 23522 /** 23523 * Global to the view hierarchy used as a temporary for dealing with 23524 * x/y location when view is transformed. 23525 */ 23526 final float[] mTmpTransformLocation = new float[2]; 23527 23528 /** 23529 * The view tree observer used to dispatch global events like 23530 * layout, pre-draw, touch mode change, etc. 23531 */ 23532 final ViewTreeObserver mTreeObserver; 23533 23534 /** 23535 * A Canvas used by the view hierarchy to perform bitmap caching. 23536 */ 23537 Canvas mCanvas; 23538 23539 /** 23540 * The view root impl. 23541 */ 23542 final ViewRootImpl mViewRootImpl; 23543 23544 /** 23545 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 23546 * handler can be used to pump events in the UI events queue. 23547 */ 23548 final Handler mHandler; 23549 23550 /** 23551 * Temporary for use in computing invalidate rectangles while 23552 * calling up the hierarchy. 23553 */ 23554 final Rect mTmpInvalRect = new Rect(); 23555 23556 /** 23557 * Temporary for use in computing hit areas with transformed views 23558 */ 23559 final RectF mTmpTransformRect = new RectF(); 23560 23561 /** 23562 * Temporary for use in computing hit areas with transformed views 23563 */ 23564 final RectF mTmpTransformRect1 = new RectF(); 23565 23566 /** 23567 * Temporary list of rectanges. 23568 */ 23569 final List<RectF> mTmpRectList = new ArrayList<>(); 23570 23571 /** 23572 * Temporary for use in transforming invalidation rect 23573 */ 23574 final Matrix mTmpMatrix = new Matrix(); 23575 23576 /** 23577 * Temporary for use in transforming invalidation rect 23578 */ 23579 final Transformation mTmpTransformation = new Transformation(); 23580 23581 /** 23582 * Temporary for use in querying outlines from OutlineProviders 23583 */ 23584 final Outline mTmpOutline = new Outline(); 23585 23586 /** 23587 * Temporary list for use in collecting focusable descendents of a view. 23588 */ 23589 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 23590 23591 /** 23592 * The id of the window for accessibility purposes. 23593 */ 23594 int mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 23595 23596 /** 23597 * Flags related to accessibility processing. 23598 * 23599 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 23600 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 23601 */ 23602 int mAccessibilityFetchFlags; 23603 23604 /** 23605 * The drawable for highlighting accessibility focus. 23606 */ 23607 Drawable mAccessibilityFocusDrawable; 23608 23609 /** 23610 * Show where the margins, bounds and layout bounds are for each view. 23611 */ 23612 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 23613 23614 /** 23615 * Point used to compute visible regions. 23616 */ 23617 final Point mPoint = new Point(); 23618 23619 /** 23620 * Used to track which View originated a requestLayout() call, used when 23621 * requestLayout() is called during layout. 23622 */ 23623 View mViewRequestingLayout; 23624 23625 /** 23626 * Used to track views that need (at least) a partial relayout at their current size 23627 * during the next traversal. 23628 */ 23629 List<View> mPartialLayoutViews = new ArrayList<>(); 23630 23631 /** 23632 * Swapped with mPartialLayoutViews during layout to avoid concurrent 23633 * modification. Lazily assigned during ViewRootImpl layout. 23634 */ 23635 List<View> mEmptyPartialLayoutViews; 23636 23637 /** 23638 * Used to track the identity of the current drag operation. 23639 */ 23640 IBinder mDragToken; 23641 23642 /** 23643 * The drag shadow surface for the current drag operation. 23644 */ 23645 public Surface mDragSurface; 23646 23647 23648 /** 23649 * The view that currently has a tooltip displayed. 23650 */ 23651 View mTooltipHost; 23652 23653 /** 23654 * Creates a new set of attachment information with the specified 23655 * events handler and thread. 23656 * 23657 * @param handler the events handler the view must use 23658 */ 23659 AttachInfo(IWindowSession session, IWindow window, Display display, 23660 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 23661 Context context) { 23662 mSession = session; 23663 mWindow = window; 23664 mWindowToken = window.asBinder(); 23665 mDisplay = display; 23666 mViewRootImpl = viewRootImpl; 23667 mHandler = handler; 23668 mRootCallbacks = effectPlayer; 23669 mTreeObserver = new ViewTreeObserver(context); 23670 } 23671 } 23672 23673 /** 23674 * <p>ScrollabilityCache holds various fields used by a View when scrolling 23675 * is supported. This avoids keeping too many unused fields in most 23676 * instances of View.</p> 23677 */ 23678 private static class ScrollabilityCache implements Runnable { 23679 23680 /** 23681 * Scrollbars are not visible 23682 */ 23683 public static final int OFF = 0; 23684 23685 /** 23686 * Scrollbars are visible 23687 */ 23688 public static final int ON = 1; 23689 23690 /** 23691 * Scrollbars are fading away 23692 */ 23693 public static final int FADING = 2; 23694 23695 public boolean fadeScrollBars; 23696 23697 public int fadingEdgeLength; 23698 public int scrollBarDefaultDelayBeforeFade; 23699 public int scrollBarFadeDuration; 23700 23701 public int scrollBarSize; 23702 public ScrollBarDrawable scrollBar; 23703 public float[] interpolatorValues; 23704 public View host; 23705 23706 public final Paint paint; 23707 public final Matrix matrix; 23708 public Shader shader; 23709 23710 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 23711 23712 private static final float[] OPAQUE = { 255 }; 23713 private static final float[] TRANSPARENT = { 0.0f }; 23714 23715 /** 23716 * When fading should start. This time moves into the future every time 23717 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 23718 */ 23719 public long fadeStartTime; 23720 23721 23722 /** 23723 * The current state of the scrollbars: ON, OFF, or FADING 23724 */ 23725 public int state = OFF; 23726 23727 private int mLastColor; 23728 23729 public final Rect mScrollBarBounds = new Rect(); 23730 23731 public static final int NOT_DRAGGING = 0; 23732 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 23733 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 23734 public int mScrollBarDraggingState = NOT_DRAGGING; 23735 23736 public float mScrollBarDraggingPos = 0; 23737 23738 public ScrollabilityCache(ViewConfiguration configuration, View host) { 23739 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 23740 scrollBarSize = configuration.getScaledScrollBarSize(); 23741 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 23742 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 23743 23744 paint = new Paint(); 23745 matrix = new Matrix(); 23746 // use use a height of 1, and then wack the matrix each time we 23747 // actually use it. 23748 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 23749 paint.setShader(shader); 23750 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 23751 23752 this.host = host; 23753 } 23754 23755 public void setFadeColor(int color) { 23756 if (color != mLastColor) { 23757 mLastColor = color; 23758 23759 if (color != 0) { 23760 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 23761 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 23762 paint.setShader(shader); 23763 // Restore the default transfer mode (src_over) 23764 paint.setXfermode(null); 23765 } else { 23766 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 23767 paint.setShader(shader); 23768 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 23769 } 23770 } 23771 } 23772 23773 public void run() { 23774 long now = AnimationUtils.currentAnimationTimeMillis(); 23775 if (now >= fadeStartTime) { 23776 23777 // the animation fades the scrollbars out by changing 23778 // the opacity (alpha) from fully opaque to fully 23779 // transparent 23780 int nextFrame = (int) now; 23781 int framesCount = 0; 23782 23783 Interpolator interpolator = scrollBarInterpolator; 23784 23785 // Start opaque 23786 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 23787 23788 // End transparent 23789 nextFrame += scrollBarFadeDuration; 23790 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 23791 23792 state = FADING; 23793 23794 // Kick off the fade animation 23795 host.invalidate(true); 23796 } 23797 } 23798 } 23799 23800 /** 23801 * Resuable callback for sending 23802 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 23803 */ 23804 private class SendViewScrolledAccessibilityEvent implements Runnable { 23805 public volatile boolean mIsPending; 23806 23807 public void run() { 23808 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 23809 mIsPending = false; 23810 } 23811 } 23812 23813 /** 23814 * <p> 23815 * This class represents a delegate that can be registered in a {@link View} 23816 * to enhance accessibility support via composition rather via inheritance. 23817 * It is specifically targeted to widget developers that extend basic View 23818 * classes i.e. classes in package android.view, that would like their 23819 * applications to be backwards compatible. 23820 * </p> 23821 * <div class="special reference"> 23822 * <h3>Developer Guides</h3> 23823 * <p>For more information about making applications accessible, read the 23824 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 23825 * developer guide.</p> 23826 * </div> 23827 * <p> 23828 * A scenario in which a developer would like to use an accessibility delegate 23829 * is overriding a method introduced in a later API version than the minimal API 23830 * version supported by the application. For example, the method 23831 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 23832 * in API version 4 when the accessibility APIs were first introduced. If a 23833 * developer would like his application to run on API version 4 devices (assuming 23834 * all other APIs used by the application are version 4 or lower) and take advantage 23835 * of this method, instead of overriding the method which would break the application's 23836 * backwards compatibility, he can override the corresponding method in this 23837 * delegate and register the delegate in the target View if the API version of 23838 * the system is high enough, i.e. the API version is the same as or higher than the API 23839 * version that introduced 23840 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 23841 * </p> 23842 * <p> 23843 * Here is an example implementation: 23844 * </p> 23845 * <code><pre><p> 23846 * if (Build.VERSION.SDK_INT >= 14) { 23847 * // If the API version is equal of higher than the version in 23848 * // which onInitializeAccessibilityNodeInfo was introduced we 23849 * // register a delegate with a customized implementation. 23850 * View view = findViewById(R.id.view_id); 23851 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 23852 * public void onInitializeAccessibilityNodeInfo(View host, 23853 * AccessibilityNodeInfo info) { 23854 * // Let the default implementation populate the info. 23855 * super.onInitializeAccessibilityNodeInfo(host, info); 23856 * // Set some other information. 23857 * info.setEnabled(host.isEnabled()); 23858 * } 23859 * }); 23860 * } 23861 * </code></pre></p> 23862 * <p> 23863 * This delegate contains methods that correspond to the accessibility methods 23864 * in View. If a delegate has been specified the implementation in View hands 23865 * off handling to the corresponding method in this delegate. The default 23866 * implementation the delegate methods behaves exactly as the corresponding 23867 * method in View for the case of no accessibility delegate been set. Hence, 23868 * to customize the behavior of a View method, clients can override only the 23869 * corresponding delegate method without altering the behavior of the rest 23870 * accessibility related methods of the host view. 23871 * </p> 23872 * <p> 23873 * <strong>Note:</strong> On platform versions prior to 23874 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 23875 * views in the {@code android.widget.*} package are called <i>before</i> 23876 * host methods. This prevents certain properties such as class name from 23877 * being modified by overriding 23878 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 23879 * as any changes will be overwritten by the host class. 23880 * <p> 23881 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 23882 * methods are called <i>after</i> host methods, which all properties to be 23883 * modified without being overwritten by the host class. 23884 */ 23885 public static class AccessibilityDelegate { 23886 23887 /** 23888 * Sends an accessibility event of the given type. If accessibility is not 23889 * enabled this method has no effect. 23890 * <p> 23891 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 23892 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 23893 * been set. 23894 * </p> 23895 * 23896 * @param host The View hosting the delegate. 23897 * @param eventType The type of the event to send. 23898 * 23899 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 23900 */ 23901 public void sendAccessibilityEvent(View host, int eventType) { 23902 host.sendAccessibilityEventInternal(eventType); 23903 } 23904 23905 /** 23906 * Performs the specified accessibility action on the view. For 23907 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 23908 * <p> 23909 * The default implementation behaves as 23910 * {@link View#performAccessibilityAction(int, Bundle) 23911 * View#performAccessibilityAction(int, Bundle)} for the case of 23912 * no accessibility delegate been set. 23913 * </p> 23914 * 23915 * @param action The action to perform. 23916 * @return Whether the action was performed. 23917 * 23918 * @see View#performAccessibilityAction(int, Bundle) 23919 * View#performAccessibilityAction(int, Bundle) 23920 */ 23921 public boolean performAccessibilityAction(View host, int action, Bundle args) { 23922 return host.performAccessibilityActionInternal(action, args); 23923 } 23924 23925 /** 23926 * Sends an accessibility event. This method behaves exactly as 23927 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 23928 * empty {@link AccessibilityEvent} and does not perform a check whether 23929 * accessibility is enabled. 23930 * <p> 23931 * The default implementation behaves as 23932 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 23933 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 23934 * the case of no accessibility delegate been set. 23935 * </p> 23936 * 23937 * @param host The View hosting the delegate. 23938 * @param event The event to send. 23939 * 23940 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 23941 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 23942 */ 23943 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 23944 host.sendAccessibilityEventUncheckedInternal(event); 23945 } 23946 23947 /** 23948 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 23949 * to its children for adding their text content to the event. 23950 * <p> 23951 * The default implementation behaves as 23952 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 23953 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 23954 * the case of no accessibility delegate been set. 23955 * </p> 23956 * 23957 * @param host The View hosting the delegate. 23958 * @param event The event. 23959 * @return True if the event population was completed. 23960 * 23961 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 23962 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 23963 */ 23964 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 23965 return host.dispatchPopulateAccessibilityEventInternal(event); 23966 } 23967 23968 /** 23969 * Gives a chance to the host View to populate the accessibility event with its 23970 * text content. 23971 * <p> 23972 * The default implementation behaves as 23973 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 23974 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 23975 * the case of no accessibility delegate been set. 23976 * </p> 23977 * 23978 * @param host The View hosting the delegate. 23979 * @param event The accessibility event which to populate. 23980 * 23981 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 23982 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 23983 */ 23984 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 23985 host.onPopulateAccessibilityEventInternal(event); 23986 } 23987 23988 /** 23989 * Initializes an {@link AccessibilityEvent} with information about the 23990 * the host View which is the event source. 23991 * <p> 23992 * The default implementation behaves as 23993 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 23994 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 23995 * the case of no accessibility delegate been set. 23996 * </p> 23997 * 23998 * @param host The View hosting the delegate. 23999 * @param event The event to initialize. 24000 * 24001 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 24002 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 24003 */ 24004 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 24005 host.onInitializeAccessibilityEventInternal(event); 24006 } 24007 24008 /** 24009 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 24010 * <p> 24011 * The default implementation behaves as 24012 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24013 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 24014 * the case of no accessibility delegate been set. 24015 * </p> 24016 * 24017 * @param host The View hosting the delegate. 24018 * @param info The instance to initialize. 24019 * 24020 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24021 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24022 */ 24023 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 24024 host.onInitializeAccessibilityNodeInfoInternal(info); 24025 } 24026 24027 /** 24028 * Called when a child of the host View has requested sending an 24029 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 24030 * to augment the event. 24031 * <p> 24032 * The default implementation behaves as 24033 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24034 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 24035 * the case of no accessibility delegate been set. 24036 * </p> 24037 * 24038 * @param host The View hosting the delegate. 24039 * @param child The child which requests sending the event. 24040 * @param event The event to be sent. 24041 * @return True if the event should be sent 24042 * 24043 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24044 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24045 */ 24046 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 24047 AccessibilityEvent event) { 24048 return host.onRequestSendAccessibilityEventInternal(child, event); 24049 } 24050 24051 /** 24052 * Gets the provider for managing a virtual view hierarchy rooted at this View 24053 * and reported to {@link android.accessibilityservice.AccessibilityService}s 24054 * that explore the window content. 24055 * <p> 24056 * The default implementation behaves as 24057 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 24058 * the case of no accessibility delegate been set. 24059 * </p> 24060 * 24061 * @return The provider. 24062 * 24063 * @see AccessibilityNodeProvider 24064 */ 24065 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 24066 return null; 24067 } 24068 24069 /** 24070 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 24071 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 24072 * This method is responsible for obtaining an accessibility node info from a 24073 * pool of reusable instances and calling 24074 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 24075 * view to initialize the former. 24076 * <p> 24077 * <strong>Note:</strong> The client is responsible for recycling the obtained 24078 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 24079 * creation. 24080 * </p> 24081 * <p> 24082 * The default implementation behaves as 24083 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 24084 * the case of no accessibility delegate been set. 24085 * </p> 24086 * @return A populated {@link AccessibilityNodeInfo}. 24087 * 24088 * @see AccessibilityNodeInfo 24089 * 24090 * @hide 24091 */ 24092 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 24093 return host.createAccessibilityNodeInfoInternal(); 24094 } 24095 } 24096 24097 private class MatchIdPredicate implements Predicate<View> { 24098 public int mId; 24099 24100 @Override 24101 public boolean apply(View view) { 24102 return (view.mID == mId); 24103 } 24104 } 24105 24106 private class MatchLabelForPredicate implements Predicate<View> { 24107 private int mLabeledId; 24108 24109 @Override 24110 public boolean apply(View view) { 24111 return (view.mLabelForId == mLabeledId); 24112 } 24113 } 24114 24115 private class SendViewStateChangedAccessibilityEvent implements Runnable { 24116 private int mChangeTypes = 0; 24117 private boolean mPosted; 24118 private boolean mPostedWithDelay; 24119 private long mLastEventTimeMillis; 24120 24121 @Override 24122 public void run() { 24123 mPosted = false; 24124 mPostedWithDelay = false; 24125 mLastEventTimeMillis = SystemClock.uptimeMillis(); 24126 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 24127 final AccessibilityEvent event = AccessibilityEvent.obtain(); 24128 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 24129 event.setContentChangeTypes(mChangeTypes); 24130 sendAccessibilityEventUnchecked(event); 24131 } 24132 mChangeTypes = 0; 24133 } 24134 24135 public void runOrPost(int changeType) { 24136 mChangeTypes |= changeType; 24137 24138 // If this is a live region or the child of a live region, collect 24139 // all events from this frame and send them on the next frame. 24140 if (inLiveRegion()) { 24141 // If we're already posted with a delay, remove that. 24142 if (mPostedWithDelay) { 24143 removeCallbacks(this); 24144 mPostedWithDelay = false; 24145 } 24146 // Only post if we're not already posted. 24147 if (!mPosted) { 24148 post(this); 24149 mPosted = true; 24150 } 24151 return; 24152 } 24153 24154 if (mPosted) { 24155 return; 24156 } 24157 24158 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 24159 final long minEventIntevalMillis = 24160 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 24161 if (timeSinceLastMillis >= minEventIntevalMillis) { 24162 removeCallbacks(this); 24163 run(); 24164 } else { 24165 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 24166 mPostedWithDelay = true; 24167 } 24168 } 24169 } 24170 24171 private boolean inLiveRegion() { 24172 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24173 return true; 24174 } 24175 24176 ViewParent parent = getParent(); 24177 while (parent instanceof View) { 24178 if (((View) parent).getAccessibilityLiveRegion() 24179 != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24180 return true; 24181 } 24182 parent = parent.getParent(); 24183 } 24184 24185 return false; 24186 } 24187 24188 /** 24189 * Dump all private flags in readable format, useful for documentation and 24190 * sanity checking. 24191 */ 24192 private static void dumpFlags() { 24193 final HashMap<String, String> found = Maps.newHashMap(); 24194 try { 24195 for (Field field : View.class.getDeclaredFields()) { 24196 final int modifiers = field.getModifiers(); 24197 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 24198 if (field.getType().equals(int.class)) { 24199 final int value = field.getInt(null); 24200 dumpFlag(found, field.getName(), value); 24201 } else if (field.getType().equals(int[].class)) { 24202 final int[] values = (int[]) field.get(null); 24203 for (int i = 0; i < values.length; i++) { 24204 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 24205 } 24206 } 24207 } 24208 } 24209 } catch (IllegalAccessException e) { 24210 throw new RuntimeException(e); 24211 } 24212 24213 final ArrayList<String> keys = Lists.newArrayList(); 24214 keys.addAll(found.keySet()); 24215 Collections.sort(keys); 24216 for (String key : keys) { 24217 Log.d(VIEW_LOG_TAG, found.get(key)); 24218 } 24219 } 24220 24221 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 24222 // Sort flags by prefix, then by bits, always keeping unique keys 24223 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 24224 final int prefix = name.indexOf('_'); 24225 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 24226 final String output = bits + " " + name; 24227 found.put(key, output); 24228 } 24229 24230 /** {@hide} */ 24231 public void encode(@NonNull ViewHierarchyEncoder stream) { 24232 stream.beginObject(this); 24233 encodeProperties(stream); 24234 stream.endObject(); 24235 } 24236 24237 /** {@hide} */ 24238 @CallSuper 24239 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 24240 Object resolveId = ViewDebug.resolveId(getContext(), mID); 24241 if (resolveId instanceof String) { 24242 stream.addProperty("id", (String) resolveId); 24243 } else { 24244 stream.addProperty("id", mID); 24245 } 24246 24247 stream.addProperty("misc:transformation.alpha", 24248 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 24249 stream.addProperty("misc:transitionName", getTransitionName()); 24250 24251 // layout 24252 stream.addProperty("layout:left", mLeft); 24253 stream.addProperty("layout:right", mRight); 24254 stream.addProperty("layout:top", mTop); 24255 stream.addProperty("layout:bottom", mBottom); 24256 stream.addProperty("layout:width", getWidth()); 24257 stream.addProperty("layout:height", getHeight()); 24258 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 24259 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 24260 stream.addProperty("layout:hasTransientState", hasTransientState()); 24261 stream.addProperty("layout:baseline", getBaseline()); 24262 24263 // layout params 24264 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 24265 if (layoutParams != null) { 24266 stream.addPropertyKey("layoutParams"); 24267 layoutParams.encode(stream); 24268 } 24269 24270 // scrolling 24271 stream.addProperty("scrolling:scrollX", mScrollX); 24272 stream.addProperty("scrolling:scrollY", mScrollY); 24273 24274 // padding 24275 stream.addProperty("padding:paddingLeft", mPaddingLeft); 24276 stream.addProperty("padding:paddingRight", mPaddingRight); 24277 stream.addProperty("padding:paddingTop", mPaddingTop); 24278 stream.addProperty("padding:paddingBottom", mPaddingBottom); 24279 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 24280 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 24281 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 24282 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 24283 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 24284 24285 // measurement 24286 stream.addProperty("measurement:minHeight", mMinHeight); 24287 stream.addProperty("measurement:minWidth", mMinWidth); 24288 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 24289 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 24290 24291 // drawing 24292 stream.addProperty("drawing:elevation", getElevation()); 24293 stream.addProperty("drawing:translationX", getTranslationX()); 24294 stream.addProperty("drawing:translationY", getTranslationY()); 24295 stream.addProperty("drawing:translationZ", getTranslationZ()); 24296 stream.addProperty("drawing:rotation", getRotation()); 24297 stream.addProperty("drawing:rotationX", getRotationX()); 24298 stream.addProperty("drawing:rotationY", getRotationY()); 24299 stream.addProperty("drawing:scaleX", getScaleX()); 24300 stream.addProperty("drawing:scaleY", getScaleY()); 24301 stream.addProperty("drawing:pivotX", getPivotX()); 24302 stream.addProperty("drawing:pivotY", getPivotY()); 24303 stream.addProperty("drawing:opaque", isOpaque()); 24304 stream.addProperty("drawing:alpha", getAlpha()); 24305 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 24306 stream.addProperty("drawing:shadow", hasShadow()); 24307 stream.addProperty("drawing:solidColor", getSolidColor()); 24308 stream.addProperty("drawing:layerType", mLayerType); 24309 stream.addProperty("drawing:willNotDraw", willNotDraw()); 24310 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 24311 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 24312 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 24313 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 24314 24315 // focus 24316 stream.addProperty("focus:hasFocus", hasFocus()); 24317 stream.addProperty("focus:isFocused", isFocused()); 24318 stream.addProperty("focus:isFocusable", isFocusable()); 24319 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 24320 24321 stream.addProperty("misc:clickable", isClickable()); 24322 stream.addProperty("misc:pressed", isPressed()); 24323 stream.addProperty("misc:selected", isSelected()); 24324 stream.addProperty("misc:touchMode", isInTouchMode()); 24325 stream.addProperty("misc:hovered", isHovered()); 24326 stream.addProperty("misc:activated", isActivated()); 24327 24328 stream.addProperty("misc:visibility", getVisibility()); 24329 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 24330 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 24331 24332 stream.addProperty("misc:enabled", isEnabled()); 24333 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 24334 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 24335 24336 // theme attributes 24337 Resources.Theme theme = getContext().getTheme(); 24338 if (theme != null) { 24339 stream.addPropertyKey("theme"); 24340 theme.encode(stream); 24341 } 24342 24343 // view attribute information 24344 int n = mAttributes != null ? mAttributes.length : 0; 24345 stream.addProperty("meta:__attrCount__", n/2); 24346 for (int i = 0; i < n; i += 2) { 24347 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 24348 } 24349 24350 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 24351 24352 // text 24353 stream.addProperty("text:textDirection", getTextDirection()); 24354 stream.addProperty("text:textAlignment", getTextAlignment()); 24355 24356 // accessibility 24357 CharSequence contentDescription = getContentDescription(); 24358 stream.addProperty("accessibility:contentDescription", 24359 contentDescription == null ? "" : contentDescription.toString()); 24360 stream.addProperty("accessibility:labelFor", getLabelFor()); 24361 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 24362 } 24363 24364 /** 24365 * Determine if this view is rendered on a round wearable device and is the main view 24366 * on the screen. 24367 */ 24368 private boolean shouldDrawRoundScrollbar() { 24369 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 24370 return false; 24371 } 24372 24373 final View rootView = getRootView(); 24374 final WindowInsets insets = getRootWindowInsets(); 24375 24376 int height = getHeight(); 24377 int width = getWidth(); 24378 int displayHeight = rootView.getHeight(); 24379 int displayWidth = rootView.getWidth(); 24380 24381 if (height != displayHeight || width != displayWidth) { 24382 return false; 24383 } 24384 24385 getLocationOnScreen(mAttachInfo.mTmpLocation); 24386 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 24387 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 24388 } 24389 24390 /** 24391 * Sets the tooltip text which will be displayed in a small popup next to the view. 24392 * <p> 24393 * The tooltip will be displayed: 24394 * <li>On long click, unless is not handled otherwise (by OnLongClickListener or a context 24395 * menu). </li> 24396 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 24397 * 24398 * @param tooltip the tooltip text, or null if no tooltip is required 24399 */ 24400 public final void setTooltip(@Nullable CharSequence tooltip) { 24401 if (TextUtils.isEmpty(tooltip)) { 24402 setFlags(0, TOOLTIP); 24403 hideTooltip(); 24404 mTooltipInfo = null; 24405 } else { 24406 setFlags(TOOLTIP, TOOLTIP); 24407 if (mTooltipInfo == null) { 24408 mTooltipInfo = new TooltipInfo(); 24409 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 24410 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 24411 } 24412 mTooltipInfo.mTooltip = tooltip; 24413 if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) { 24414 mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltip); 24415 } 24416 } 24417 } 24418 24419 /** 24420 * Returns the view's tooltip text. 24421 * 24422 * @return the tooltip text 24423 */ 24424 @Nullable 24425 public final CharSequence getTooltip() { 24426 return mTooltipInfo != null ? mTooltipInfo.mTooltip : null; 24427 } 24428 24429 private boolean showTooltip(int x, int y, boolean fromLongClick) { 24430 if (mAttachInfo == null) { 24431 return false; 24432 } 24433 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 24434 return false; 24435 } 24436 final CharSequence tooltipText = getTooltip(); 24437 if (TextUtils.isEmpty(tooltipText)) { 24438 return false; 24439 } 24440 hideTooltip(); 24441 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 24442 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 24443 mTooltipInfo.mTooltipPopup.show(this, x, y, tooltipText); 24444 mAttachInfo.mTooltipHost = this; 24445 return true; 24446 } 24447 24448 void hideTooltip() { 24449 if (mTooltipInfo == null) { 24450 return; 24451 } 24452 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24453 if (mTooltipInfo.mTooltipPopup == null) { 24454 return; 24455 } 24456 mTooltipInfo.mTooltipPopup.hide(); 24457 mTooltipInfo.mTooltipPopup = null; 24458 mTooltipInfo.mTooltipFromLongClick = false; 24459 if (mAttachInfo != null) { 24460 mAttachInfo.mTooltipHost = null; 24461 } 24462 } 24463 24464 private boolean showLongClickTooltip(int x, int y) { 24465 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24466 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24467 return showTooltip(x, y, true); 24468 } 24469 24470 private void showHoverTooltip() { 24471 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 24472 } 24473 24474 boolean dispatchTooltipHoverEvent(MotionEvent event) { 24475 if (mTooltipInfo == null) { 24476 return false; 24477 } 24478 switch(event.getAction()) { 24479 case MotionEvent.ACTION_HOVER_MOVE: 24480 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 24481 break; 24482 } 24483 if (!mTooltipInfo.mTooltipFromLongClick) { 24484 if (mTooltipInfo.mTooltipPopup == null) { 24485 // Schedule showing the tooltip after a timeout. 24486 mTooltipInfo.mAnchorX = (int) event.getX(); 24487 mTooltipInfo.mAnchorY = (int) event.getY(); 24488 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24489 postDelayed(mTooltipInfo.mShowTooltipRunnable, 24490 ViewConfiguration.getHoverTooltipShowTimeout()); 24491 } 24492 24493 // Hide hover-triggered tooltip after a period of inactivity. 24494 // Match the timeout used by NativeInputManager to hide the mouse pointer 24495 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 24496 final int timeout; 24497 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 24498 == SYSTEM_UI_FLAG_LOW_PROFILE) { 24499 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 24500 } else { 24501 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 24502 } 24503 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24504 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 24505 } 24506 return true; 24507 24508 case MotionEvent.ACTION_HOVER_EXIT: 24509 if (!mTooltipInfo.mTooltipFromLongClick) { 24510 hideTooltip(); 24511 } 24512 break; 24513 } 24514 return false; 24515 } 24516 24517 void handleTooltipKey(KeyEvent event) { 24518 switch (event.getAction()) { 24519 case KeyEvent.ACTION_DOWN: 24520 if (event.getRepeatCount() == 0) { 24521 hideTooltip(); 24522 } 24523 break; 24524 24525 case KeyEvent.ACTION_UP: 24526 handleTooltipUp(); 24527 break; 24528 } 24529 } 24530 24531 private void handleTooltipUp() { 24532 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 24533 return; 24534 } 24535 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24536 postDelayed(mTooltipInfo.mHideTooltipRunnable, 24537 ViewConfiguration.getLongPressTooltipHideTimeout()); 24538 } 24539 24540 /** 24541 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 24542 * is not showing. 24543 * @hide 24544 */ 24545 @TestApi 24546 public View getTooltipView() { 24547 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 24548 return null; 24549 } 24550 return mTooltipInfo.mTooltipPopup.getContentView(); 24551 } 24552} 24553