View.java revision 37bf8b17364c444aabfcaaed8081b3830202c5e6
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.view; 18 19import static java.lang.Math.max; 20 21import android.animation.AnimatorInflater; 22import android.animation.StateListAnimator; 23import android.annotation.CallSuper; 24import android.annotation.ColorInt; 25import android.annotation.DrawableRes; 26import android.annotation.FloatRange; 27import android.annotation.IdRes; 28import android.annotation.IntDef; 29import android.annotation.IntRange; 30import android.annotation.LayoutRes; 31import android.annotation.NonNull; 32import android.annotation.Nullable; 33import android.annotation.Size; 34import android.annotation.TestApi; 35import android.annotation.UiThread; 36import android.content.ClipData; 37import android.content.Context; 38import android.content.ContextWrapper; 39import android.content.Intent; 40import android.content.res.ColorStateList; 41import android.content.res.Configuration; 42import android.content.res.Resources; 43import android.content.res.TypedArray; 44import android.graphics.Bitmap; 45import android.graphics.Canvas; 46import android.graphics.Color; 47import android.graphics.Insets; 48import android.graphics.Interpolator; 49import android.graphics.LinearGradient; 50import android.graphics.Matrix; 51import android.graphics.Outline; 52import android.graphics.Paint; 53import android.graphics.PixelFormat; 54import android.graphics.Point; 55import android.graphics.PorterDuff; 56import android.graphics.PorterDuffXfermode; 57import android.graphics.Rect; 58import android.graphics.RectF; 59import android.graphics.Region; 60import android.graphics.Shader; 61import android.graphics.drawable.ColorDrawable; 62import android.graphics.drawable.Drawable; 63import android.hardware.display.DisplayManagerGlobal; 64import android.os.Build; 65import android.os.Bundle; 66import android.os.Handler; 67import android.os.IBinder; 68import android.os.Parcel; 69import android.os.Parcelable; 70import android.os.RemoteException; 71import android.os.SystemClock; 72import android.os.SystemProperties; 73import android.os.Trace; 74import android.text.TextUtils; 75import android.util.AttributeSet; 76import android.util.FloatProperty; 77import android.util.LayoutDirection; 78import android.util.Log; 79import android.util.LongSparseLongArray; 80import android.util.Pools.SynchronizedPool; 81import android.util.Property; 82import android.util.SparseArray; 83import android.util.StateSet; 84import android.util.SuperNotCalledException; 85import android.util.TypedValue; 86import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 87import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 88import android.view.AccessibilityIterators.TextSegmentIterator; 89import android.view.AccessibilityIterators.WordTextSegmentIterator; 90import android.view.ContextMenu.ContextMenuInfo; 91import android.view.accessibility.AccessibilityEvent; 92import android.view.accessibility.AccessibilityEventSource; 93import android.view.accessibility.AccessibilityManager; 94import android.view.accessibility.AccessibilityNodeInfo; 95import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 96import android.view.accessibility.AccessibilityNodeProvider; 97import android.view.accessibility.AccessibilityWindowInfo; 98import android.view.animation.Animation; 99import android.view.animation.AnimationUtils; 100import android.view.animation.Transformation; 101import android.view.autofill.AutofillManager; 102import android.view.autofill.AutofillValue; 103import android.view.inputmethod.EditorInfo; 104import android.view.inputmethod.InputConnection; 105import android.view.inputmethod.InputMethodManager; 106import android.widget.Checkable; 107import android.widget.FrameLayout; 108import android.widget.ScrollBarDrawable; 109 110import com.android.internal.R; 111import com.android.internal.util.Preconditions; 112import com.android.internal.view.TooltipPopup; 113import com.android.internal.view.menu.MenuBuilder; 114import com.android.internal.widget.ScrollBarUtils; 115 116import com.google.android.collect.Lists; 117import com.google.android.collect.Maps; 118 119import java.lang.annotation.Retention; 120import java.lang.annotation.RetentionPolicy; 121import java.lang.ref.WeakReference; 122import java.lang.reflect.Field; 123import java.lang.reflect.InvocationTargetException; 124import java.lang.reflect.Method; 125import java.lang.reflect.Modifier; 126import java.util.ArrayList; 127import java.util.Arrays; 128import java.util.Collection; 129import java.util.Collections; 130import java.util.HashMap; 131import java.util.List; 132import java.util.Locale; 133import java.util.Map; 134import java.util.concurrent.CopyOnWriteArrayList; 135import java.util.concurrent.atomic.AtomicInteger; 136import java.util.function.Predicate; 137 138/** 139 * <p> 140 * This class represents the basic building block for user interface components. A View 141 * occupies a rectangular area on the screen and is responsible for drawing and 142 * event handling. View is the base class for <em>widgets</em>, which are 143 * used to create interactive UI components (buttons, text fields, etc.). The 144 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 145 * are invisible containers that hold other Views (or other ViewGroups) and define 146 * their layout properties. 147 * </p> 148 * 149 * <div class="special reference"> 150 * <h3>Developer Guides</h3> 151 * <p>For information about using this class to develop your application's user interface, 152 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 153 * </div> 154 * 155 * <a name="Using"></a> 156 * <h3>Using Views</h3> 157 * <p> 158 * All of the views in a window are arranged in a single tree. You can add views 159 * either from code or by specifying a tree of views in one or more XML layout 160 * files. There are many specialized subclasses of views that act as controls or 161 * are capable of displaying text, images, or other content. 162 * </p> 163 * <p> 164 * Once you have created a tree of views, there are typically a few types of 165 * common operations you may wish to perform: 166 * <ul> 167 * <li><strong>Set properties:</strong> for example setting the text of a 168 * {@link android.widget.TextView}. The available properties and the methods 169 * that set them will vary among the different subclasses of views. Note that 170 * properties that are known at build time can be set in the XML layout 171 * files.</li> 172 * <li><strong>Set focus:</strong> The framework will handle moving focus in 173 * response to user input. To force focus to a specific view, call 174 * {@link #requestFocus}.</li> 175 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 176 * that will be notified when something interesting happens to the view. For 177 * example, all views will let you set a listener to be notified when the view 178 * gains or loses focus. You can register such a listener using 179 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 180 * Other view subclasses offer more specialized listeners. For example, a Button 181 * exposes a listener to notify clients when the button is clicked.</li> 182 * <li><strong>Set visibility:</strong> You can hide or show views using 183 * {@link #setVisibility(int)}.</li> 184 * </ul> 185 * </p> 186 * <p><em> 187 * Note: The Android framework is responsible for measuring, laying out and 188 * drawing views. You should not call methods that perform these actions on 189 * views yourself unless you are actually implementing a 190 * {@link android.view.ViewGroup}. 191 * </em></p> 192 * 193 * <a name="Lifecycle"></a> 194 * <h3>Implementing a Custom View</h3> 195 * 196 * <p> 197 * To implement a custom view, you will usually begin by providing overrides for 198 * some of the standard methods that the framework calls on all views. You do 199 * not need to override all of these methods. In fact, you can start by just 200 * overriding {@link #onDraw(android.graphics.Canvas)}. 201 * <table border="2" width="85%" align="center" cellpadding="5"> 202 * <thead> 203 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 204 * </thead> 205 * 206 * <tbody> 207 * <tr> 208 * <td rowspan="2">Creation</td> 209 * <td>Constructors</td> 210 * <td>There is a form of the constructor that are called when the view 211 * is created from code and a form that is called when the view is 212 * inflated from a layout file. The second form should parse and apply 213 * any attributes defined in the layout file. 214 * </td> 215 * </tr> 216 * <tr> 217 * <td><code>{@link #onFinishInflate()}</code></td> 218 * <td>Called after a view and all of its children has been inflated 219 * from XML.</td> 220 * </tr> 221 * 222 * <tr> 223 * <td rowspan="3">Layout</td> 224 * <td><code>{@link #onMeasure(int, int)}</code></td> 225 * <td>Called to determine the size requirements for this view and all 226 * of its children. 227 * </td> 228 * </tr> 229 * <tr> 230 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 231 * <td>Called when this view should assign a size and position to all 232 * of its children. 233 * </td> 234 * </tr> 235 * <tr> 236 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 237 * <td>Called when the size of this view has changed. 238 * </td> 239 * </tr> 240 * 241 * <tr> 242 * <td>Drawing</td> 243 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 244 * <td>Called when the view should render its content. 245 * </td> 246 * </tr> 247 * 248 * <tr> 249 * <td rowspan="4">Event processing</td> 250 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 251 * <td>Called when a new hardware key event occurs. 252 * </td> 253 * </tr> 254 * <tr> 255 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 256 * <td>Called when a hardware key up event occurs. 257 * </td> 258 * </tr> 259 * <tr> 260 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 261 * <td>Called when a trackball motion event occurs. 262 * </td> 263 * </tr> 264 * <tr> 265 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 266 * <td>Called when a touch screen motion event occurs. 267 * </td> 268 * </tr> 269 * 270 * <tr> 271 * <td rowspan="2">Focus</td> 272 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 273 * <td>Called when the view gains or loses focus. 274 * </td> 275 * </tr> 276 * 277 * <tr> 278 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 279 * <td>Called when the window containing the view gains or loses focus. 280 * </td> 281 * </tr> 282 * 283 * <tr> 284 * <td rowspan="3">Attaching</td> 285 * <td><code>{@link #onAttachedToWindow()}</code></td> 286 * <td>Called when the view is attached to a window. 287 * </td> 288 * </tr> 289 * 290 * <tr> 291 * <td><code>{@link #onDetachedFromWindow}</code></td> 292 * <td>Called when the view is detached from its window. 293 * </td> 294 * </tr> 295 * 296 * <tr> 297 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 298 * <td>Called when the visibility of the window containing the view 299 * has changed. 300 * </td> 301 * </tr> 302 * </tbody> 303 * 304 * </table> 305 * </p> 306 * 307 * <a name="IDs"></a> 308 * <h3>IDs</h3> 309 * Views may have an integer id associated with them. These ids are typically 310 * assigned in the layout XML files, and are used to find specific views within 311 * the view tree. A common pattern is to: 312 * <ul> 313 * <li>Define a Button in the layout file and assign it a unique ID. 314 * <pre> 315 * <Button 316 * android:id="@+id/my_button" 317 * android:layout_width="wrap_content" 318 * android:layout_height="wrap_content" 319 * android:text="@string/my_button_text"/> 320 * </pre></li> 321 * <li>From the onCreate method of an Activity, find the Button 322 * <pre class="prettyprint"> 323 * Button myButton = (Button) findViewById(R.id.my_button); 324 * </pre></li> 325 * </ul> 326 * <p> 327 * View IDs need not be unique throughout the tree, but it is good practice to 328 * ensure that they are at least unique within the part of the tree you are 329 * searching. 330 * </p> 331 * 332 * <a name="Position"></a> 333 * <h3>Position</h3> 334 * <p> 335 * The geometry of a view is that of a rectangle. A view has a location, 336 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 337 * two dimensions, expressed as a width and a height. The unit for location 338 * and dimensions is the pixel. 339 * </p> 340 * 341 * <p> 342 * It is possible to retrieve the location of a view by invoking the methods 343 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 344 * coordinate of the rectangle representing the view. The latter returns the 345 * top, or Y, coordinate of the rectangle representing the view. These methods 346 * both return the location of the view relative to its parent. For instance, 347 * when getLeft() returns 20, that means the view is located 20 pixels to the 348 * right of the left edge of its direct parent. 349 * </p> 350 * 351 * <p> 352 * In addition, several convenience methods are offered to avoid unnecessary 353 * computations, namely {@link #getRight()} and {@link #getBottom()}. 354 * These methods return the coordinates of the right and bottom edges of the 355 * rectangle representing the view. For instance, calling {@link #getRight()} 356 * is similar to the following computation: <code>getLeft() + getWidth()</code> 357 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 358 * </p> 359 * 360 * <a name="SizePaddingMargins"></a> 361 * <h3>Size, padding and margins</h3> 362 * <p> 363 * The size of a view is expressed with a width and a height. A view actually 364 * possess two pairs of width and height values. 365 * </p> 366 * 367 * <p> 368 * The first pair is known as <em>measured width</em> and 369 * <em>measured height</em>. These dimensions define how big a view wants to be 370 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 371 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 372 * and {@link #getMeasuredHeight()}. 373 * </p> 374 * 375 * <p> 376 * The second pair is simply known as <em>width</em> and <em>height</em>, or 377 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 378 * dimensions define the actual size of the view on screen, at drawing time and 379 * after layout. These values may, but do not have to, be different from the 380 * measured width and height. The width and height can be obtained by calling 381 * {@link #getWidth()} and {@link #getHeight()}. 382 * </p> 383 * 384 * <p> 385 * To measure its dimensions, a view takes into account its padding. The padding 386 * is expressed in pixels for the left, top, right and bottom parts of the view. 387 * Padding can be used to offset the content of the view by a specific amount of 388 * pixels. For instance, a left padding of 2 will push the view's content by 389 * 2 pixels to the right of the left edge. Padding can be set using the 390 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 391 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 392 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 393 * {@link #getPaddingEnd()}. 394 * </p> 395 * 396 * <p> 397 * Even though a view can define a padding, it does not provide any support for 398 * margins. However, view groups provide such a support. Refer to 399 * {@link android.view.ViewGroup} and 400 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 401 * </p> 402 * 403 * <a name="Layout"></a> 404 * <h3>Layout</h3> 405 * <p> 406 * Layout is a two pass process: a measure pass and a layout pass. The measuring 407 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 408 * of the view tree. Each view pushes dimension specifications down the tree 409 * during the recursion. At the end of the measure pass, every view has stored 410 * its measurements. The second pass happens in 411 * {@link #layout(int,int,int,int)} and is also top-down. During 412 * this pass each parent is responsible for positioning all of its children 413 * using the sizes computed in the measure pass. 414 * </p> 415 * 416 * <p> 417 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 418 * {@link #getMeasuredHeight()} values must be set, along with those for all of 419 * that view's descendants. A view's measured width and measured height values 420 * must respect the constraints imposed by the view's parents. This guarantees 421 * that at the end of the measure pass, all parents accept all of their 422 * children's measurements. A parent view may call measure() more than once on 423 * its children. For example, the parent may measure each child once with 424 * unspecified dimensions to find out how big they want to be, then call 425 * measure() on them again with actual numbers if the sum of all the children's 426 * unconstrained sizes is too big or too small. 427 * </p> 428 * 429 * <p> 430 * The measure pass uses two classes to communicate dimensions. The 431 * {@link MeasureSpec} class is used by views to tell their parents how they 432 * want to be measured and positioned. The base LayoutParams class just 433 * describes how big the view wants to be for both width and height. For each 434 * dimension, it can specify one of: 435 * <ul> 436 * <li> an exact number 437 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 438 * (minus padding) 439 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 440 * enclose its content (plus padding). 441 * </ul> 442 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 443 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 444 * an X and Y value. 445 * </p> 446 * 447 * <p> 448 * MeasureSpecs are used to push requirements down the tree from parent to 449 * child. A MeasureSpec can be in one of three modes: 450 * <ul> 451 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 452 * of a child view. For example, a LinearLayout may call measure() on its child 453 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 454 * tall the child view wants to be given a width of 240 pixels. 455 * <li>EXACTLY: This is used by the parent to impose an exact size on the 456 * child. The child must use this size, and guarantee that all of its 457 * descendants will fit within this size. 458 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 459 * child. The child must guarantee that it and all of its descendants will fit 460 * within this size. 461 * </ul> 462 * </p> 463 * 464 * <p> 465 * To initiate a layout, call {@link #requestLayout}. This method is typically 466 * called by a view on itself when it believes that is can no longer fit within 467 * its current bounds. 468 * </p> 469 * 470 * <a name="Drawing"></a> 471 * <h3>Drawing</h3> 472 * <p> 473 * Drawing is handled by walking the tree and recording the drawing commands of 474 * any View that needs to update. After this, the drawing commands of the 475 * entire tree are issued to screen, clipped to the newly damaged area. 476 * </p> 477 * 478 * <p> 479 * The tree is largely recorded and drawn in order, with parents drawn before 480 * (i.e., behind) their children, with siblings drawn in the order they appear 481 * in the tree. If you set a background drawable for a View, then the View will 482 * draw it before calling back to its <code>onDraw()</code> method. The child 483 * drawing order can be overridden with 484 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 485 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 486 * </p> 487 * 488 * <p> 489 * To force a view to draw, call {@link #invalidate()}. 490 * </p> 491 * 492 * <a name="EventHandlingThreading"></a> 493 * <h3>Event Handling and Threading</h3> 494 * <p> 495 * The basic cycle of a view is as follows: 496 * <ol> 497 * <li>An event comes in and is dispatched to the appropriate view. The view 498 * handles the event and notifies any listeners.</li> 499 * <li>If in the course of processing the event, the view's bounds may need 500 * to be changed, the view will call {@link #requestLayout()}.</li> 501 * <li>Similarly, if in the course of processing the event the view's appearance 502 * may need to be changed, the view will call {@link #invalidate()}.</li> 503 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 504 * the framework will take care of measuring, laying out, and drawing the tree 505 * as appropriate.</li> 506 * </ol> 507 * </p> 508 * 509 * <p><em>Note: The entire view tree is single threaded. You must always be on 510 * the UI thread when calling any method on any view.</em> 511 * If you are doing work on other threads and want to update the state of a view 512 * from that thread, you should use a {@link Handler}. 513 * </p> 514 * 515 * <a name="FocusHandling"></a> 516 * <h3>Focus Handling</h3> 517 * <p> 518 * The framework will handle routine focus movement in response to user input. 519 * This includes changing the focus as views are removed or hidden, or as new 520 * views become available. Views indicate their willingness to take focus 521 * through the {@link #isFocusable} method. To change whether a view can take 522 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 523 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 524 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 525 * </p> 526 * <p> 527 * Focus movement is based on an algorithm which finds the nearest neighbor in a 528 * given direction. In rare cases, the default algorithm may not match the 529 * intended behavior of the developer. In these situations, you can provide 530 * explicit overrides by using these XML attributes in the layout file: 531 * <pre> 532 * nextFocusDown 533 * nextFocusLeft 534 * nextFocusRight 535 * nextFocusUp 536 * </pre> 537 * </p> 538 * 539 * 540 * <p> 541 * To get a particular view to take focus, call {@link #requestFocus()}. 542 * </p> 543 * 544 * <a name="TouchMode"></a> 545 * <h3>Touch Mode</h3> 546 * <p> 547 * When a user is navigating a user interface via directional keys such as a D-pad, it is 548 * necessary to give focus to actionable items such as buttons so the user can see 549 * what will take input. If the device has touch capabilities, however, and the user 550 * begins interacting with the interface by touching it, it is no longer necessary to 551 * always highlight, or give focus to, a particular view. This motivates a mode 552 * for interaction named 'touch mode'. 553 * </p> 554 * <p> 555 * For a touch capable device, once the user touches the screen, the device 556 * will enter touch mode. From this point onward, only views for which 557 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 558 * Other views that are touchable, like buttons, will not take focus when touched; they will 559 * only fire the on click listeners. 560 * </p> 561 * <p> 562 * Any time a user hits a directional key, such as a D-pad direction, the view device will 563 * exit touch mode, and find a view to take focus, so that the user may resume interacting 564 * with the user interface without touching the screen again. 565 * </p> 566 * <p> 567 * The touch mode state is maintained across {@link android.app.Activity}s. Call 568 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 569 * </p> 570 * 571 * <a name="Scrolling"></a> 572 * <h3>Scrolling</h3> 573 * <p> 574 * The framework provides basic support for views that wish to internally 575 * scroll their content. This includes keeping track of the X and Y scroll 576 * offset as well as mechanisms for drawing scrollbars. See 577 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 578 * {@link #awakenScrollBars()} for more details. 579 * </p> 580 * 581 * <a name="Tags"></a> 582 * <h3>Tags</h3> 583 * <p> 584 * Unlike IDs, tags are not used to identify views. Tags are essentially an 585 * extra piece of information that can be associated with a view. They are most 586 * often used as a convenience to store data related to views in the views 587 * themselves rather than by putting them in a separate structure. 588 * </p> 589 * <p> 590 * Tags may be specified with character sequence values in layout XML as either 591 * a single tag using the {@link android.R.styleable#View_tag android:tag} 592 * attribute or multiple tags using the {@code <tag>} child element: 593 * <pre> 594 * <View ... 595 * android:tag="@string/mytag_value" /> 596 * <View ...> 597 * <tag android:id="@+id/mytag" 598 * android:value="@string/mytag_value" /> 599 * </View> 600 * </pre> 601 * </p> 602 * <p> 603 * Tags may also be specified with arbitrary objects from code using 604 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 605 * </p> 606 * 607 * <a name="Themes"></a> 608 * <h3>Themes</h3> 609 * <p> 610 * By default, Views are created using the theme of the Context object supplied 611 * to their constructor; however, a different theme may be specified by using 612 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 613 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 614 * code. 615 * </p> 616 * <p> 617 * When the {@link android.R.styleable#View_theme android:theme} attribute is 618 * used in XML, the specified theme is applied on top of the inflation 619 * context's theme (see {@link LayoutInflater}) and used for the view itself as 620 * well as any child elements. 621 * </p> 622 * <p> 623 * In the following example, both views will be created using the Material dark 624 * color scheme; however, because an overlay theme is used which only defines a 625 * subset of attributes, the value of 626 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 627 * the inflation context's theme (e.g. the Activity theme) will be preserved. 628 * <pre> 629 * <LinearLayout 630 * ... 631 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 632 * <View ...> 633 * </LinearLayout> 634 * </pre> 635 * </p> 636 * 637 * <a name="Properties"></a> 638 * <h3>Properties</h3> 639 * <p> 640 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 641 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 642 * available both in the {@link Property} form as well as in similarly-named setter/getter 643 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 644 * be used to set persistent state associated with these rendering-related properties on the view. 645 * The properties and methods can also be used in conjunction with 646 * {@link android.animation.Animator Animator}-based animations, described more in the 647 * <a href="#Animation">Animation</a> section. 648 * </p> 649 * 650 * <a name="Animation"></a> 651 * <h3>Animation</h3> 652 * <p> 653 * Starting with Android 3.0, the preferred way of animating views is to use the 654 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 655 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 656 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 657 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 658 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 659 * makes animating these View properties particularly easy and efficient. 660 * </p> 661 * <p> 662 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 663 * You can attach an {@link Animation} object to a view using 664 * {@link #setAnimation(Animation)} or 665 * {@link #startAnimation(Animation)}. The animation can alter the scale, 666 * rotation, translation and alpha of a view over time. If the animation is 667 * attached to a view that has children, the animation will affect the entire 668 * subtree rooted by that node. When an animation is started, the framework will 669 * take care of redrawing the appropriate views until the animation completes. 670 * </p> 671 * 672 * <a name="Security"></a> 673 * <h3>Security</h3> 674 * <p> 675 * Sometimes it is essential that an application be able to verify that an action 676 * is being performed with the full knowledge and consent of the user, such as 677 * granting a permission request, making a purchase or clicking on an advertisement. 678 * Unfortunately, a malicious application could try to spoof the user into 679 * performing these actions, unaware, by concealing the intended purpose of the view. 680 * As a remedy, the framework offers a touch filtering mechanism that can be used to 681 * improve the security of views that provide access to sensitive functionality. 682 * </p><p> 683 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 684 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 685 * will discard touches that are received whenever the view's window is obscured by 686 * another visible window. As a result, the view will not receive touches whenever a 687 * toast, dialog or other window appears above the view's window. 688 * </p><p> 689 * For more fine-grained control over security, consider overriding the 690 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 691 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 692 * </p> 693 * 694 * @attr ref android.R.styleable#View_alpha 695 * @attr ref android.R.styleable#View_background 696 * @attr ref android.R.styleable#View_clickable 697 * @attr ref android.R.styleable#View_contentDescription 698 * @attr ref android.R.styleable#View_drawingCacheQuality 699 * @attr ref android.R.styleable#View_duplicateParentState 700 * @attr ref android.R.styleable#View_id 701 * @attr ref android.R.styleable#View_requiresFadingEdge 702 * @attr ref android.R.styleable#View_fadeScrollbars 703 * @attr ref android.R.styleable#View_fadingEdgeLength 704 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 705 * @attr ref android.R.styleable#View_fitsSystemWindows 706 * @attr ref android.R.styleable#View_isScrollContainer 707 * @attr ref android.R.styleable#View_focusable 708 * @attr ref android.R.styleable#View_focusableInTouchMode 709 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 710 * @attr ref android.R.styleable#View_keepScreenOn 711 * @attr ref android.R.styleable#View_layerType 712 * @attr ref android.R.styleable#View_layoutDirection 713 * @attr ref android.R.styleable#View_longClickable 714 * @attr ref android.R.styleable#View_minHeight 715 * @attr ref android.R.styleable#View_minWidth 716 * @attr ref android.R.styleable#View_nextFocusDown 717 * @attr ref android.R.styleable#View_nextFocusLeft 718 * @attr ref android.R.styleable#View_nextFocusRight 719 * @attr ref android.R.styleable#View_nextFocusUp 720 * @attr ref android.R.styleable#View_onClick 721 * @attr ref android.R.styleable#View_padding 722 * @attr ref android.R.styleable#View_paddingBottom 723 * @attr ref android.R.styleable#View_paddingLeft 724 * @attr ref android.R.styleable#View_paddingRight 725 * @attr ref android.R.styleable#View_paddingTop 726 * @attr ref android.R.styleable#View_paddingStart 727 * @attr ref android.R.styleable#View_paddingEnd 728 * @attr ref android.R.styleable#View_saveEnabled 729 * @attr ref android.R.styleable#View_rotation 730 * @attr ref android.R.styleable#View_rotationX 731 * @attr ref android.R.styleable#View_rotationY 732 * @attr ref android.R.styleable#View_scaleX 733 * @attr ref android.R.styleable#View_scaleY 734 * @attr ref android.R.styleable#View_scrollX 735 * @attr ref android.R.styleable#View_scrollY 736 * @attr ref android.R.styleable#View_scrollbarSize 737 * @attr ref android.R.styleable#View_scrollbarStyle 738 * @attr ref android.R.styleable#View_scrollbars 739 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 740 * @attr ref android.R.styleable#View_scrollbarFadeDuration 741 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 742 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 743 * @attr ref android.R.styleable#View_scrollbarThumbVertical 744 * @attr ref android.R.styleable#View_scrollbarTrackVertical 745 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 746 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 747 * @attr ref android.R.styleable#View_stateListAnimator 748 * @attr ref android.R.styleable#View_transitionName 749 * @attr ref android.R.styleable#View_soundEffectsEnabled 750 * @attr ref android.R.styleable#View_tag 751 * @attr ref android.R.styleable#View_textAlignment 752 * @attr ref android.R.styleable#View_textDirection 753 * @attr ref android.R.styleable#View_transformPivotX 754 * @attr ref android.R.styleable#View_transformPivotY 755 * @attr ref android.R.styleable#View_translationX 756 * @attr ref android.R.styleable#View_translationY 757 * @attr ref android.R.styleable#View_translationZ 758 * @attr ref android.R.styleable#View_visibility 759 * @attr ref android.R.styleable#View_theme 760 * 761 * @see android.view.ViewGroup 762 */ 763@UiThread 764public class View implements Drawable.Callback, KeyEvent.Callback, 765 AccessibilityEventSource { 766 private static final boolean DBG = false; 767 768 /** @hide */ 769 public static boolean DEBUG_DRAW = false; 770 771 /** 772 * The logging tag used by this class with android.util.Log. 773 */ 774 protected static final String VIEW_LOG_TAG = "View"; 775 776 /** 777 * When set to true, apps will draw debugging information about their layouts. 778 * 779 * @hide 780 */ 781 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 782 783 /** 784 * When set to true, this view will save its attribute data. 785 * 786 * @hide 787 */ 788 public static boolean mDebugViewAttributes = false; 789 790 /** 791 * Used to mark a View that has no ID. 792 */ 793 public static final int NO_ID = -1; 794 795 /** 796 * Signals that compatibility booleans have been initialized according to 797 * target SDK versions. 798 */ 799 private static boolean sCompatibilityDone = false; 800 801 /** 802 * Use the old (broken) way of building MeasureSpecs. 803 */ 804 private static boolean sUseBrokenMakeMeasureSpec = false; 805 806 /** 807 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 808 */ 809 static boolean sUseZeroUnspecifiedMeasureSpec = false; 810 811 /** 812 * Ignore any optimizations using the measure cache. 813 */ 814 private static boolean sIgnoreMeasureCache = false; 815 816 /** 817 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 818 */ 819 private static boolean sAlwaysRemeasureExactly = false; 820 821 /** 822 * Relax constraints around whether setLayoutParams() must be called after 823 * modifying the layout params. 824 */ 825 private static boolean sLayoutParamsAlwaysChanged = false; 826 827 /** 828 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 829 * without throwing 830 */ 831 static boolean sTextureViewIgnoresDrawableSetters = false; 832 833 /** 834 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 835 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 836 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 837 * check is implemented for backwards compatibility. 838 * 839 * {@hide} 840 */ 841 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 842 843 /** 844 * Prior to N, when drag enters into child of a view that has already received an 845 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 846 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 847 * false from its event handler for these events. 848 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 849 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 850 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 851 */ 852 static boolean sCascadedDragDrop; 853 854 /** 855 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 856 * to determine things like whether or not to permit item click events. We can't break 857 * apps that do this just because more things (clickable things) are now auto-focusable 858 * and they would get different results, so give old behavior to old apps. 859 */ 860 static boolean sHasFocusableExcludeAutoFocusable; 861 862 /** 863 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 864 * made focusable by default. As a result, apps could (incorrectly) change the clickable 865 * setting of views off the UI thread. Now that clickable can effect the focusable state, 866 * changing the clickable attribute off the UI thread will cause an exception (since changing 867 * the focusable state checks). In order to prevent apps from crashing, we will handle this 868 * specific case and just not notify parents on new focusables resulting from marking views 869 * clickable from outside the UI thread. 870 */ 871 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 872 873 /** @hide */ 874 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 875 @Retention(RetentionPolicy.SOURCE) 876 public @interface Focusable {} 877 878 /** 879 * This view does not want keystrokes. 880 * <p> 881 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 882 * android:focusable}. 883 */ 884 public static final int NOT_FOCUSABLE = 0x00000000; 885 886 /** 887 * This view wants keystrokes. 888 * <p> 889 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 890 * android:focusable}. 891 */ 892 public static final int FOCUSABLE = 0x00000001; 893 894 /** 895 * This view determines focusability automatically. This is the default. 896 * <p> 897 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 898 * android:focusable}. 899 */ 900 public static final int FOCUSABLE_AUTO = 0x00000010; 901 902 /** 903 * Mask for use with setFlags indicating bits used for focus. 904 */ 905 private static final int FOCUSABLE_MASK = 0x00000011; 906 907 /** 908 * This view will adjust its padding to fit sytem windows (e.g. status bar) 909 */ 910 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 911 912 /** @hide */ 913 @IntDef({VISIBLE, INVISIBLE, GONE}) 914 @Retention(RetentionPolicy.SOURCE) 915 public @interface Visibility {} 916 917 /** 918 * This view is visible. 919 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 920 * android:visibility}. 921 */ 922 public static final int VISIBLE = 0x00000000; 923 924 /** 925 * This view is invisible, but it still takes up space for layout purposes. 926 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 927 * android:visibility}. 928 */ 929 public static final int INVISIBLE = 0x00000004; 930 931 /** 932 * This view is invisible, and it doesn't take any space for layout 933 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 934 * android:visibility}. 935 */ 936 public static final int GONE = 0x00000008; 937 938 /** 939 * Mask for use with setFlags indicating bits used for visibility. 940 * {@hide} 941 */ 942 static final int VISIBILITY_MASK = 0x0000000C; 943 944 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 945 946 /** @hide */ 947 @IntDef({ 948 AUTOFILL_MODE_INHERIT, 949 AUTOFILL_MODE_AUTO, 950 AUTOFILL_MODE_MANUAL 951 }) 952 @Retention(RetentionPolicy.SOURCE) 953 public @interface AutofillMode {} 954 955 /** 956 * This view inherits the autofill state from it's parent. If there is no parent it is 957 * {@link #AUTOFILL_MODE_AUTO}. 958 * Use with {@link #setAutofillMode(int)} and <a href="#attr_android:autofillMode"> 959 * {@code android:autofillMode}. 960 */ 961 public static final int AUTOFILL_MODE_INHERIT = 0; 962 963 /** 964 * Allows this view to automatically trigger an autofill request when it get focus. 965 * Use with {@link #setAutofillMode(int)} and <a href="#attr_android:autofillMode"> 966 * {@code android:autofillMode}. 967 */ 968 public static final int AUTOFILL_MODE_AUTO = 1; 969 970 /** 971 * Do not trigger an autofill request if this view is focused. The user can still force 972 * an autofill request. 973 * <p>This does not prevent this field from being autofilled if an autofill operation is 974 * triggered from a different view.</p> 975 * 976 * Use with {@link #setAutofillMode(int)} and <a href="#attr_android:autofillMode">{@code 977 * android:autofillMode}. 978 */ 979 public static final int AUTOFILL_MODE_MANUAL = 2; 980 981 /** 982 * This view contains an email address. 983 * 984 * Use with {@link #setAutofillHint(String[])}, or set "{@value #AUTOFILL_HINT_EMAIL_ADDRESS}" 985 * to <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 986 */ 987 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 988 989 /** 990 * The view contains a real name. 991 * 992 * Use with {@link #setAutofillHint(String[])}, or set "{@value #AUTOFILL_HINT_NAME}" to 993 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 994 */ 995 public static final String AUTOFILL_HINT_NAME = "name"; 996 997 /** 998 * The view contains a user name. 999 * 1000 * Use with {@link #setAutofillHint(String[])}, or set "{@value #AUTOFILL_HINT_USERNAME}" to 1001 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 1002 */ 1003 public static final String AUTOFILL_HINT_USERNAME = "username"; 1004 1005 /** 1006 * The view contains a password. 1007 * 1008 * Use with {@link #setAutofillHint(String[])}, or set "{@value #AUTOFILL_HINT_PASSWORD}" to 1009 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 1010 */ 1011 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1012 1013 /** 1014 * The view contains a phone number. 1015 * 1016 * Use with {@link #setAutofillHint(String[])}, or set "{@value #AUTOFILL_HINT_PHONE}" to 1017 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 1018 */ 1019 public static final String AUTOFILL_HINT_PHONE = "phone"; 1020 1021 /** 1022 * The view contains a postal address. 1023 * 1024 * Use with {@link #setAutofillHint(String[])}, or set "{@value #AUTOFILL_HINT_POSTAL_ADDRESS}" 1025 * to <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 1026 */ 1027 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1028 1029 /** 1030 * The view contains a postal code. 1031 * 1032 * Use with {@link #setAutofillHint(String[])}, or set "{@value #AUTOFILL_HINT_POSTAL_CODE}" to 1033 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 1034 */ 1035 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1036 1037 /** 1038 * The view contains a credit card number. 1039 * 1040 * Use with {@link #setAutofillHint(String[])}, or set "{@value 1041 * #AUTOFILL_HINT_CREDIT_CARD_NUMBER}" to <a href="#attr_android:autofillHint"> {@code 1042 * android:autofillHint}. 1043 */ 1044 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1045 1046 /** 1047 * The view contains a credit card security code. 1048 * 1049 * Use with {@link #setAutofillHint(String[])}, or set "{@value 1050 * #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}" to <a href="#attr_android:autofillHint"> {@code 1051 * android:autofillHint}. 1052 */ 1053 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1054 1055 /** 1056 * The view contains a credit card expiration date. 1057 * 1058 * Use with {@link #setAutofillHint(String[])}, or set "{@value 1059 * #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}" to <a href="#attr_android:autofillHint"> {@code 1060 * android:autofillHint}. 1061 */ 1062 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1063 "creditCardExpirationDate"; 1064 1065 /** 1066 * The view contains the month a credit card expires. 1067 * 1068 * Use with {@link #setAutofillHint(String[])}, or set "{@value 1069 * #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}" to <a href="#attr_android:autofillHint"> {@code 1070 * android:autofillHint}. 1071 */ 1072 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1073 "creditCardExpirationMonth"; 1074 1075 /** 1076 * The view contains the year a credit card expires. 1077 * 1078 * Use with {@link #setAutofillHint(String[])}, or set "{@value 1079 * #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}" to <a href="#attr_android:autofillHint"> {@code 1080 * android:autofillHint}. 1081 */ 1082 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1083 "creditCardExpirationYear"; 1084 1085 /** 1086 * The view contains the day a credit card expires. 1087 * 1088 * Use with {@link #setAutofillHint(String[])}, or set "{@value 1089 * #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}" to <a href="#attr_android:autofillHint"> {@code 1090 * android:autofillHint}. 1091 */ 1092 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1093 1094 /** 1095 * Hintd for the autofill services that describes the content of the view. 1096 */ 1097 private @Nullable String[] mAutofillHint; 1098 1099 /** @hide */ 1100 @IntDef({ 1101 AUTOFILL_TYPE_NONE, 1102 AUTOFILL_TYPE_TEXT, 1103 AUTOFILL_TYPE_TOGGLE, 1104 AUTOFILL_TYPE_LIST, 1105 AUTOFILL_TYPE_DATE 1106 }) 1107 @Retention(RetentionPolicy.SOURCE) 1108 public @interface AutofillType {} 1109 1110 /** 1111 * Autofill type for views that cannot be autofilled. 1112 */ 1113 public static final int AUTOFILL_TYPE_NONE = 0; 1114 1115 /** 1116 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1117 * 1118 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1119 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1120 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1121 */ 1122 public static final int AUTOFILL_TYPE_TEXT = 1; 1123 1124 /** 1125 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1126 * 1127 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1128 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1129 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1130 */ 1131 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1132 1133 /** 1134 * Autofill type for a selection list field, which is filled by an {@code int} 1135 * representing the element index inside the list (starting at {@code 0}). 1136 * 1137 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1138 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1139 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1140 * 1141 * <p>The available options in the selection list are typically provided by 1142 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1143 */ 1144 public static final int AUTOFILL_TYPE_LIST = 3; 1145 1146 1147 /** 1148 * Autofill type for a field that contains a date, which is represented by a long representing 1149 * the number of milliseconds since the standard base time known as "the epoch", namely 1150 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1151 * 1152 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1153 * {@link AutofillValue#forDate(long)}, and the values passed to 1154 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1155 */ 1156 public static final int AUTOFILL_TYPE_DATE = 4; 1157 1158 /** @hide */ 1159 @IntDef({ 1160 IMPORTANT_FOR_AUTOFILL_AUTO, 1161 IMPORTANT_FOR_AUTOFILL_YES, 1162 IMPORTANT_FOR_AUTOFILL_NO 1163 }) 1164 @Retention(RetentionPolicy.SOURCE) 1165 public @interface AutofillImportance {} 1166 1167 /** 1168 * Automatically determine whether a view is important for auto-fill. 1169 */ 1170 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1171 1172 /** 1173 * The view is important for important for auto-fill. 1174 */ 1175 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1176 1177 /** 1178 * The view is not important for auto-fill. 1179 */ 1180 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1181 1182 /** 1183 * This view is enabled. Interpretation varies by subclass. 1184 * Use with ENABLED_MASK when calling setFlags. 1185 * {@hide} 1186 */ 1187 static final int ENABLED = 0x00000000; 1188 1189 /** 1190 * This view is disabled. Interpretation varies by subclass. 1191 * Use with ENABLED_MASK when calling setFlags. 1192 * {@hide} 1193 */ 1194 static final int DISABLED = 0x00000020; 1195 1196 /** 1197 * Mask for use with setFlags indicating bits used for indicating whether 1198 * this view is enabled 1199 * {@hide} 1200 */ 1201 static final int ENABLED_MASK = 0x00000020; 1202 1203 /** 1204 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1205 * called and further optimizations will be performed. It is okay to have 1206 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1207 * {@hide} 1208 */ 1209 static final int WILL_NOT_DRAW = 0x00000080; 1210 1211 /** 1212 * Mask for use with setFlags indicating bits used for indicating whether 1213 * this view is will draw 1214 * {@hide} 1215 */ 1216 static final int DRAW_MASK = 0x00000080; 1217 1218 /** 1219 * <p>This view doesn't show scrollbars.</p> 1220 * {@hide} 1221 */ 1222 static final int SCROLLBARS_NONE = 0x00000000; 1223 1224 /** 1225 * <p>This view shows horizontal scrollbars.</p> 1226 * {@hide} 1227 */ 1228 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1229 1230 /** 1231 * <p>This view shows vertical scrollbars.</p> 1232 * {@hide} 1233 */ 1234 static final int SCROLLBARS_VERTICAL = 0x00000200; 1235 1236 /** 1237 * <p>Mask for use with setFlags indicating bits used for indicating which 1238 * scrollbars are enabled.</p> 1239 * {@hide} 1240 */ 1241 static final int SCROLLBARS_MASK = 0x00000300; 1242 1243 /** 1244 * Indicates that the view should filter touches when its window is obscured. 1245 * Refer to the class comments for more information about this security feature. 1246 * {@hide} 1247 */ 1248 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1249 1250 /** 1251 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1252 * that they are optional and should be skipped if the window has 1253 * requested system UI flags that ignore those insets for layout. 1254 */ 1255 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1256 1257 /** 1258 * <p>This view doesn't show fading edges.</p> 1259 * {@hide} 1260 */ 1261 static final int FADING_EDGE_NONE = 0x00000000; 1262 1263 /** 1264 * <p>This view shows horizontal fading edges.</p> 1265 * {@hide} 1266 */ 1267 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1268 1269 /** 1270 * <p>This view shows vertical fading edges.</p> 1271 * {@hide} 1272 */ 1273 static final int FADING_EDGE_VERTICAL = 0x00002000; 1274 1275 /** 1276 * <p>Mask for use with setFlags indicating bits used for indicating which 1277 * fading edges are enabled.</p> 1278 * {@hide} 1279 */ 1280 static final int FADING_EDGE_MASK = 0x00003000; 1281 1282 /** 1283 * <p>Indicates this view can be clicked. When clickable, a View reacts 1284 * to clicks by notifying the OnClickListener.<p> 1285 * {@hide} 1286 */ 1287 static final int CLICKABLE = 0x00004000; 1288 1289 /** 1290 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1291 * {@hide} 1292 */ 1293 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1294 1295 /** 1296 * <p>Indicates that no icicle should be saved for this view.<p> 1297 * {@hide} 1298 */ 1299 static final int SAVE_DISABLED = 0x000010000; 1300 1301 /** 1302 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1303 * property.</p> 1304 * {@hide} 1305 */ 1306 static final int SAVE_DISABLED_MASK = 0x000010000; 1307 1308 /** 1309 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1310 * {@hide} 1311 */ 1312 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1313 1314 /** 1315 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1316 * {@hide} 1317 */ 1318 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1319 1320 /** @hide */ 1321 @Retention(RetentionPolicy.SOURCE) 1322 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1323 public @interface DrawingCacheQuality {} 1324 1325 /** 1326 * <p>Enables low quality mode for the drawing cache.</p> 1327 */ 1328 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1329 1330 /** 1331 * <p>Enables high quality mode for the drawing cache.</p> 1332 */ 1333 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1334 1335 /** 1336 * <p>Enables automatic quality mode for the drawing cache.</p> 1337 */ 1338 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1339 1340 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1341 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1342 }; 1343 1344 /** 1345 * <p>Mask for use with setFlags indicating bits used for the cache 1346 * quality property.</p> 1347 * {@hide} 1348 */ 1349 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1350 1351 /** 1352 * <p> 1353 * Indicates this view can be long clicked. When long clickable, a View 1354 * reacts to long clicks by notifying the OnLongClickListener or showing a 1355 * context menu. 1356 * </p> 1357 * {@hide} 1358 */ 1359 static final int LONG_CLICKABLE = 0x00200000; 1360 1361 /** 1362 * <p>Indicates that this view gets its drawable states from its direct parent 1363 * and ignores its original internal states.</p> 1364 * 1365 * @hide 1366 */ 1367 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1368 1369 /** 1370 * <p> 1371 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1372 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1373 * OnContextClickListener. 1374 * </p> 1375 * {@hide} 1376 */ 1377 static final int CONTEXT_CLICKABLE = 0x00800000; 1378 1379 1380 /** @hide */ 1381 @IntDef({ 1382 SCROLLBARS_INSIDE_OVERLAY, 1383 SCROLLBARS_INSIDE_INSET, 1384 SCROLLBARS_OUTSIDE_OVERLAY, 1385 SCROLLBARS_OUTSIDE_INSET 1386 }) 1387 @Retention(RetentionPolicy.SOURCE) 1388 public @interface ScrollBarStyle {} 1389 1390 /** 1391 * The scrollbar style to display the scrollbars inside the content area, 1392 * without increasing the padding. The scrollbars will be overlaid with 1393 * translucency on the view's content. 1394 */ 1395 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1396 1397 /** 1398 * The scrollbar style to display the scrollbars inside the padded area, 1399 * increasing the padding of the view. The scrollbars will not overlap the 1400 * content area of the view. 1401 */ 1402 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1403 1404 /** 1405 * The scrollbar style to display the scrollbars at the edge of the view, 1406 * without increasing the padding. The scrollbars will be overlaid with 1407 * translucency. 1408 */ 1409 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1410 1411 /** 1412 * The scrollbar style to display the scrollbars at the edge of the view, 1413 * increasing the padding of the view. The scrollbars will only overlap the 1414 * background, if any. 1415 */ 1416 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1417 1418 /** 1419 * Mask to check if the scrollbar style is overlay or inset. 1420 * {@hide} 1421 */ 1422 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1423 1424 /** 1425 * Mask to check if the scrollbar style is inside or outside. 1426 * {@hide} 1427 */ 1428 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1429 1430 /** 1431 * Mask for scrollbar style. 1432 * {@hide} 1433 */ 1434 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1435 1436 /** 1437 * View flag indicating that the screen should remain on while the 1438 * window containing this view is visible to the user. This effectively 1439 * takes care of automatically setting the WindowManager's 1440 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1441 */ 1442 public static final int KEEP_SCREEN_ON = 0x04000000; 1443 1444 /** 1445 * View flag indicating whether this view should have sound effects enabled 1446 * for events such as clicking and touching. 1447 */ 1448 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1449 1450 /** 1451 * View flag indicating whether this view should have haptic feedback 1452 * enabled for events such as long presses. 1453 */ 1454 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1455 1456 /** 1457 * <p>Indicates that the view hierarchy should stop saving state when 1458 * it reaches this view. If state saving is initiated immediately at 1459 * the view, it will be allowed. 1460 * {@hide} 1461 */ 1462 static final int PARENT_SAVE_DISABLED = 0x20000000; 1463 1464 /** 1465 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1466 * {@hide} 1467 */ 1468 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1469 1470 private static Paint sDebugPaint; 1471 1472 /** 1473 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1474 * {@hide} 1475 */ 1476 static final int TOOLTIP = 0x40000000; 1477 1478 /** @hide */ 1479 @IntDef(flag = true, 1480 value = { 1481 FOCUSABLES_ALL, 1482 FOCUSABLES_TOUCH_MODE 1483 }) 1484 @Retention(RetentionPolicy.SOURCE) 1485 public @interface FocusableMode {} 1486 1487 /** 1488 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1489 * should add all focusable Views regardless if they are focusable in touch mode. 1490 */ 1491 public static final int FOCUSABLES_ALL = 0x00000000; 1492 1493 /** 1494 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1495 * should add only Views focusable in touch mode. 1496 */ 1497 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1498 1499 /** @hide */ 1500 @IntDef({ 1501 FOCUS_BACKWARD, 1502 FOCUS_FORWARD, 1503 FOCUS_LEFT, 1504 FOCUS_UP, 1505 FOCUS_RIGHT, 1506 FOCUS_DOWN 1507 }) 1508 @Retention(RetentionPolicy.SOURCE) 1509 public @interface FocusDirection {} 1510 1511 /** @hide */ 1512 @IntDef({ 1513 FOCUS_LEFT, 1514 FOCUS_UP, 1515 FOCUS_RIGHT, 1516 FOCUS_DOWN 1517 }) 1518 @Retention(RetentionPolicy.SOURCE) 1519 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1520 1521 /** 1522 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1523 * item. 1524 */ 1525 public static final int FOCUS_BACKWARD = 0x00000001; 1526 1527 /** 1528 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1529 * item. 1530 */ 1531 public static final int FOCUS_FORWARD = 0x00000002; 1532 1533 /** 1534 * Use with {@link #focusSearch(int)}. Move focus to the left. 1535 */ 1536 public static final int FOCUS_LEFT = 0x00000011; 1537 1538 /** 1539 * Use with {@link #focusSearch(int)}. Move focus up. 1540 */ 1541 public static final int FOCUS_UP = 0x00000021; 1542 1543 /** 1544 * Use with {@link #focusSearch(int)}. Move focus to the right. 1545 */ 1546 public static final int FOCUS_RIGHT = 0x00000042; 1547 1548 /** 1549 * Use with {@link #focusSearch(int)}. Move focus down. 1550 */ 1551 public static final int FOCUS_DOWN = 0x00000082; 1552 1553 /** 1554 * Bits of {@link #getMeasuredWidthAndState()} and 1555 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1556 */ 1557 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1558 1559 /** 1560 * Bits of {@link #getMeasuredWidthAndState()} and 1561 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1562 */ 1563 public static final int MEASURED_STATE_MASK = 0xff000000; 1564 1565 /** 1566 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1567 * for functions that combine both width and height into a single int, 1568 * such as {@link #getMeasuredState()} and the childState argument of 1569 * {@link #resolveSizeAndState(int, int, int)}. 1570 */ 1571 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1572 1573 /** 1574 * Bit of {@link #getMeasuredWidthAndState()} and 1575 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1576 * is smaller that the space the view would like to have. 1577 */ 1578 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1579 1580 /** 1581 * Base View state sets 1582 */ 1583 // Singles 1584 /** 1585 * Indicates the view has no states set. States are used with 1586 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1587 * view depending on its state. 1588 * 1589 * @see android.graphics.drawable.Drawable 1590 * @see #getDrawableState() 1591 */ 1592 protected static final int[] EMPTY_STATE_SET; 1593 /** 1594 * Indicates the view is enabled. States are used with 1595 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1596 * view depending on its state. 1597 * 1598 * @see android.graphics.drawable.Drawable 1599 * @see #getDrawableState() 1600 */ 1601 protected static final int[] ENABLED_STATE_SET; 1602 /** 1603 * Indicates the view is focused. States are used with 1604 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1605 * view depending on its state. 1606 * 1607 * @see android.graphics.drawable.Drawable 1608 * @see #getDrawableState() 1609 */ 1610 protected static final int[] FOCUSED_STATE_SET; 1611 /** 1612 * Indicates the view is selected. States are used with 1613 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1614 * view depending on its state. 1615 * 1616 * @see android.graphics.drawable.Drawable 1617 * @see #getDrawableState() 1618 */ 1619 protected static final int[] SELECTED_STATE_SET; 1620 /** 1621 * Indicates the view is pressed. States are used with 1622 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1623 * view depending on its state. 1624 * 1625 * @see android.graphics.drawable.Drawable 1626 * @see #getDrawableState() 1627 */ 1628 protected static final int[] PRESSED_STATE_SET; 1629 /** 1630 * Indicates the view's window has focus. States are used with 1631 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1632 * view depending on its state. 1633 * 1634 * @see android.graphics.drawable.Drawable 1635 * @see #getDrawableState() 1636 */ 1637 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1638 // Doubles 1639 /** 1640 * Indicates the view is enabled and has the focus. 1641 * 1642 * @see #ENABLED_STATE_SET 1643 * @see #FOCUSED_STATE_SET 1644 */ 1645 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1646 /** 1647 * Indicates the view is enabled and selected. 1648 * 1649 * @see #ENABLED_STATE_SET 1650 * @see #SELECTED_STATE_SET 1651 */ 1652 protected static final int[] ENABLED_SELECTED_STATE_SET; 1653 /** 1654 * Indicates the view is enabled and that its window has focus. 1655 * 1656 * @see #ENABLED_STATE_SET 1657 * @see #WINDOW_FOCUSED_STATE_SET 1658 */ 1659 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1660 /** 1661 * Indicates the view is focused and selected. 1662 * 1663 * @see #FOCUSED_STATE_SET 1664 * @see #SELECTED_STATE_SET 1665 */ 1666 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1667 /** 1668 * Indicates the view has the focus and that its window has the focus. 1669 * 1670 * @see #FOCUSED_STATE_SET 1671 * @see #WINDOW_FOCUSED_STATE_SET 1672 */ 1673 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1674 /** 1675 * Indicates the view is selected and that its window has the focus. 1676 * 1677 * @see #SELECTED_STATE_SET 1678 * @see #WINDOW_FOCUSED_STATE_SET 1679 */ 1680 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1681 // Triples 1682 /** 1683 * Indicates the view is enabled, focused and selected. 1684 * 1685 * @see #ENABLED_STATE_SET 1686 * @see #FOCUSED_STATE_SET 1687 * @see #SELECTED_STATE_SET 1688 */ 1689 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1690 /** 1691 * Indicates the view is enabled, focused and its window has the focus. 1692 * 1693 * @see #ENABLED_STATE_SET 1694 * @see #FOCUSED_STATE_SET 1695 * @see #WINDOW_FOCUSED_STATE_SET 1696 */ 1697 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1698 /** 1699 * Indicates the view is enabled, selected and its window has the focus. 1700 * 1701 * @see #ENABLED_STATE_SET 1702 * @see #SELECTED_STATE_SET 1703 * @see #WINDOW_FOCUSED_STATE_SET 1704 */ 1705 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1706 /** 1707 * Indicates the view is focused, selected and its window has the focus. 1708 * 1709 * @see #FOCUSED_STATE_SET 1710 * @see #SELECTED_STATE_SET 1711 * @see #WINDOW_FOCUSED_STATE_SET 1712 */ 1713 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1714 /** 1715 * Indicates the view is enabled, focused, selected and its window 1716 * has the focus. 1717 * 1718 * @see #ENABLED_STATE_SET 1719 * @see #FOCUSED_STATE_SET 1720 * @see #SELECTED_STATE_SET 1721 * @see #WINDOW_FOCUSED_STATE_SET 1722 */ 1723 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1724 /** 1725 * Indicates the view is pressed and its window has the focus. 1726 * 1727 * @see #PRESSED_STATE_SET 1728 * @see #WINDOW_FOCUSED_STATE_SET 1729 */ 1730 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1731 /** 1732 * Indicates the view is pressed and selected. 1733 * 1734 * @see #PRESSED_STATE_SET 1735 * @see #SELECTED_STATE_SET 1736 */ 1737 protected static final int[] PRESSED_SELECTED_STATE_SET; 1738 /** 1739 * Indicates the view is pressed, selected and its window has the focus. 1740 * 1741 * @see #PRESSED_STATE_SET 1742 * @see #SELECTED_STATE_SET 1743 * @see #WINDOW_FOCUSED_STATE_SET 1744 */ 1745 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1746 /** 1747 * Indicates the view is pressed and focused. 1748 * 1749 * @see #PRESSED_STATE_SET 1750 * @see #FOCUSED_STATE_SET 1751 */ 1752 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1753 /** 1754 * Indicates the view is pressed, focused and its window has the focus. 1755 * 1756 * @see #PRESSED_STATE_SET 1757 * @see #FOCUSED_STATE_SET 1758 * @see #WINDOW_FOCUSED_STATE_SET 1759 */ 1760 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1761 /** 1762 * Indicates the view is pressed, focused and selected. 1763 * 1764 * @see #PRESSED_STATE_SET 1765 * @see #SELECTED_STATE_SET 1766 * @see #FOCUSED_STATE_SET 1767 */ 1768 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1769 /** 1770 * Indicates the view is pressed, focused, selected and its window has the focus. 1771 * 1772 * @see #PRESSED_STATE_SET 1773 * @see #FOCUSED_STATE_SET 1774 * @see #SELECTED_STATE_SET 1775 * @see #WINDOW_FOCUSED_STATE_SET 1776 */ 1777 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1778 /** 1779 * Indicates the view is pressed and enabled. 1780 * 1781 * @see #PRESSED_STATE_SET 1782 * @see #ENABLED_STATE_SET 1783 */ 1784 protected static final int[] PRESSED_ENABLED_STATE_SET; 1785 /** 1786 * Indicates the view is pressed, enabled and its window has the focus. 1787 * 1788 * @see #PRESSED_STATE_SET 1789 * @see #ENABLED_STATE_SET 1790 * @see #WINDOW_FOCUSED_STATE_SET 1791 */ 1792 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1793 /** 1794 * Indicates the view is pressed, enabled and selected. 1795 * 1796 * @see #PRESSED_STATE_SET 1797 * @see #ENABLED_STATE_SET 1798 * @see #SELECTED_STATE_SET 1799 */ 1800 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1801 /** 1802 * Indicates the view is pressed, enabled, selected and its window has the 1803 * focus. 1804 * 1805 * @see #PRESSED_STATE_SET 1806 * @see #ENABLED_STATE_SET 1807 * @see #SELECTED_STATE_SET 1808 * @see #WINDOW_FOCUSED_STATE_SET 1809 */ 1810 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1811 /** 1812 * Indicates the view is pressed, enabled and focused. 1813 * 1814 * @see #PRESSED_STATE_SET 1815 * @see #ENABLED_STATE_SET 1816 * @see #FOCUSED_STATE_SET 1817 */ 1818 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1819 /** 1820 * Indicates the view is pressed, enabled, focused and its window has the 1821 * focus. 1822 * 1823 * @see #PRESSED_STATE_SET 1824 * @see #ENABLED_STATE_SET 1825 * @see #FOCUSED_STATE_SET 1826 * @see #WINDOW_FOCUSED_STATE_SET 1827 */ 1828 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1829 /** 1830 * Indicates the view is pressed, enabled, focused and selected. 1831 * 1832 * @see #PRESSED_STATE_SET 1833 * @see #ENABLED_STATE_SET 1834 * @see #SELECTED_STATE_SET 1835 * @see #FOCUSED_STATE_SET 1836 */ 1837 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1838 /** 1839 * Indicates the view is pressed, enabled, focused, selected and its window 1840 * has the focus. 1841 * 1842 * @see #PRESSED_STATE_SET 1843 * @see #ENABLED_STATE_SET 1844 * @see #SELECTED_STATE_SET 1845 * @see #FOCUSED_STATE_SET 1846 * @see #WINDOW_FOCUSED_STATE_SET 1847 */ 1848 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1849 1850 static { 1851 EMPTY_STATE_SET = StateSet.get(0); 1852 1853 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1854 1855 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1856 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1857 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1858 1859 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1860 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1861 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1862 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1863 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1864 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1865 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1866 | StateSet.VIEW_STATE_FOCUSED); 1867 1868 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1869 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1870 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1871 ENABLED_SELECTED_STATE_SET = StateSet.get( 1872 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1873 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1874 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1875 | StateSet.VIEW_STATE_ENABLED); 1876 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1877 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1878 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1879 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1880 | StateSet.VIEW_STATE_ENABLED); 1881 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1882 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1883 | StateSet.VIEW_STATE_ENABLED); 1884 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1885 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1886 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1887 1888 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1889 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1890 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1891 PRESSED_SELECTED_STATE_SET = StateSet.get( 1892 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1893 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1894 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1895 | StateSet.VIEW_STATE_PRESSED); 1896 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1897 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1898 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1899 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1900 | StateSet.VIEW_STATE_PRESSED); 1901 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1902 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1903 | StateSet.VIEW_STATE_PRESSED); 1904 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1905 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1906 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1907 PRESSED_ENABLED_STATE_SET = StateSet.get( 1908 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1909 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1910 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1911 | StateSet.VIEW_STATE_PRESSED); 1912 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1913 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1914 | StateSet.VIEW_STATE_PRESSED); 1915 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1916 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1917 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1918 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 1919 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 1920 | StateSet.VIEW_STATE_PRESSED); 1921 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1922 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1923 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1924 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1925 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1926 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1927 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1928 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1929 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 1930 | StateSet.VIEW_STATE_PRESSED); 1931 } 1932 1933 /** 1934 * Accessibility event types that are dispatched for text population. 1935 */ 1936 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 1937 AccessibilityEvent.TYPE_VIEW_CLICKED 1938 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 1939 | AccessibilityEvent.TYPE_VIEW_SELECTED 1940 | AccessibilityEvent.TYPE_VIEW_FOCUSED 1941 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 1942 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 1943 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 1944 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 1945 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 1946 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 1947 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 1948 1949 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 1950 1951 static final int DEBUG_CORNERS_SIZE_DIP = 8; 1952 1953 /** 1954 * Temporary Rect currently for use in setBackground(). This will probably 1955 * be extended in the future to hold our own class with more than just 1956 * a Rect. :) 1957 */ 1958 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 1959 1960 /** 1961 * Map used to store views' tags. 1962 */ 1963 private SparseArray<Object> mKeyedTags; 1964 1965 /** 1966 * The next available accessibility id. 1967 */ 1968 private static int sNextAccessibilityViewId; 1969 1970 /** 1971 * The animation currently associated with this view. 1972 * @hide 1973 */ 1974 protected Animation mCurrentAnimation = null; 1975 1976 /** 1977 * Width as measured during measure pass. 1978 * {@hide} 1979 */ 1980 @ViewDebug.ExportedProperty(category = "measurement") 1981 int mMeasuredWidth; 1982 1983 /** 1984 * Height as measured during measure pass. 1985 * {@hide} 1986 */ 1987 @ViewDebug.ExportedProperty(category = "measurement") 1988 int mMeasuredHeight; 1989 1990 /** 1991 * Flag to indicate that this view was marked INVALIDATED, or had its display list 1992 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 1993 * its display list. This flag, used only when hw accelerated, allows us to clear the 1994 * flag while retaining this information until it's needed (at getDisplayList() time and 1995 * in drawChild(), when we decide to draw a view's children's display lists into our own). 1996 * 1997 * {@hide} 1998 */ 1999 boolean mRecreateDisplayList = false; 2000 2001 /** 2002 * The view's identifier. 2003 * {@hide} 2004 * 2005 * @see #setId(int) 2006 * @see #getId() 2007 */ 2008 @IdRes 2009 @ViewDebug.ExportedProperty(resolveId = true) 2010 int mID = NO_ID; 2011 2012 /** 2013 * The stable ID of this view for accessibility purposes. 2014 */ 2015 int mAccessibilityViewId = NO_ID; 2016 2017 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2018 2019 SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent; 2020 2021 /** 2022 * The view's tag. 2023 * {@hide} 2024 * 2025 * @see #setTag(Object) 2026 * @see #getTag() 2027 */ 2028 protected Object mTag = null; 2029 2030 // for mPrivateFlags: 2031 /** {@hide} */ 2032 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2033 /** {@hide} */ 2034 static final int PFLAG_FOCUSED = 0x00000002; 2035 /** {@hide} */ 2036 static final int PFLAG_SELECTED = 0x00000004; 2037 /** {@hide} */ 2038 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2039 /** {@hide} */ 2040 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2041 /** {@hide} */ 2042 static final int PFLAG_DRAWN = 0x00000020; 2043 /** 2044 * When this flag is set, this view is running an animation on behalf of its 2045 * children and should therefore not cancel invalidate requests, even if they 2046 * lie outside of this view's bounds. 2047 * 2048 * {@hide} 2049 */ 2050 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2051 /** {@hide} */ 2052 static final int PFLAG_SKIP_DRAW = 0x00000080; 2053 /** {@hide} */ 2054 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2055 /** {@hide} */ 2056 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2057 /** {@hide} */ 2058 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2059 /** {@hide} */ 2060 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2061 /** {@hide} */ 2062 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2063 2064 private static final int PFLAG_PRESSED = 0x00004000; 2065 2066 /** {@hide} */ 2067 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2068 /** 2069 * Flag used to indicate that this view should be drawn once more (and only once 2070 * more) after its animation has completed. 2071 * {@hide} 2072 */ 2073 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2074 2075 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2076 2077 /** 2078 * Indicates that the View returned true when onSetAlpha() was called and that 2079 * the alpha must be restored. 2080 * {@hide} 2081 */ 2082 static final int PFLAG_ALPHA_SET = 0x00040000; 2083 2084 /** 2085 * Set by {@link #setScrollContainer(boolean)}. 2086 */ 2087 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2088 2089 /** 2090 * Set by {@link #setScrollContainer(boolean)}. 2091 */ 2092 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2093 2094 /** 2095 * View flag indicating whether this view was invalidated (fully or partially.) 2096 * 2097 * @hide 2098 */ 2099 static final int PFLAG_DIRTY = 0x00200000; 2100 2101 /** 2102 * View flag indicating whether this view was invalidated by an opaque 2103 * invalidate request. 2104 * 2105 * @hide 2106 */ 2107 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 2108 2109 /** 2110 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 2111 * 2112 * @hide 2113 */ 2114 static final int PFLAG_DIRTY_MASK = 0x00600000; 2115 2116 /** 2117 * Indicates whether the background is opaque. 2118 * 2119 * @hide 2120 */ 2121 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2122 2123 /** 2124 * Indicates whether the scrollbars are opaque. 2125 * 2126 * @hide 2127 */ 2128 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2129 2130 /** 2131 * Indicates whether the view is opaque. 2132 * 2133 * @hide 2134 */ 2135 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2136 2137 /** 2138 * Indicates a prepressed state; 2139 * the short time between ACTION_DOWN and recognizing 2140 * a 'real' press. Prepressed is used to recognize quick taps 2141 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2142 * 2143 * @hide 2144 */ 2145 private static final int PFLAG_PREPRESSED = 0x02000000; 2146 2147 /** 2148 * Indicates whether the view is temporarily detached. 2149 * 2150 * @hide 2151 */ 2152 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2153 2154 /** 2155 * Indicates that we should awaken scroll bars once attached 2156 * 2157 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2158 * during window attachment and it is no longer needed. Feel free to repurpose it. 2159 * 2160 * @hide 2161 */ 2162 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2163 2164 /** 2165 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2166 * @hide 2167 */ 2168 private static final int PFLAG_HOVERED = 0x10000000; 2169 2170 /** 2171 * no longer needed, should be reused 2172 */ 2173 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 2174 2175 /** {@hide} */ 2176 static final int PFLAG_ACTIVATED = 0x40000000; 2177 2178 /** 2179 * Indicates that this view was specifically invalidated, not just dirtied because some 2180 * child view was invalidated. The flag is used to determine when we need to recreate 2181 * a view's display list (as opposed to just returning a reference to its existing 2182 * display list). 2183 * 2184 * @hide 2185 */ 2186 static final int PFLAG_INVALIDATED = 0x80000000; 2187 2188 /** 2189 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2190 * 2191 * |-------|-------|-------|-------| 2192 * 1 PFLAG2_DRAG_CAN_ACCEPT 2193 * 1 PFLAG2_DRAG_HOVERED 2194 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2195 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2196 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2197 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2198 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2199 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2200 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2201 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2202 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2203 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2204 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2205 * 111 PFLAG2_TEXT_DIRECTION_MASK 2206 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2207 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2208 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2209 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2210 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2211 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2212 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2213 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2214 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2215 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2216 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2217 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2218 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2219 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2220 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2221 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2222 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2223 * 1 PFLAG2_VIEW_QUICK_REJECTED 2224 * 1 PFLAG2_PADDING_RESOLVED 2225 * 1 PFLAG2_DRAWABLE_RESOLVED 2226 * 1 PFLAG2_HAS_TRANSIENT_STATE 2227 * |-------|-------|-------|-------| 2228 */ 2229 2230 /** 2231 * Indicates that this view has reported that it can accept the current drag's content. 2232 * Cleared when the drag operation concludes. 2233 * @hide 2234 */ 2235 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2236 2237 /** 2238 * Indicates that this view is currently directly under the drag location in a 2239 * drag-and-drop operation involving content that it can accept. Cleared when 2240 * the drag exits the view, or when the drag operation concludes. 2241 * @hide 2242 */ 2243 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2244 2245 /** @hide */ 2246 @IntDef({ 2247 LAYOUT_DIRECTION_LTR, 2248 LAYOUT_DIRECTION_RTL, 2249 LAYOUT_DIRECTION_INHERIT, 2250 LAYOUT_DIRECTION_LOCALE 2251 }) 2252 @Retention(RetentionPolicy.SOURCE) 2253 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2254 public @interface LayoutDir {} 2255 2256 /** @hide */ 2257 @IntDef({ 2258 LAYOUT_DIRECTION_LTR, 2259 LAYOUT_DIRECTION_RTL 2260 }) 2261 @Retention(RetentionPolicy.SOURCE) 2262 public @interface ResolvedLayoutDir {} 2263 2264 /** 2265 * A flag to indicate that the layout direction of this view has not been defined yet. 2266 * @hide 2267 */ 2268 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2269 2270 /** 2271 * Horizontal layout direction of this view is from Left to Right. 2272 * Use with {@link #setLayoutDirection}. 2273 */ 2274 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2275 2276 /** 2277 * Horizontal layout direction of this view is from Right to Left. 2278 * Use with {@link #setLayoutDirection}. 2279 */ 2280 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2281 2282 /** 2283 * Horizontal layout direction of this view is inherited from its parent. 2284 * Use with {@link #setLayoutDirection}. 2285 */ 2286 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2287 2288 /** 2289 * Horizontal layout direction of this view is from deduced from the default language 2290 * script for the locale. Use with {@link #setLayoutDirection}. 2291 */ 2292 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2293 2294 /** 2295 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2296 * @hide 2297 */ 2298 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2299 2300 /** 2301 * Mask for use with private flags indicating bits used for horizontal layout direction. 2302 * @hide 2303 */ 2304 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2305 2306 /** 2307 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2308 * right-to-left direction. 2309 * @hide 2310 */ 2311 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2312 2313 /** 2314 * Indicates whether the view horizontal layout direction has been resolved. 2315 * @hide 2316 */ 2317 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2318 2319 /** 2320 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2321 * @hide 2322 */ 2323 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2324 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2325 2326 /* 2327 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2328 * flag value. 2329 * @hide 2330 */ 2331 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2332 LAYOUT_DIRECTION_LTR, 2333 LAYOUT_DIRECTION_RTL, 2334 LAYOUT_DIRECTION_INHERIT, 2335 LAYOUT_DIRECTION_LOCALE 2336 }; 2337 2338 /** 2339 * Default horizontal layout direction. 2340 */ 2341 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2342 2343 /** 2344 * Default horizontal layout direction. 2345 * @hide 2346 */ 2347 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2348 2349 /** 2350 * Text direction is inherited through {@link ViewGroup} 2351 */ 2352 public static final int TEXT_DIRECTION_INHERIT = 0; 2353 2354 /** 2355 * Text direction is using "first strong algorithm". The first strong directional character 2356 * determines the paragraph direction. If there is no strong directional character, the 2357 * paragraph direction is the view's resolved layout direction. 2358 */ 2359 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2360 2361 /** 2362 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2363 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2364 * If there are neither, the paragraph direction is the view's resolved layout direction. 2365 */ 2366 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2367 2368 /** 2369 * Text direction is forced to LTR. 2370 */ 2371 public static final int TEXT_DIRECTION_LTR = 3; 2372 2373 /** 2374 * Text direction is forced to RTL. 2375 */ 2376 public static final int TEXT_DIRECTION_RTL = 4; 2377 2378 /** 2379 * Text direction is coming from the system Locale. 2380 */ 2381 public static final int TEXT_DIRECTION_LOCALE = 5; 2382 2383 /** 2384 * Text direction is using "first strong algorithm". The first strong directional character 2385 * determines the paragraph direction. If there is no strong directional character, the 2386 * paragraph direction is LTR. 2387 */ 2388 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2389 2390 /** 2391 * Text direction is using "first strong algorithm". The first strong directional character 2392 * determines the paragraph direction. If there is no strong directional character, the 2393 * paragraph direction is RTL. 2394 */ 2395 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2396 2397 /** 2398 * Default text direction is inherited 2399 */ 2400 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2401 2402 /** 2403 * Default resolved text direction 2404 * @hide 2405 */ 2406 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2407 2408 /** 2409 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2410 * @hide 2411 */ 2412 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2413 2414 /** 2415 * Mask for use with private flags indicating bits used for text direction. 2416 * @hide 2417 */ 2418 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2419 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2420 2421 /** 2422 * Array of text direction flags for mapping attribute "textDirection" to correct 2423 * flag value. 2424 * @hide 2425 */ 2426 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2427 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2428 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2429 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2430 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2431 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2432 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2433 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2434 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2435 }; 2436 2437 /** 2438 * Indicates whether the view text direction has been resolved. 2439 * @hide 2440 */ 2441 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2442 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2443 2444 /** 2445 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2446 * @hide 2447 */ 2448 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2449 2450 /** 2451 * Mask for use with private flags indicating bits used for resolved text direction. 2452 * @hide 2453 */ 2454 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2455 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2456 2457 /** 2458 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2459 * @hide 2460 */ 2461 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2462 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2463 2464 /** @hide */ 2465 @IntDef({ 2466 TEXT_ALIGNMENT_INHERIT, 2467 TEXT_ALIGNMENT_GRAVITY, 2468 TEXT_ALIGNMENT_CENTER, 2469 TEXT_ALIGNMENT_TEXT_START, 2470 TEXT_ALIGNMENT_TEXT_END, 2471 TEXT_ALIGNMENT_VIEW_START, 2472 TEXT_ALIGNMENT_VIEW_END 2473 }) 2474 @Retention(RetentionPolicy.SOURCE) 2475 public @interface TextAlignment {} 2476 2477 /** 2478 * Default text alignment. The text alignment of this View is inherited from its parent. 2479 * Use with {@link #setTextAlignment(int)} 2480 */ 2481 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2482 2483 /** 2484 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2485 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2486 * 2487 * Use with {@link #setTextAlignment(int)} 2488 */ 2489 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2490 2491 /** 2492 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2493 * 2494 * Use with {@link #setTextAlignment(int)} 2495 */ 2496 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2497 2498 /** 2499 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2500 * 2501 * Use with {@link #setTextAlignment(int)} 2502 */ 2503 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2504 2505 /** 2506 * Center the paragraph, e.g. ALIGN_CENTER. 2507 * 2508 * Use with {@link #setTextAlignment(int)} 2509 */ 2510 public static final int TEXT_ALIGNMENT_CENTER = 4; 2511 2512 /** 2513 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2514 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2515 * 2516 * Use with {@link #setTextAlignment(int)} 2517 */ 2518 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2519 2520 /** 2521 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2522 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2523 * 2524 * Use with {@link #setTextAlignment(int)} 2525 */ 2526 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2527 2528 /** 2529 * Default text alignment is inherited 2530 */ 2531 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2532 2533 /** 2534 * Default resolved text alignment 2535 * @hide 2536 */ 2537 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2538 2539 /** 2540 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2541 * @hide 2542 */ 2543 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2544 2545 /** 2546 * Mask for use with private flags indicating bits used for text alignment. 2547 * @hide 2548 */ 2549 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2550 2551 /** 2552 * Array of text direction flags for mapping attribute "textAlignment" to correct 2553 * flag value. 2554 * @hide 2555 */ 2556 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2557 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2558 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2559 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2560 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2561 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2562 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2563 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2564 }; 2565 2566 /** 2567 * Indicates whether the view text alignment has been resolved. 2568 * @hide 2569 */ 2570 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2571 2572 /** 2573 * Bit shift to get the resolved text alignment. 2574 * @hide 2575 */ 2576 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2577 2578 /** 2579 * Mask for use with private flags indicating bits used for text alignment. 2580 * @hide 2581 */ 2582 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2583 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2584 2585 /** 2586 * Indicates whether if the view text alignment has been resolved to gravity 2587 */ 2588 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2589 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2590 2591 // Accessiblity constants for mPrivateFlags2 2592 2593 /** 2594 * Shift for the bits in {@link #mPrivateFlags2} related to the 2595 * "importantForAccessibility" attribute. 2596 */ 2597 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2598 2599 /** 2600 * Automatically determine whether a view is important for accessibility. 2601 */ 2602 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2603 2604 /** 2605 * The view is important for accessibility. 2606 */ 2607 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2608 2609 /** 2610 * The view is not important for accessibility. 2611 */ 2612 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2613 2614 /** 2615 * The view is not important for accessibility, nor are any of its 2616 * descendant views. 2617 */ 2618 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2619 2620 /** 2621 * The default whether the view is important for accessibility. 2622 */ 2623 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2624 2625 /** 2626 * Mask for obtaining the bits which specify how to determine 2627 * whether a view is important for accessibility. 2628 */ 2629 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2630 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2631 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2632 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2633 2634 /** 2635 * Shift for the bits in {@link #mPrivateFlags2} related to the 2636 * "accessibilityLiveRegion" attribute. 2637 */ 2638 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2639 2640 /** 2641 * Live region mode specifying that accessibility services should not 2642 * automatically announce changes to this view. This is the default live 2643 * region mode for most views. 2644 * <p> 2645 * Use with {@link #setAccessibilityLiveRegion(int)}. 2646 */ 2647 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2648 2649 /** 2650 * Live region mode specifying that accessibility services should announce 2651 * changes to this view. 2652 * <p> 2653 * Use with {@link #setAccessibilityLiveRegion(int)}. 2654 */ 2655 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2656 2657 /** 2658 * Live region mode specifying that accessibility services should interrupt 2659 * ongoing speech to immediately announce changes to this view. 2660 * <p> 2661 * Use with {@link #setAccessibilityLiveRegion(int)}. 2662 */ 2663 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2664 2665 /** 2666 * The default whether the view is important for accessibility. 2667 */ 2668 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2669 2670 /** 2671 * Mask for obtaining the bits which specify a view's accessibility live 2672 * region mode. 2673 */ 2674 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2675 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2676 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2677 2678 /** 2679 * Flag indicating whether a view has accessibility focus. 2680 */ 2681 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2682 2683 /** 2684 * Flag whether the accessibility state of the subtree rooted at this view changed. 2685 */ 2686 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2687 2688 /** 2689 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2690 * is used to check whether later changes to the view's transform should invalidate the 2691 * view to force the quickReject test to run again. 2692 */ 2693 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2694 2695 /** 2696 * Flag indicating that start/end padding has been resolved into left/right padding 2697 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2698 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2699 * during measurement. In some special cases this is required such as when an adapter-based 2700 * view measures prospective children without attaching them to a window. 2701 */ 2702 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2703 2704 /** 2705 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2706 */ 2707 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2708 2709 /** 2710 * Indicates that the view is tracking some sort of transient state 2711 * that the app should not need to be aware of, but that the framework 2712 * should take special care to preserve. 2713 */ 2714 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2715 2716 /** 2717 * Group of bits indicating that RTL properties resolution is done. 2718 */ 2719 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2720 PFLAG2_TEXT_DIRECTION_RESOLVED | 2721 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2722 PFLAG2_PADDING_RESOLVED | 2723 PFLAG2_DRAWABLE_RESOLVED; 2724 2725 // There are a couple of flags left in mPrivateFlags2 2726 2727 /* End of masks for mPrivateFlags2 */ 2728 2729 /** 2730 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2731 * 2732 * |-------|-------|-------|-------| 2733 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2734 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2735 * 1 PFLAG3_IS_LAID_OUT 2736 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2737 * 1 PFLAG3_CALLED_SUPER 2738 * 1 PFLAG3_APPLYING_INSETS 2739 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2740 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2741 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2742 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2743 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2744 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2745 * 1 PFLAG3_SCROLL_INDICATOR_START 2746 * 1 PFLAG3_SCROLL_INDICATOR_END 2747 * 1 PFLAG3_ASSIST_BLOCKED 2748 * 1 PFLAG3_CLUSTER 2749 * x * NO LONGER NEEDED, SHOULD BE REUSED * 2750 * 1 PFLAG3_FINGER_DOWN 2751 * 1 PFLAG3_FOCUSED_BY_DEFAULT 2752<<<<<<< HEAD 2753 * 11 PFLAG3_AUTO_FILL_MODE_MASK 2754 * 11 PFLAG3_IMPORTANT_FOR_AUTOFILL 2755======= 2756 * 11 PFLAG3_AUTOFILL_MODE_MASK 2757 * xx * NO LONGER NEEDED, SHOULD BE REUSED * 2758>>>>>>> Replaced auto-fill by autofill to keep it consistent with API style. 2759 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2760 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2761 * 1 PFLAG3_TEMPORARY_DETACH 2762 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2763 * |-------|-------|-------|-------| 2764 */ 2765 2766 /** 2767 * Flag indicating that view has a transform animation set on it. This is used to track whether 2768 * an animation is cleared between successive frames, in order to tell the associated 2769 * DisplayList to clear its animation matrix. 2770 */ 2771 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2772 2773 /** 2774 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2775 * animation is cleared between successive frames, in order to tell the associated 2776 * DisplayList to restore its alpha value. 2777 */ 2778 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2779 2780 /** 2781 * Flag indicating that the view has been through at least one layout since it 2782 * was last attached to a window. 2783 */ 2784 static final int PFLAG3_IS_LAID_OUT = 0x4; 2785 2786 /** 2787 * Flag indicating that a call to measure() was skipped and should be done 2788 * instead when layout() is invoked. 2789 */ 2790 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2791 2792 /** 2793 * Flag indicating that an overridden method correctly called down to 2794 * the superclass implementation as required by the API spec. 2795 */ 2796 static final int PFLAG3_CALLED_SUPER = 0x10; 2797 2798 /** 2799 * Flag indicating that we're in the process of applying window insets. 2800 */ 2801 static final int PFLAG3_APPLYING_INSETS = 0x20; 2802 2803 /** 2804 * Flag indicating that we're in the process of fitting system windows using the old method. 2805 */ 2806 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2807 2808 /** 2809 * Flag indicating that nested scrolling is enabled for this view. 2810 * The view will optionally cooperate with views up its parent chain to allow for 2811 * integrated nested scrolling along the same axis. 2812 */ 2813 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2814 2815 /** 2816 * Flag indicating that the bottom scroll indicator should be displayed 2817 * when this view can scroll up. 2818 */ 2819 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2820 2821 /** 2822 * Flag indicating that the bottom scroll indicator should be displayed 2823 * when this view can scroll down. 2824 */ 2825 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2826 2827 /** 2828 * Flag indicating that the left scroll indicator should be displayed 2829 * when this view can scroll left. 2830 */ 2831 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2832 2833 /** 2834 * Flag indicating that the right scroll indicator should be displayed 2835 * when this view can scroll right. 2836 */ 2837 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2838 2839 /** 2840 * Flag indicating that the start scroll indicator should be displayed 2841 * when this view can scroll in the start direction. 2842 */ 2843 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2844 2845 /** 2846 * Flag indicating that the end scroll indicator should be displayed 2847 * when this view can scroll in the end direction. 2848 */ 2849 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2850 2851 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2852 2853 static final int SCROLL_INDICATORS_NONE = 0x0000; 2854 2855 /** 2856 * Mask for use with setFlags indicating bits used for indicating which 2857 * scroll indicators are enabled. 2858 */ 2859 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2860 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2861 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2862 | PFLAG3_SCROLL_INDICATOR_END; 2863 2864 /** 2865 * Left-shift required to translate between public scroll indicator flags 2866 * and internal PFLAGS3 flags. When used as a right-shift, translates 2867 * PFLAGS3 flags to public flags. 2868 */ 2869 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2870 2871 /** @hide */ 2872 @Retention(RetentionPolicy.SOURCE) 2873 @IntDef(flag = true, 2874 value = { 2875 SCROLL_INDICATOR_TOP, 2876 SCROLL_INDICATOR_BOTTOM, 2877 SCROLL_INDICATOR_LEFT, 2878 SCROLL_INDICATOR_RIGHT, 2879 SCROLL_INDICATOR_START, 2880 SCROLL_INDICATOR_END, 2881 }) 2882 public @interface ScrollIndicators {} 2883 2884 /** 2885 * Scroll indicator direction for the top edge of the view. 2886 * 2887 * @see #setScrollIndicators(int) 2888 * @see #setScrollIndicators(int, int) 2889 * @see #getScrollIndicators() 2890 */ 2891 public static final int SCROLL_INDICATOR_TOP = 2892 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2893 2894 /** 2895 * Scroll indicator direction for the bottom edge of the view. 2896 * 2897 * @see #setScrollIndicators(int) 2898 * @see #setScrollIndicators(int, int) 2899 * @see #getScrollIndicators() 2900 */ 2901 public static final int SCROLL_INDICATOR_BOTTOM = 2902 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2903 2904 /** 2905 * Scroll indicator direction for the left edge of the view. 2906 * 2907 * @see #setScrollIndicators(int) 2908 * @see #setScrollIndicators(int, int) 2909 * @see #getScrollIndicators() 2910 */ 2911 public static final int SCROLL_INDICATOR_LEFT = 2912 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2913 2914 /** 2915 * Scroll indicator direction for the right edge of the view. 2916 * 2917 * @see #setScrollIndicators(int) 2918 * @see #setScrollIndicators(int, int) 2919 * @see #getScrollIndicators() 2920 */ 2921 public static final int SCROLL_INDICATOR_RIGHT = 2922 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2923 2924 /** 2925 * Scroll indicator direction for the starting edge of the view. 2926 * <p> 2927 * Resolved according to the view's layout direction, see 2928 * {@link #getLayoutDirection()} for more information. 2929 * 2930 * @see #setScrollIndicators(int) 2931 * @see #setScrollIndicators(int, int) 2932 * @see #getScrollIndicators() 2933 */ 2934 public static final int SCROLL_INDICATOR_START = 2935 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2936 2937 /** 2938 * Scroll indicator direction for the ending edge of the view. 2939 * <p> 2940 * Resolved according to the view's layout direction, see 2941 * {@link #getLayoutDirection()} for more information. 2942 * 2943 * @see #setScrollIndicators(int) 2944 * @see #setScrollIndicators(int, int) 2945 * @see #getScrollIndicators() 2946 */ 2947 public static final int SCROLL_INDICATOR_END = 2948 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2949 2950 /** 2951 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 2952 * into this view.<p> 2953 */ 2954 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 2955 2956 /** 2957 * Flag indicating that the view is a root of a keyboard navigation cluster. 2958 * 2959 * @see #isKeyboardNavigationCluster() 2960 * @see #setKeyboardNavigationCluster(boolean) 2961 */ 2962 private static final int PFLAG3_CLUSTER = 0x8000; 2963 2964 /** 2965 * Indicates that the user is currently touching the screen. 2966 * Currently used for the tooltip positioning only. 2967 */ 2968 private static final int PFLAG3_FINGER_DOWN = 0x20000; 2969 2970 /** 2971 * Flag indicating that this view is the default-focus view. 2972 * 2973 * @see #isFocusedByDefault() 2974 * @see #setFocusedByDefault(boolean) 2975 */ 2976 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 2977 2978 /** 2979 * Shift for the place where the autofill mode is stored in the pflags 2980 * 2981 * @see #getAutofillMode() 2982 * @see #setAutofillMode(int) 2983 */ 2984 private static final int PFLAG3_AUTOFILL_MODE_SHIFT = 19; 2985 2986 /** 2987 * Mask for autofill modes 2988 * 2989 * @see #getAutofillMode() 2990 * @see #setAutofillMode(int) 2991 */ 2992 private static final int PFLAG3_AUTOFILL_MODE_MASK = (AUTOFILL_MODE_INHERIT 2993 | AUTOFILL_MODE_AUTO | AUTOFILL_MODE_MANUAL) << PFLAG3_AUTOFILL_MODE_SHIFT; 2994 2995 /** 2996 * Shift for the bits in {@link #mPrivateFlags3} related to the 2997 * "importantForAutofill" attribute. 2998 */ 2999 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 21; 3000 3001 /** 3002 * Mask for obtaining the bits which specify how to determine 3003 * whether a view is important for autofill. 3004 */ 3005 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3006 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO) 3007 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3008 3009 /** 3010 * Whether this view has rendered elements that overlap (see {@link 3011 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3012 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3013 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3014 * determined by whatever {@link #hasOverlappingRendering()} returns. 3015 */ 3016 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3017 3018 /** 3019 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3020 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3021 */ 3022 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3023 3024 /** 3025 * Flag indicating that the view is temporarily detached from the parent view. 3026 * 3027 * @see #onStartTemporaryDetach() 3028 * @see #onFinishTemporaryDetach() 3029 */ 3030 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3031 3032 /** 3033 * Flag indicating that the view does not wish to be revealed within its parent 3034 * hierarchy when it gains focus. Expressed in the negative since the historical 3035 * default behavior is to reveal on focus; this flag suppresses that behavior. 3036 * 3037 * @see #setRevealOnFocusHint(boolean) 3038 * @see #getRevealOnFocusHint() 3039 */ 3040 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3041 3042 /* End of masks for mPrivateFlags3 */ 3043 3044 /** 3045 * Always allow a user to over-scroll this view, provided it is a 3046 * view that can scroll. 3047 * 3048 * @see #getOverScrollMode() 3049 * @see #setOverScrollMode(int) 3050 */ 3051 public static final int OVER_SCROLL_ALWAYS = 0; 3052 3053 /** 3054 * Allow a user to over-scroll this view only if the content is large 3055 * enough to meaningfully scroll, provided it is a view that can scroll. 3056 * 3057 * @see #getOverScrollMode() 3058 * @see #setOverScrollMode(int) 3059 */ 3060 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3061 3062 /** 3063 * Never allow a user to over-scroll this view. 3064 * 3065 * @see #getOverScrollMode() 3066 * @see #setOverScrollMode(int) 3067 */ 3068 public static final int OVER_SCROLL_NEVER = 2; 3069 3070 /** 3071 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3072 * requested the system UI (status bar) to be visible (the default). 3073 * 3074 * @see #setSystemUiVisibility(int) 3075 */ 3076 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3077 3078 /** 3079 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3080 * system UI to enter an unobtrusive "low profile" mode. 3081 * 3082 * <p>This is for use in games, book readers, video players, or any other 3083 * "immersive" application where the usual system chrome is deemed too distracting. 3084 * 3085 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3086 * 3087 * @see #setSystemUiVisibility(int) 3088 */ 3089 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3090 3091 /** 3092 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3093 * system navigation be temporarily hidden. 3094 * 3095 * <p>This is an even less obtrusive state than that called for by 3096 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3097 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3098 * those to disappear. This is useful (in conjunction with the 3099 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3100 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3101 * window flags) for displaying content using every last pixel on the display. 3102 * 3103 * <p>There is a limitation: because navigation controls are so important, the least user 3104 * interaction will cause them to reappear immediately. When this happens, both 3105 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3106 * so that both elements reappear at the same time. 3107 * 3108 * @see #setSystemUiVisibility(int) 3109 */ 3110 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3111 3112 /** 3113 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3114 * into the normal fullscreen mode so that its content can take over the screen 3115 * while still allowing the user to interact with the application. 3116 * 3117 * <p>This has the same visual effect as 3118 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3119 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3120 * meaning that non-critical screen decorations (such as the status bar) will be 3121 * hidden while the user is in the View's window, focusing the experience on 3122 * that content. Unlike the window flag, if you are using ActionBar in 3123 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3124 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3125 * hide the action bar. 3126 * 3127 * <p>This approach to going fullscreen is best used over the window flag when 3128 * it is a transient state -- that is, the application does this at certain 3129 * points in its user interaction where it wants to allow the user to focus 3130 * on content, but not as a continuous state. For situations where the application 3131 * would like to simply stay full screen the entire time (such as a game that 3132 * wants to take over the screen), the 3133 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3134 * is usually a better approach. The state set here will be removed by the system 3135 * in various situations (such as the user moving to another application) like 3136 * the other system UI states. 3137 * 3138 * <p>When using this flag, the application should provide some easy facility 3139 * for the user to go out of it. A common example would be in an e-book 3140 * reader, where tapping on the screen brings back whatever screen and UI 3141 * decorations that had been hidden while the user was immersed in reading 3142 * the book. 3143 * 3144 * @see #setSystemUiVisibility(int) 3145 */ 3146 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3147 3148 /** 3149 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3150 * flags, we would like a stable view of the content insets given to 3151 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3152 * will always represent the worst case that the application can expect 3153 * as a continuous state. In the stock Android UI this is the space for 3154 * the system bar, nav bar, and status bar, but not more transient elements 3155 * such as an input method. 3156 * 3157 * The stable layout your UI sees is based on the system UI modes you can 3158 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3159 * then you will get a stable layout for changes of the 3160 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3161 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3162 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3163 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3164 * with a stable layout. (Note that you should avoid using 3165 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3166 * 3167 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3168 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3169 * then a hidden status bar will be considered a "stable" state for purposes 3170 * here. This allows your UI to continually hide the status bar, while still 3171 * using the system UI flags to hide the action bar while still retaining 3172 * a stable layout. Note that changing the window fullscreen flag will never 3173 * provide a stable layout for a clean transition. 3174 * 3175 * <p>If you are using ActionBar in 3176 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3177 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3178 * insets it adds to those given to the application. 3179 */ 3180 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3181 3182 /** 3183 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3184 * to be laid out as if it has requested 3185 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3186 * allows it to avoid artifacts when switching in and out of that mode, at 3187 * the expense that some of its user interface may be covered by screen 3188 * decorations when they are shown. You can perform layout of your inner 3189 * UI elements to account for the navigation system UI through the 3190 * {@link #fitSystemWindows(Rect)} method. 3191 */ 3192 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3193 3194 /** 3195 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3196 * to be laid out as if it has requested 3197 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3198 * allows it to avoid artifacts when switching in and out of that mode, at 3199 * the expense that some of its user interface may be covered by screen 3200 * decorations when they are shown. You can perform layout of your inner 3201 * UI elements to account for non-fullscreen system UI through the 3202 * {@link #fitSystemWindows(Rect)} method. 3203 */ 3204 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3205 3206 /** 3207 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3208 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3209 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3210 * user interaction. 3211 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3212 * has an effect when used in combination with that flag.</p> 3213 */ 3214 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3215 3216 /** 3217 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3218 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3219 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3220 * experience while also hiding the system bars. If this flag is not set, 3221 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3222 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3223 * if the user swipes from the top of the screen. 3224 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3225 * system gestures, such as swiping from the top of the screen. These transient system bars 3226 * will overlay app’s content, may have some degree of transparency, and will automatically 3227 * hide after a short timeout. 3228 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3229 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3230 * with one or both of those flags.</p> 3231 */ 3232 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3233 3234 /** 3235 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3236 * is compatible with light status bar backgrounds. 3237 * 3238 * <p>For this to take effect, the window must request 3239 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3240 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3241 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3242 * FLAG_TRANSLUCENT_STATUS}. 3243 * 3244 * @see android.R.attr#windowLightStatusBar 3245 */ 3246 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3247 3248 /** 3249 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3250 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3251 */ 3252 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3253 3254 /** 3255 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3256 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3257 */ 3258 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3259 3260 /** 3261 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3262 * that is compatible with light navigation bar backgrounds. 3263 * 3264 * <p>For this to take effect, the window must request 3265 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3266 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3267 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3268 * FLAG_TRANSLUCENT_NAVIGATION}. 3269 */ 3270 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3271 3272 /** 3273 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3274 */ 3275 @Deprecated 3276 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3277 3278 /** 3279 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3280 */ 3281 @Deprecated 3282 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3283 3284 /** 3285 * @hide 3286 * 3287 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3288 * out of the public fields to keep the undefined bits out of the developer's way. 3289 * 3290 * Flag to make the status bar not expandable. Unless you also 3291 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3292 */ 3293 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3294 3295 /** 3296 * @hide 3297 * 3298 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3299 * out of the public fields to keep the undefined bits out of the developer's way. 3300 * 3301 * Flag to hide notification icons and scrolling ticker text. 3302 */ 3303 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3304 3305 /** 3306 * @hide 3307 * 3308 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3309 * out of the public fields to keep the undefined bits out of the developer's way. 3310 * 3311 * Flag to disable incoming notification alerts. This will not block 3312 * icons, but it will block sound, vibrating and other visual or aural notifications. 3313 */ 3314 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3315 3316 /** 3317 * @hide 3318 * 3319 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3320 * out of the public fields to keep the undefined bits out of the developer's way. 3321 * 3322 * Flag to hide only the scrolling ticker. Note that 3323 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3324 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3325 */ 3326 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3327 3328 /** 3329 * @hide 3330 * 3331 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3332 * out of the public fields to keep the undefined bits out of the developer's way. 3333 * 3334 * Flag to hide the center system info area. 3335 */ 3336 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3337 3338 /** 3339 * @hide 3340 * 3341 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3342 * out of the public fields to keep the undefined bits out of the developer's way. 3343 * 3344 * Flag to hide only the home button. Don't use this 3345 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3346 */ 3347 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3348 3349 /** 3350 * @hide 3351 * 3352 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3353 * out of the public fields to keep the undefined bits out of the developer's way. 3354 * 3355 * Flag to hide only the back button. Don't use this 3356 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3357 */ 3358 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3359 3360 /** 3361 * @hide 3362 * 3363 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3364 * out of the public fields to keep the undefined bits out of the developer's way. 3365 * 3366 * Flag to hide only the clock. You might use this if your activity has 3367 * its own clock making the status bar's clock redundant. 3368 */ 3369 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3370 3371 /** 3372 * @hide 3373 * 3374 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3375 * out of the public fields to keep the undefined bits out of the developer's way. 3376 * 3377 * Flag to hide only the recent apps button. Don't use this 3378 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3379 */ 3380 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3381 3382 /** 3383 * @hide 3384 * 3385 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3386 * out of the public fields to keep the undefined bits out of the developer's way. 3387 * 3388 * Flag to disable the global search gesture. Don't use this 3389 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3390 */ 3391 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3392 3393 /** 3394 * @hide 3395 * 3396 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3397 * out of the public fields to keep the undefined bits out of the developer's way. 3398 * 3399 * Flag to specify that the status bar is displayed in transient mode. 3400 */ 3401 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3402 3403 /** 3404 * @hide 3405 * 3406 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3407 * out of the public fields to keep the undefined bits out of the developer's way. 3408 * 3409 * Flag to specify that the navigation bar is displayed in transient mode. 3410 */ 3411 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3412 3413 /** 3414 * @hide 3415 * 3416 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3417 * out of the public fields to keep the undefined bits out of the developer's way. 3418 * 3419 * Flag to specify that the hidden status bar would like to be shown. 3420 */ 3421 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3422 3423 /** 3424 * @hide 3425 * 3426 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3427 * out of the public fields to keep the undefined bits out of the developer's way. 3428 * 3429 * Flag to specify that the hidden navigation bar would like to be shown. 3430 */ 3431 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3432 3433 /** 3434 * @hide 3435 * 3436 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3437 * out of the public fields to keep the undefined bits out of the developer's way. 3438 * 3439 * Flag to specify that the status bar is displayed in translucent mode. 3440 */ 3441 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3442 3443 /** 3444 * @hide 3445 * 3446 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3447 * out of the public fields to keep the undefined bits out of the developer's way. 3448 * 3449 * Flag to specify that the navigation bar is displayed in translucent mode. 3450 */ 3451 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3452 3453 /** 3454 * @hide 3455 * 3456 * Makes navigation bar transparent (but not the status bar). 3457 */ 3458 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3459 3460 /** 3461 * @hide 3462 * 3463 * Makes status bar transparent (but not the navigation bar). 3464 */ 3465 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3466 3467 /** 3468 * @hide 3469 * 3470 * Makes both status bar and navigation bar transparent. 3471 */ 3472 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3473 | STATUS_BAR_TRANSPARENT; 3474 3475 /** 3476 * @hide 3477 */ 3478 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3479 3480 /** 3481 * These are the system UI flags that can be cleared by events outside 3482 * of an application. Currently this is just the ability to tap on the 3483 * screen while hiding the navigation bar to have it return. 3484 * @hide 3485 */ 3486 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3487 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3488 | SYSTEM_UI_FLAG_FULLSCREEN; 3489 3490 /** 3491 * Flags that can impact the layout in relation to system UI. 3492 */ 3493 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3494 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3495 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3496 3497 /** @hide */ 3498 @IntDef(flag = true, 3499 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3500 @Retention(RetentionPolicy.SOURCE) 3501 public @interface FindViewFlags {} 3502 3503 /** 3504 * Find views that render the specified text. 3505 * 3506 * @see #findViewsWithText(ArrayList, CharSequence, int) 3507 */ 3508 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3509 3510 /** 3511 * Find find views that contain the specified content description. 3512 * 3513 * @see #findViewsWithText(ArrayList, CharSequence, int) 3514 */ 3515 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3516 3517 /** 3518 * Find views that contain {@link AccessibilityNodeProvider}. Such 3519 * a View is a root of virtual view hierarchy and may contain the searched 3520 * text. If this flag is set Views with providers are automatically 3521 * added and it is a responsibility of the client to call the APIs of 3522 * the provider to determine whether the virtual tree rooted at this View 3523 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3524 * representing the virtual views with this text. 3525 * 3526 * @see #findViewsWithText(ArrayList, CharSequence, int) 3527 * 3528 * @hide 3529 */ 3530 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3531 3532 /** 3533 * The undefined cursor position. 3534 * 3535 * @hide 3536 */ 3537 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3538 3539 /** 3540 * Indicates that the screen has changed state and is now off. 3541 * 3542 * @see #onScreenStateChanged(int) 3543 */ 3544 public static final int SCREEN_STATE_OFF = 0x0; 3545 3546 /** 3547 * Indicates that the screen has changed state and is now on. 3548 * 3549 * @see #onScreenStateChanged(int) 3550 */ 3551 public static final int SCREEN_STATE_ON = 0x1; 3552 3553 /** 3554 * Indicates no axis of view scrolling. 3555 */ 3556 public static final int SCROLL_AXIS_NONE = 0; 3557 3558 /** 3559 * Indicates scrolling along the horizontal axis. 3560 */ 3561 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3562 3563 /** 3564 * Indicates scrolling along the vertical axis. 3565 */ 3566 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3567 3568 /** 3569 * Controls the over-scroll mode for this view. 3570 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3571 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3572 * and {@link #OVER_SCROLL_NEVER}. 3573 */ 3574 private int mOverScrollMode; 3575 3576 /** 3577 * The parent this view is attached to. 3578 * {@hide} 3579 * 3580 * @see #getParent() 3581 */ 3582 protected ViewParent mParent; 3583 3584 /** 3585 * {@hide} 3586 */ 3587 AttachInfo mAttachInfo; 3588 3589 /** 3590 * {@hide} 3591 */ 3592 @ViewDebug.ExportedProperty(flagMapping = { 3593 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3594 name = "FORCE_LAYOUT"), 3595 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3596 name = "LAYOUT_REQUIRED"), 3597 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3598 name = "DRAWING_CACHE_INVALID", outputIf = false), 3599 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3600 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3601 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3602 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3603 }, formatToHexString = true) 3604 3605 /* @hide */ 3606 public int mPrivateFlags; 3607 int mPrivateFlags2; 3608 int mPrivateFlags3; 3609 3610 /** 3611 * This view's request for the visibility of the status bar. 3612 * @hide 3613 */ 3614 @ViewDebug.ExportedProperty(flagMapping = { 3615 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3616 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3617 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3618 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3619 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3620 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3621 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3622 equals = SYSTEM_UI_FLAG_VISIBLE, 3623 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3624 }, formatToHexString = true) 3625 int mSystemUiVisibility; 3626 3627 /** 3628 * Reference count for transient state. 3629 * @see #setHasTransientState(boolean) 3630 */ 3631 int mTransientStateCount = 0; 3632 3633 /** 3634 * Count of how many windows this view has been attached to. 3635 */ 3636 int mWindowAttachCount; 3637 3638 /** 3639 * The layout parameters associated with this view and used by the parent 3640 * {@link android.view.ViewGroup} to determine how this view should be 3641 * laid out. 3642 * {@hide} 3643 */ 3644 protected ViewGroup.LayoutParams mLayoutParams; 3645 3646 /** 3647 * The view flags hold various views states. 3648 * {@hide} 3649 */ 3650 @ViewDebug.ExportedProperty(formatToHexString = true) 3651 int mViewFlags; 3652 3653 static class TransformationInfo { 3654 /** 3655 * The transform matrix for the View. This transform is calculated internally 3656 * based on the translation, rotation, and scale properties. 3657 * 3658 * Do *not* use this variable directly; instead call getMatrix(), which will 3659 * load the value from the View's RenderNode. 3660 */ 3661 private final Matrix mMatrix = new Matrix(); 3662 3663 /** 3664 * The inverse transform matrix for the View. This transform is calculated 3665 * internally based on the translation, rotation, and scale properties. 3666 * 3667 * Do *not* use this variable directly; instead call getInverseMatrix(), 3668 * which will load the value from the View's RenderNode. 3669 */ 3670 private Matrix mInverseMatrix; 3671 3672 /** 3673 * The opacity of the View. This is a value from 0 to 1, where 0 means 3674 * completely transparent and 1 means completely opaque. 3675 */ 3676 @ViewDebug.ExportedProperty 3677 float mAlpha = 1f; 3678 3679 /** 3680 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3681 * property only used by transitions, which is composited with the other alpha 3682 * values to calculate the final visual alpha value. 3683 */ 3684 float mTransitionAlpha = 1f; 3685 } 3686 3687 /** @hide */ 3688 public TransformationInfo mTransformationInfo; 3689 3690 /** 3691 * Current clip bounds. to which all drawing of this view are constrained. 3692 */ 3693 Rect mClipBounds = null; 3694 3695 private boolean mLastIsOpaque; 3696 3697 /** 3698 * The distance in pixels from the left edge of this view's parent 3699 * to the left edge of this view. 3700 * {@hide} 3701 */ 3702 @ViewDebug.ExportedProperty(category = "layout") 3703 protected int mLeft; 3704 /** 3705 * The distance in pixels from the left edge of this view's parent 3706 * to the right edge of this view. 3707 * {@hide} 3708 */ 3709 @ViewDebug.ExportedProperty(category = "layout") 3710 protected int mRight; 3711 /** 3712 * The distance in pixels from the top edge of this view's parent 3713 * to the top edge of this view. 3714 * {@hide} 3715 */ 3716 @ViewDebug.ExportedProperty(category = "layout") 3717 protected int mTop; 3718 /** 3719 * The distance in pixels from the top edge of this view's parent 3720 * to the bottom edge of this view. 3721 * {@hide} 3722 */ 3723 @ViewDebug.ExportedProperty(category = "layout") 3724 protected int mBottom; 3725 3726 /** 3727 * The offset, in pixels, by which the content of this view is scrolled 3728 * horizontally. 3729 * {@hide} 3730 */ 3731 @ViewDebug.ExportedProperty(category = "scrolling") 3732 protected int mScrollX; 3733 /** 3734 * The offset, in pixels, by which the content of this view is scrolled 3735 * vertically. 3736 * {@hide} 3737 */ 3738 @ViewDebug.ExportedProperty(category = "scrolling") 3739 protected int mScrollY; 3740 3741 /** 3742 * The left padding in pixels, that is the distance in pixels between the 3743 * left edge of this view and the left edge of its content. 3744 * {@hide} 3745 */ 3746 @ViewDebug.ExportedProperty(category = "padding") 3747 protected int mPaddingLeft = 0; 3748 /** 3749 * The right padding in pixels, that is the distance in pixels between the 3750 * right edge of this view and the right edge of its content. 3751 * {@hide} 3752 */ 3753 @ViewDebug.ExportedProperty(category = "padding") 3754 protected int mPaddingRight = 0; 3755 /** 3756 * The top padding in pixels, that is the distance in pixels between the 3757 * top edge of this view and the top edge of its content. 3758 * {@hide} 3759 */ 3760 @ViewDebug.ExportedProperty(category = "padding") 3761 protected int mPaddingTop; 3762 /** 3763 * The bottom padding in pixels, that is the distance in pixels between the 3764 * bottom edge of this view and the bottom edge of its content. 3765 * {@hide} 3766 */ 3767 @ViewDebug.ExportedProperty(category = "padding") 3768 protected int mPaddingBottom; 3769 3770 /** 3771 * The layout insets in pixels, that is the distance in pixels between the 3772 * visible edges of this view its bounds. 3773 */ 3774 private Insets mLayoutInsets; 3775 3776 /** 3777 * Briefly describes the view and is primarily used for accessibility support. 3778 */ 3779 private CharSequence mContentDescription; 3780 3781 /** 3782 * Specifies the id of a view for which this view serves as a label for 3783 * accessibility purposes. 3784 */ 3785 private int mLabelForId = View.NO_ID; 3786 3787 /** 3788 * Predicate for matching labeled view id with its label for 3789 * accessibility purposes. 3790 */ 3791 private MatchLabelForPredicate mMatchLabelForPredicate; 3792 3793 /** 3794 * Specifies a view before which this one is visited in accessibility traversal. 3795 */ 3796 private int mAccessibilityTraversalBeforeId = NO_ID; 3797 3798 /** 3799 * Specifies a view after which this one is visited in accessibility traversal. 3800 */ 3801 private int mAccessibilityTraversalAfterId = NO_ID; 3802 3803 /** 3804 * Predicate for matching a view by its id. 3805 */ 3806 private MatchIdPredicate mMatchIdPredicate; 3807 3808 /** 3809 * Cache the paddingRight set by the user to append to the scrollbar's size. 3810 * 3811 * @hide 3812 */ 3813 @ViewDebug.ExportedProperty(category = "padding") 3814 protected int mUserPaddingRight; 3815 3816 /** 3817 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3818 * 3819 * @hide 3820 */ 3821 @ViewDebug.ExportedProperty(category = "padding") 3822 protected int mUserPaddingBottom; 3823 3824 /** 3825 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3826 * 3827 * @hide 3828 */ 3829 @ViewDebug.ExportedProperty(category = "padding") 3830 protected int mUserPaddingLeft; 3831 3832 /** 3833 * Cache the paddingStart set by the user to append to the scrollbar's size. 3834 * 3835 */ 3836 @ViewDebug.ExportedProperty(category = "padding") 3837 int mUserPaddingStart; 3838 3839 /** 3840 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3841 * 3842 */ 3843 @ViewDebug.ExportedProperty(category = "padding") 3844 int mUserPaddingEnd; 3845 3846 /** 3847 * Cache initial left padding. 3848 * 3849 * @hide 3850 */ 3851 int mUserPaddingLeftInitial; 3852 3853 /** 3854 * Cache initial right padding. 3855 * 3856 * @hide 3857 */ 3858 int mUserPaddingRightInitial; 3859 3860 /** 3861 * Default undefined padding 3862 */ 3863 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3864 3865 /** 3866 * Cache if a left padding has been defined 3867 */ 3868 private boolean mLeftPaddingDefined = false; 3869 3870 /** 3871 * Cache if a right padding has been defined 3872 */ 3873 private boolean mRightPaddingDefined = false; 3874 3875 /** 3876 * @hide 3877 */ 3878 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3879 /** 3880 * @hide 3881 */ 3882 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3883 3884 private LongSparseLongArray mMeasureCache; 3885 3886 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3887 private Drawable mBackground; 3888 private TintInfo mBackgroundTint; 3889 3890 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3891 private ForegroundInfo mForegroundInfo; 3892 3893 private Drawable mScrollIndicatorDrawable; 3894 3895 /** 3896 * RenderNode used for backgrounds. 3897 * <p> 3898 * When non-null and valid, this is expected to contain an up-to-date copy 3899 * of the background drawable. It is cleared on temporary detach, and reset 3900 * on cleanup. 3901 */ 3902 private RenderNode mBackgroundRenderNode; 3903 3904 private int mBackgroundResource; 3905 private boolean mBackgroundSizeChanged; 3906 3907 private String mTransitionName; 3908 3909 static class TintInfo { 3910 ColorStateList mTintList; 3911 PorterDuff.Mode mTintMode; 3912 boolean mHasTintMode; 3913 boolean mHasTintList; 3914 } 3915 3916 private static class ForegroundInfo { 3917 private Drawable mDrawable; 3918 private TintInfo mTintInfo; 3919 private int mGravity = Gravity.FILL; 3920 private boolean mInsidePadding = true; 3921 private boolean mBoundsChanged = true; 3922 private final Rect mSelfBounds = new Rect(); 3923 private final Rect mOverlayBounds = new Rect(); 3924 } 3925 3926 static class ListenerInfo { 3927 /** 3928 * Listener used to dispatch focus change events. 3929 * This field should be made private, so it is hidden from the SDK. 3930 * {@hide} 3931 */ 3932 protected OnFocusChangeListener mOnFocusChangeListener; 3933 3934 /** 3935 * Listeners for layout change events. 3936 */ 3937 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 3938 3939 protected OnScrollChangeListener mOnScrollChangeListener; 3940 3941 /** 3942 * Listeners for attach events. 3943 */ 3944 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 3945 3946 /** 3947 * Listener used to dispatch click events. 3948 * This field should be made private, so it is hidden from the SDK. 3949 * {@hide} 3950 */ 3951 public OnClickListener mOnClickListener; 3952 3953 /** 3954 * Listener used to dispatch long click events. 3955 * This field should be made private, so it is hidden from the SDK. 3956 * {@hide} 3957 */ 3958 protected OnLongClickListener mOnLongClickListener; 3959 3960 /** 3961 * Listener used to dispatch context click events. This field should be made private, so it 3962 * is hidden from the SDK. 3963 * {@hide} 3964 */ 3965 protected OnContextClickListener mOnContextClickListener; 3966 3967 /** 3968 * Listener used to build the context menu. 3969 * This field should be made private, so it is hidden from the SDK. 3970 * {@hide} 3971 */ 3972 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 3973 3974 private OnKeyListener mOnKeyListener; 3975 3976 private OnTouchListener mOnTouchListener; 3977 3978 private OnHoverListener mOnHoverListener; 3979 3980 private OnGenericMotionListener mOnGenericMotionListener; 3981 3982 private OnDragListener mOnDragListener; 3983 3984 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 3985 3986 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 3987 3988 OnCapturedPointerListener mOnCapturedPointerListener; 3989 } 3990 3991 ListenerInfo mListenerInfo; 3992 3993 private static class TooltipInfo { 3994 /** 3995 * Text to be displayed in a tooltip popup. 3996 */ 3997 @Nullable 3998 CharSequence mTooltipText; 3999 4000 /** 4001 * View-relative position of the tooltip anchor point. 4002 */ 4003 int mAnchorX; 4004 int mAnchorY; 4005 4006 /** 4007 * The tooltip popup. 4008 */ 4009 @Nullable 4010 TooltipPopup mTooltipPopup; 4011 4012 /** 4013 * Set to true if the tooltip was shown as a result of a long click. 4014 */ 4015 boolean mTooltipFromLongClick; 4016 4017 /** 4018 * Keep these Runnables so that they can be used to reschedule. 4019 */ 4020 Runnable mShowTooltipRunnable; 4021 Runnable mHideTooltipRunnable; 4022 } 4023 4024 TooltipInfo mTooltipInfo; 4025 4026 // Temporary values used to hold (x,y) coordinates when delegating from the 4027 // two-arg performLongClick() method to the legacy no-arg version. 4028 private float mLongClickX = Float.NaN; 4029 private float mLongClickY = Float.NaN; 4030 4031 /** 4032 * The application environment this view lives in. 4033 * This field should be made private, so it is hidden from the SDK. 4034 * {@hide} 4035 */ 4036 @ViewDebug.ExportedProperty(deepExport = true) 4037 protected Context mContext; 4038 4039 private final Resources mResources; 4040 4041 private ScrollabilityCache mScrollCache; 4042 4043 private int[] mDrawableState = null; 4044 4045 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4046 4047 /** 4048 * Animator that automatically runs based on state changes. 4049 */ 4050 private StateListAnimator mStateListAnimator; 4051 4052 /** 4053 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4054 * the user may specify which view to go to next. 4055 */ 4056 private int mNextFocusLeftId = View.NO_ID; 4057 4058 /** 4059 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4060 * the user may specify which view to go to next. 4061 */ 4062 private int mNextFocusRightId = View.NO_ID; 4063 4064 /** 4065 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4066 * the user may specify which view to go to next. 4067 */ 4068 private int mNextFocusUpId = View.NO_ID; 4069 4070 /** 4071 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4072 * the user may specify which view to go to next. 4073 */ 4074 private int mNextFocusDownId = View.NO_ID; 4075 4076 /** 4077 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4078 * the user may specify which view to go to next. 4079 */ 4080 int mNextFocusForwardId = View.NO_ID; 4081 4082 /** 4083 * User-specified next keyboard navigation cluster. 4084 */ 4085 int mNextClusterForwardId = View.NO_ID; 4086 4087 private CheckForLongPress mPendingCheckForLongPress; 4088 private CheckForTap mPendingCheckForTap = null; 4089 private PerformClick mPerformClick; 4090 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4091 4092 private UnsetPressedState mUnsetPressedState; 4093 4094 /** 4095 * Whether the long press's action has been invoked. The tap's action is invoked on the 4096 * up event while a long press is invoked as soon as the long press duration is reached, so 4097 * a long press could be performed before the tap is checked, in which case the tap's action 4098 * should not be invoked. 4099 */ 4100 private boolean mHasPerformedLongPress; 4101 4102 /** 4103 * Whether a context click button is currently pressed down. This is true when the stylus is 4104 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4105 * pressed. This is false once the button is released or if the stylus has been lifted. 4106 */ 4107 private boolean mInContextButtonPress; 4108 4109 /** 4110 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4111 * true after a stylus button press has occured, when the next up event should not be recognized 4112 * as a tap. 4113 */ 4114 private boolean mIgnoreNextUpEvent; 4115 4116 /** 4117 * The minimum height of the view. We'll try our best to have the height 4118 * of this view to at least this amount. 4119 */ 4120 @ViewDebug.ExportedProperty(category = "measurement") 4121 private int mMinHeight; 4122 4123 /** 4124 * The minimum width of the view. We'll try our best to have the width 4125 * of this view to at least this amount. 4126 */ 4127 @ViewDebug.ExportedProperty(category = "measurement") 4128 private int mMinWidth; 4129 4130 /** 4131 * The delegate to handle touch events that are physically in this view 4132 * but should be handled by another view. 4133 */ 4134 private TouchDelegate mTouchDelegate = null; 4135 4136 /** 4137 * Solid color to use as a background when creating the drawing cache. Enables 4138 * the cache to use 16 bit bitmaps instead of 32 bit. 4139 */ 4140 private int mDrawingCacheBackgroundColor = 0; 4141 4142 /** 4143 * Special tree observer used when mAttachInfo is null. 4144 */ 4145 private ViewTreeObserver mFloatingTreeObserver; 4146 4147 /** 4148 * Cache the touch slop from the context that created the view. 4149 */ 4150 private int mTouchSlop; 4151 4152 /** 4153 * Object that handles automatic animation of view properties. 4154 */ 4155 private ViewPropertyAnimator mAnimator = null; 4156 4157 /** 4158 * List of registered FrameMetricsObservers. 4159 */ 4160 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4161 4162 /** 4163 * Flag indicating that a drag can cross window boundaries. When 4164 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4165 * with this flag set, all visible applications with targetSdkVersion >= 4166 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4167 * in the drag operation and receive the dragged content. 4168 * 4169 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4170 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 4171 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 4172 */ 4173 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 4174 4175 /** 4176 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4177 * request read access to the content URI(s) contained in the {@link ClipData} object. 4178 * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION 4179 */ 4180 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 4181 4182 /** 4183 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4184 * request write access to the content URI(s) contained in the {@link ClipData} object. 4185 * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION 4186 */ 4187 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 4188 4189 /** 4190 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4191 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 4192 * reboots until explicitly revoked with 4193 * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}. 4194 * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION 4195 */ 4196 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 4197 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 4198 4199 /** 4200 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4201 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 4202 * match against the original granted URI. 4203 * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION 4204 */ 4205 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 4206 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 4207 4208 /** 4209 * Flag indicating that the drag shadow will be opaque. When 4210 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4211 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 4212 */ 4213 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 4214 4215 /** 4216 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 4217 */ 4218 private float mVerticalScrollFactor; 4219 4220 /** 4221 * Position of the vertical scroll bar. 4222 */ 4223 private int mVerticalScrollbarPosition; 4224 4225 /** 4226 * Position the scroll bar at the default position as determined by the system. 4227 */ 4228 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 4229 4230 /** 4231 * Position the scroll bar along the left edge. 4232 */ 4233 public static final int SCROLLBAR_POSITION_LEFT = 1; 4234 4235 /** 4236 * Position the scroll bar along the right edge. 4237 */ 4238 public static final int SCROLLBAR_POSITION_RIGHT = 2; 4239 4240 /** 4241 * Indicates that the view does not have a layer. 4242 * 4243 * @see #getLayerType() 4244 * @see #setLayerType(int, android.graphics.Paint) 4245 * @see #LAYER_TYPE_SOFTWARE 4246 * @see #LAYER_TYPE_HARDWARE 4247 */ 4248 public static final int LAYER_TYPE_NONE = 0; 4249 4250 /** 4251 * <p>Indicates that the view has a software layer. A software layer is backed 4252 * by a bitmap and causes the view to be rendered using Android's software 4253 * rendering pipeline, even if hardware acceleration is enabled.</p> 4254 * 4255 * <p>Software layers have various usages:</p> 4256 * <p>When the application is not using hardware acceleration, a software layer 4257 * is useful to apply a specific color filter and/or blending mode and/or 4258 * translucency to a view and all its children.</p> 4259 * <p>When the application is using hardware acceleration, a software layer 4260 * is useful to render drawing primitives not supported by the hardware 4261 * accelerated pipeline. It can also be used to cache a complex view tree 4262 * into a texture and reduce the complexity of drawing operations. For instance, 4263 * when animating a complex view tree with a translation, a software layer can 4264 * be used to render the view tree only once.</p> 4265 * <p>Software layers should be avoided when the affected view tree updates 4266 * often. Every update will require to re-render the software layer, which can 4267 * potentially be slow (particularly when hardware acceleration is turned on 4268 * since the layer will have to be uploaded into a hardware texture after every 4269 * update.)</p> 4270 * 4271 * @see #getLayerType() 4272 * @see #setLayerType(int, android.graphics.Paint) 4273 * @see #LAYER_TYPE_NONE 4274 * @see #LAYER_TYPE_HARDWARE 4275 */ 4276 public static final int LAYER_TYPE_SOFTWARE = 1; 4277 4278 /** 4279 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4280 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4281 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4282 * rendering pipeline, but only if hardware acceleration is turned on for the 4283 * view hierarchy. When hardware acceleration is turned off, hardware layers 4284 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4285 * 4286 * <p>A hardware layer is useful to apply a specific color filter and/or 4287 * blending mode and/or translucency to a view and all its children.</p> 4288 * <p>A hardware layer can be used to cache a complex view tree into a 4289 * texture and reduce the complexity of drawing operations. For instance, 4290 * when animating a complex view tree with a translation, a hardware layer can 4291 * be used to render the view tree only once.</p> 4292 * <p>A hardware layer can also be used to increase the rendering quality when 4293 * rotation transformations are applied on a view. It can also be used to 4294 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4295 * 4296 * @see #getLayerType() 4297 * @see #setLayerType(int, android.graphics.Paint) 4298 * @see #LAYER_TYPE_NONE 4299 * @see #LAYER_TYPE_SOFTWARE 4300 */ 4301 public static final int LAYER_TYPE_HARDWARE = 2; 4302 4303 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4304 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4305 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4306 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4307 }) 4308 int mLayerType = LAYER_TYPE_NONE; 4309 Paint mLayerPaint; 4310 4311 /** 4312 * Set to true when drawing cache is enabled and cannot be created. 4313 * 4314 * @hide 4315 */ 4316 public boolean mCachingFailed; 4317 private Bitmap mDrawingCache; 4318 private Bitmap mUnscaledDrawingCache; 4319 4320 /** 4321 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4322 * <p> 4323 * When non-null and valid, this is expected to contain an up-to-date copy 4324 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4325 * cleanup. 4326 */ 4327 final RenderNode mRenderNode; 4328 4329 /** 4330 * Set to true when the view is sending hover accessibility events because it 4331 * is the innermost hovered view. 4332 */ 4333 private boolean mSendingHoverAccessibilityEvents; 4334 4335 /** 4336 * Delegate for injecting accessibility functionality. 4337 */ 4338 AccessibilityDelegate mAccessibilityDelegate; 4339 4340 /** 4341 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4342 * and add/remove objects to/from the overlay directly through the Overlay methods. 4343 */ 4344 ViewOverlay mOverlay; 4345 4346 /** 4347 * The currently active parent view for receiving delegated nested scrolling events. 4348 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4349 * by {@link #stopNestedScroll()} at the same point where we clear 4350 * requestDisallowInterceptTouchEvent. 4351 */ 4352 private ViewParent mNestedScrollingParent; 4353 4354 /** 4355 * Consistency verifier for debugging purposes. 4356 * @hide 4357 */ 4358 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4359 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4360 new InputEventConsistencyVerifier(this, 0) : null; 4361 4362 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4363 4364 private int[] mTempNestedScrollConsumed; 4365 4366 /** 4367 * An overlay is going to draw this View instead of being drawn as part of this 4368 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4369 * when this view is invalidated. 4370 */ 4371 GhostView mGhostView; 4372 4373 /** 4374 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4375 * @hide 4376 */ 4377 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4378 public String[] mAttributes; 4379 4380 /** 4381 * Maps a Resource id to its name. 4382 */ 4383 private static SparseArray<String> mAttributeMap; 4384 4385 /** 4386 * Queue of pending runnables. Used to postpone calls to post() until this 4387 * view is attached and has a handler. 4388 */ 4389 private HandlerActionQueue mRunQueue; 4390 4391 /** 4392 * The pointer icon when the mouse hovers on this view. The default is null. 4393 */ 4394 private PointerIcon mPointerIcon; 4395 4396 /** 4397 * @hide 4398 */ 4399 String mStartActivityRequestWho; 4400 4401 @Nullable 4402 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4403 4404 /** 4405 * Simple constructor to use when creating a view from code. 4406 * 4407 * @param context The Context the view is running in, through which it can 4408 * access the current theme, resources, etc. 4409 */ 4410 public View(Context context) { 4411 mContext = context; 4412 mResources = context != null ? context.getResources() : null; 4413 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 4414 // Set some flags defaults 4415 mPrivateFlags2 = 4416 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4417 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4418 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4419 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4420 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4421 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4422 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4423 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4424 mUserPaddingStart = UNDEFINED_PADDING; 4425 mUserPaddingEnd = UNDEFINED_PADDING; 4426 mRenderNode = RenderNode.create(getClass().getName(), this); 4427 4428 if (!sCompatibilityDone && context != null) { 4429 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4430 4431 // Older apps may need this compatibility hack for measurement. 4432 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 4433 4434 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4435 // of whether a layout was requested on that View. 4436 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 4437 4438 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 4439 4440 // In M and newer, our widgets can pass a "hint" value in the size 4441 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4442 // know what the expected parent size is going to be, so e.g. list items can size 4443 // themselves at 1/3 the size of their container. It breaks older apps though, 4444 // specifically apps that use some popular open source libraries. 4445 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 4446 4447 // Old versions of the platform would give different results from 4448 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4449 // modes, so we always need to run an additional EXACTLY pass. 4450 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 4451 4452 // Prior to N, layout params could change without requiring a 4453 // subsequent call to setLayoutParams() and they would usually 4454 // work. Partial layout breaks this assumption. 4455 sLayoutParamsAlwaysChanged = targetSdkVersion <= Build.VERSION_CODES.M; 4456 4457 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4458 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4459 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 4460 4461 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4462 // in apps so we target check it to avoid breaking existing apps. 4463 sPreserveMarginParamsInLayoutParamConversion = 4464 targetSdkVersion >= Build.VERSION_CODES.N; 4465 4466 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 4467 4468 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 4469 4470 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 4471 4472 sCompatibilityDone = true; 4473 } 4474 } 4475 4476 /** 4477 * Constructor that is called when inflating a view from XML. This is called 4478 * when a view is being constructed from an XML file, supplying attributes 4479 * that were specified in the XML file. This version uses a default style of 4480 * 0, so the only attribute values applied are those in the Context's Theme 4481 * and the given AttributeSet. 4482 * 4483 * <p> 4484 * The method onFinishInflate() will be called after all children have been 4485 * added. 4486 * 4487 * @param context The Context the view is running in, through which it can 4488 * access the current theme, resources, etc. 4489 * @param attrs The attributes of the XML tag that is inflating the view. 4490 * @see #View(Context, AttributeSet, int) 4491 */ 4492 public View(Context context, @Nullable AttributeSet attrs) { 4493 this(context, attrs, 0); 4494 } 4495 4496 /** 4497 * Perform inflation from XML and apply a class-specific base style from a 4498 * theme attribute. This constructor of View allows subclasses to use their 4499 * own base style when they are inflating. For example, a Button class's 4500 * constructor would call this version of the super class constructor and 4501 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4502 * allows the theme's button style to modify all of the base view attributes 4503 * (in particular its background) as well as the Button class's attributes. 4504 * 4505 * @param context The Context the view is running in, through which it can 4506 * access the current theme, resources, etc. 4507 * @param attrs The attributes of the XML tag that is inflating the view. 4508 * @param defStyleAttr An attribute in the current theme that contains a 4509 * reference to a style resource that supplies default values for 4510 * the view. Can be 0 to not look for defaults. 4511 * @see #View(Context, AttributeSet) 4512 */ 4513 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4514 this(context, attrs, defStyleAttr, 0); 4515 } 4516 4517 /** 4518 * Perform inflation from XML and apply a class-specific base style from a 4519 * theme attribute or style resource. This constructor of View allows 4520 * subclasses to use their own base style when they are inflating. 4521 * <p> 4522 * When determining the final value of a particular attribute, there are 4523 * four inputs that come into play: 4524 * <ol> 4525 * <li>Any attribute values in the given AttributeSet. 4526 * <li>The style resource specified in the AttributeSet (named "style"). 4527 * <li>The default style specified by <var>defStyleAttr</var>. 4528 * <li>The default style specified by <var>defStyleRes</var>. 4529 * <li>The base values in this theme. 4530 * </ol> 4531 * <p> 4532 * Each of these inputs is considered in-order, with the first listed taking 4533 * precedence over the following ones. In other words, if in the 4534 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4535 * , then the button's text will <em>always</em> be black, regardless of 4536 * what is specified in any of the styles. 4537 * 4538 * @param context The Context the view is running in, through which it can 4539 * access the current theme, resources, etc. 4540 * @param attrs The attributes of the XML tag that is inflating the view. 4541 * @param defStyleAttr An attribute in the current theme that contains a 4542 * reference to a style resource that supplies default values for 4543 * the view. Can be 0 to not look for defaults. 4544 * @param defStyleRes A resource identifier of a style resource that 4545 * supplies default values for the view, used only if 4546 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4547 * to not look for defaults. 4548 * @see #View(Context, AttributeSet, int) 4549 */ 4550 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4551 this(context); 4552 4553 final TypedArray a = context.obtainStyledAttributes( 4554 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4555 4556 if (mDebugViewAttributes) { 4557 saveAttributeData(attrs, a); 4558 } 4559 4560 Drawable background = null; 4561 4562 int leftPadding = -1; 4563 int topPadding = -1; 4564 int rightPadding = -1; 4565 int bottomPadding = -1; 4566 int startPadding = UNDEFINED_PADDING; 4567 int endPadding = UNDEFINED_PADDING; 4568 4569 int padding = -1; 4570 int paddingHorizontal = -1; 4571 int paddingVertical = -1; 4572 4573 int viewFlagValues = 0; 4574 int viewFlagMasks = 0; 4575 4576 boolean setScrollContainer = false; 4577 4578 int x = 0; 4579 int y = 0; 4580 4581 float tx = 0; 4582 float ty = 0; 4583 float tz = 0; 4584 float elevation = 0; 4585 float rotation = 0; 4586 float rotationX = 0; 4587 float rotationY = 0; 4588 float sx = 1f; 4589 float sy = 1f; 4590 boolean transformSet = false; 4591 4592 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4593 int overScrollMode = mOverScrollMode; 4594 boolean initializeScrollbars = false; 4595 boolean initializeScrollIndicators = false; 4596 4597 boolean startPaddingDefined = false; 4598 boolean endPaddingDefined = false; 4599 boolean leftPaddingDefined = false; 4600 boolean rightPaddingDefined = false; 4601 4602 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4603 4604 // Set default values. 4605 viewFlagValues |= FOCUSABLE_AUTO; 4606 viewFlagMasks |= FOCUSABLE_AUTO; 4607 4608 final int N = a.getIndexCount(); 4609 for (int i = 0; i < N; i++) { 4610 int attr = a.getIndex(i); 4611 switch (attr) { 4612 case com.android.internal.R.styleable.View_background: 4613 background = a.getDrawable(attr); 4614 break; 4615 case com.android.internal.R.styleable.View_padding: 4616 padding = a.getDimensionPixelSize(attr, -1); 4617 mUserPaddingLeftInitial = padding; 4618 mUserPaddingRightInitial = padding; 4619 leftPaddingDefined = true; 4620 rightPaddingDefined = true; 4621 break; 4622 case com.android.internal.R.styleable.View_paddingHorizontal: 4623 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4624 mUserPaddingLeftInitial = paddingHorizontal; 4625 mUserPaddingRightInitial = paddingHorizontal; 4626 leftPaddingDefined = true; 4627 rightPaddingDefined = true; 4628 break; 4629 case com.android.internal.R.styleable.View_paddingVertical: 4630 paddingVertical = a.getDimensionPixelSize(attr, -1); 4631 break; 4632 case com.android.internal.R.styleable.View_paddingLeft: 4633 leftPadding = a.getDimensionPixelSize(attr, -1); 4634 mUserPaddingLeftInitial = leftPadding; 4635 leftPaddingDefined = true; 4636 break; 4637 case com.android.internal.R.styleable.View_paddingTop: 4638 topPadding = a.getDimensionPixelSize(attr, -1); 4639 break; 4640 case com.android.internal.R.styleable.View_paddingRight: 4641 rightPadding = a.getDimensionPixelSize(attr, -1); 4642 mUserPaddingRightInitial = rightPadding; 4643 rightPaddingDefined = true; 4644 break; 4645 case com.android.internal.R.styleable.View_paddingBottom: 4646 bottomPadding = a.getDimensionPixelSize(attr, -1); 4647 break; 4648 case com.android.internal.R.styleable.View_paddingStart: 4649 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4650 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4651 break; 4652 case com.android.internal.R.styleable.View_paddingEnd: 4653 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4654 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4655 break; 4656 case com.android.internal.R.styleable.View_scrollX: 4657 x = a.getDimensionPixelOffset(attr, 0); 4658 break; 4659 case com.android.internal.R.styleable.View_scrollY: 4660 y = a.getDimensionPixelOffset(attr, 0); 4661 break; 4662 case com.android.internal.R.styleable.View_alpha: 4663 setAlpha(a.getFloat(attr, 1f)); 4664 break; 4665 case com.android.internal.R.styleable.View_transformPivotX: 4666 setPivotX(a.getDimension(attr, 0)); 4667 break; 4668 case com.android.internal.R.styleable.View_transformPivotY: 4669 setPivotY(a.getDimension(attr, 0)); 4670 break; 4671 case com.android.internal.R.styleable.View_translationX: 4672 tx = a.getDimension(attr, 0); 4673 transformSet = true; 4674 break; 4675 case com.android.internal.R.styleable.View_translationY: 4676 ty = a.getDimension(attr, 0); 4677 transformSet = true; 4678 break; 4679 case com.android.internal.R.styleable.View_translationZ: 4680 tz = a.getDimension(attr, 0); 4681 transformSet = true; 4682 break; 4683 case com.android.internal.R.styleable.View_elevation: 4684 elevation = a.getDimension(attr, 0); 4685 transformSet = true; 4686 break; 4687 case com.android.internal.R.styleable.View_rotation: 4688 rotation = a.getFloat(attr, 0); 4689 transformSet = true; 4690 break; 4691 case com.android.internal.R.styleable.View_rotationX: 4692 rotationX = a.getFloat(attr, 0); 4693 transformSet = true; 4694 break; 4695 case com.android.internal.R.styleable.View_rotationY: 4696 rotationY = a.getFloat(attr, 0); 4697 transformSet = true; 4698 break; 4699 case com.android.internal.R.styleable.View_scaleX: 4700 sx = a.getFloat(attr, 1f); 4701 transformSet = true; 4702 break; 4703 case com.android.internal.R.styleable.View_scaleY: 4704 sy = a.getFloat(attr, 1f); 4705 transformSet = true; 4706 break; 4707 case com.android.internal.R.styleable.View_id: 4708 mID = a.getResourceId(attr, NO_ID); 4709 break; 4710 case com.android.internal.R.styleable.View_tag: 4711 mTag = a.getText(attr); 4712 break; 4713 case com.android.internal.R.styleable.View_fitsSystemWindows: 4714 if (a.getBoolean(attr, false)) { 4715 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4716 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4717 } 4718 break; 4719 case com.android.internal.R.styleable.View_focusable: 4720 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 4721 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 4722 viewFlagMasks |= FOCUSABLE_MASK; 4723 } 4724 break; 4725 case com.android.internal.R.styleable.View_focusableInTouchMode: 4726 if (a.getBoolean(attr, false)) { 4727 // unset auto focus since focusableInTouchMode implies explicit focusable 4728 viewFlagValues &= ~FOCUSABLE_AUTO; 4729 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4730 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4731 } 4732 break; 4733 case com.android.internal.R.styleable.View_clickable: 4734 if (a.getBoolean(attr, false)) { 4735 viewFlagValues |= CLICKABLE; 4736 viewFlagMasks |= CLICKABLE; 4737 } 4738 break; 4739 case com.android.internal.R.styleable.View_longClickable: 4740 if (a.getBoolean(attr, false)) { 4741 viewFlagValues |= LONG_CLICKABLE; 4742 viewFlagMasks |= LONG_CLICKABLE; 4743 } 4744 break; 4745 case com.android.internal.R.styleable.View_contextClickable: 4746 if (a.getBoolean(attr, false)) { 4747 viewFlagValues |= CONTEXT_CLICKABLE; 4748 viewFlagMasks |= CONTEXT_CLICKABLE; 4749 } 4750 break; 4751 case com.android.internal.R.styleable.View_saveEnabled: 4752 if (!a.getBoolean(attr, true)) { 4753 viewFlagValues |= SAVE_DISABLED; 4754 viewFlagMasks |= SAVE_DISABLED_MASK; 4755 } 4756 break; 4757 case com.android.internal.R.styleable.View_duplicateParentState: 4758 if (a.getBoolean(attr, false)) { 4759 viewFlagValues |= DUPLICATE_PARENT_STATE; 4760 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4761 } 4762 break; 4763 case com.android.internal.R.styleable.View_visibility: 4764 final int visibility = a.getInt(attr, 0); 4765 if (visibility != 0) { 4766 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4767 viewFlagMasks |= VISIBILITY_MASK; 4768 } 4769 break; 4770 case com.android.internal.R.styleable.View_layoutDirection: 4771 // Clear any layout direction flags (included resolved bits) already set 4772 mPrivateFlags2 &= 4773 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4774 // Set the layout direction flags depending on the value of the attribute 4775 final int layoutDirection = a.getInt(attr, -1); 4776 final int value = (layoutDirection != -1) ? 4777 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4778 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4779 break; 4780 case com.android.internal.R.styleable.View_drawingCacheQuality: 4781 final int cacheQuality = a.getInt(attr, 0); 4782 if (cacheQuality != 0) { 4783 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4784 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4785 } 4786 break; 4787 case com.android.internal.R.styleable.View_contentDescription: 4788 setContentDescription(a.getString(attr)); 4789 break; 4790 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4791 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4792 break; 4793 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4794 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4795 break; 4796 case com.android.internal.R.styleable.View_labelFor: 4797 setLabelFor(a.getResourceId(attr, NO_ID)); 4798 break; 4799 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4800 if (!a.getBoolean(attr, true)) { 4801 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4802 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4803 } 4804 break; 4805 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4806 if (!a.getBoolean(attr, true)) { 4807 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4808 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4809 } 4810 break; 4811 case R.styleable.View_scrollbars: 4812 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4813 if (scrollbars != SCROLLBARS_NONE) { 4814 viewFlagValues |= scrollbars; 4815 viewFlagMasks |= SCROLLBARS_MASK; 4816 initializeScrollbars = true; 4817 } 4818 break; 4819 //noinspection deprecation 4820 case R.styleable.View_fadingEdge: 4821 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 4822 // Ignore the attribute starting with ICS 4823 break; 4824 } 4825 // With builds < ICS, fall through and apply fading edges 4826 case R.styleable.View_requiresFadingEdge: 4827 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4828 if (fadingEdge != FADING_EDGE_NONE) { 4829 viewFlagValues |= fadingEdge; 4830 viewFlagMasks |= FADING_EDGE_MASK; 4831 initializeFadingEdgeInternal(a); 4832 } 4833 break; 4834 case R.styleable.View_scrollbarStyle: 4835 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4836 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4837 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4838 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4839 } 4840 break; 4841 case R.styleable.View_isScrollContainer: 4842 setScrollContainer = true; 4843 if (a.getBoolean(attr, false)) { 4844 setScrollContainer(true); 4845 } 4846 break; 4847 case com.android.internal.R.styleable.View_keepScreenOn: 4848 if (a.getBoolean(attr, false)) { 4849 viewFlagValues |= KEEP_SCREEN_ON; 4850 viewFlagMasks |= KEEP_SCREEN_ON; 4851 } 4852 break; 4853 case R.styleable.View_filterTouchesWhenObscured: 4854 if (a.getBoolean(attr, false)) { 4855 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4856 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4857 } 4858 break; 4859 case R.styleable.View_nextFocusLeft: 4860 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4861 break; 4862 case R.styleable.View_nextFocusRight: 4863 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4864 break; 4865 case R.styleable.View_nextFocusUp: 4866 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4867 break; 4868 case R.styleable.View_nextFocusDown: 4869 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4870 break; 4871 case R.styleable.View_nextFocusForward: 4872 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4873 break; 4874 case R.styleable.View_nextClusterForward: 4875 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 4876 break; 4877 case R.styleable.View_minWidth: 4878 mMinWidth = a.getDimensionPixelSize(attr, 0); 4879 break; 4880 case R.styleable.View_minHeight: 4881 mMinHeight = a.getDimensionPixelSize(attr, 0); 4882 break; 4883 case R.styleable.View_onClick: 4884 if (context.isRestricted()) { 4885 throw new IllegalStateException("The android:onClick attribute cannot " 4886 + "be used within a restricted context"); 4887 } 4888 4889 final String handlerName = a.getString(attr); 4890 if (handlerName != null) { 4891 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 4892 } 4893 break; 4894 case R.styleable.View_overScrollMode: 4895 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 4896 break; 4897 case R.styleable.View_verticalScrollbarPosition: 4898 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 4899 break; 4900 case R.styleable.View_layerType: 4901 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 4902 break; 4903 case R.styleable.View_textDirection: 4904 // Clear any text direction flag already set 4905 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 4906 // Set the text direction flags depending on the value of the attribute 4907 final int textDirection = a.getInt(attr, -1); 4908 if (textDirection != -1) { 4909 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 4910 } 4911 break; 4912 case R.styleable.View_textAlignment: 4913 // Clear any text alignment flag already set 4914 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 4915 // Set the text alignment flag depending on the value of the attribute 4916 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 4917 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 4918 break; 4919 case R.styleable.View_importantForAccessibility: 4920 setImportantForAccessibility(a.getInt(attr, 4921 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 4922 break; 4923 case R.styleable.View_accessibilityLiveRegion: 4924 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 4925 break; 4926 case R.styleable.View_transitionName: 4927 setTransitionName(a.getString(attr)); 4928 break; 4929 case R.styleable.View_nestedScrollingEnabled: 4930 setNestedScrollingEnabled(a.getBoolean(attr, false)); 4931 break; 4932 case R.styleable.View_stateListAnimator: 4933 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 4934 a.getResourceId(attr, 0))); 4935 break; 4936 case R.styleable.View_backgroundTint: 4937 // This will get applied later during setBackground(). 4938 if (mBackgroundTint == null) { 4939 mBackgroundTint = new TintInfo(); 4940 } 4941 mBackgroundTint.mTintList = a.getColorStateList( 4942 R.styleable.View_backgroundTint); 4943 mBackgroundTint.mHasTintList = true; 4944 break; 4945 case R.styleable.View_backgroundTintMode: 4946 // This will get applied later during setBackground(). 4947 if (mBackgroundTint == null) { 4948 mBackgroundTint = new TintInfo(); 4949 } 4950 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 4951 R.styleable.View_backgroundTintMode, -1), null); 4952 mBackgroundTint.mHasTintMode = true; 4953 break; 4954 case R.styleable.View_outlineProvider: 4955 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 4956 PROVIDER_BACKGROUND)); 4957 break; 4958 case R.styleable.View_foreground: 4959 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4960 setForeground(a.getDrawable(attr)); 4961 } 4962 break; 4963 case R.styleable.View_foregroundGravity: 4964 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4965 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 4966 } 4967 break; 4968 case R.styleable.View_foregroundTintMode: 4969 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4970 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 4971 } 4972 break; 4973 case R.styleable.View_foregroundTint: 4974 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4975 setForegroundTintList(a.getColorStateList(attr)); 4976 } 4977 break; 4978 case R.styleable.View_foregroundInsidePadding: 4979 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4980 if (mForegroundInfo == null) { 4981 mForegroundInfo = new ForegroundInfo(); 4982 } 4983 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 4984 mForegroundInfo.mInsidePadding); 4985 } 4986 break; 4987 case R.styleable.View_scrollIndicators: 4988 final int scrollIndicators = 4989 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 4990 & SCROLL_INDICATORS_PFLAG3_MASK; 4991 if (scrollIndicators != 0) { 4992 mPrivateFlags3 |= scrollIndicators; 4993 initializeScrollIndicators = true; 4994 } 4995 break; 4996 case R.styleable.View_pointerIcon: 4997 final int resourceId = a.getResourceId(attr, 0); 4998 if (resourceId != 0) { 4999 setPointerIcon(PointerIcon.load( 5000 context.getResources(), resourceId)); 5001 } else { 5002 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5003 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5004 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5005 } 5006 } 5007 break; 5008 case R.styleable.View_forceHasOverlappingRendering: 5009 if (a.peekValue(attr) != null) { 5010 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5011 } 5012 break; 5013 case R.styleable.View_tooltipText: 5014 setTooltipText(a.getText(attr)); 5015 break; 5016 case R.styleable.View_keyboardNavigationCluster: 5017 if (a.peekValue(attr) != null) { 5018 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5019 } 5020 break; 5021 case R.styleable.View_focusedByDefault: 5022 if (a.peekValue(attr) != null) { 5023 setFocusedByDefault(a.getBoolean(attr, true)); 5024 } 5025 break; 5026 case R.styleable.View_autofillMode: 5027 if (a.peekValue(attr) != null) { 5028 setAutofillMode(a.getInt(attr, AUTOFILL_MODE_INHERIT)); 5029 } 5030 break; 5031 case R.styleable.View_autofillHint: 5032 if (a.peekValue(attr) != null) { 5033 CharSequence[] rawHints = null; 5034 String rawString = null; 5035 5036 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5037 int resId = a.getResourceId(attr, 0); 5038 5039 try { 5040 rawHints = a.getTextArray(attr); 5041 } catch (NullPointerException e) { 5042 rawString = getResources().getString(resId); 5043 } 5044 } else { 5045 rawString = a.getString(attr); 5046 } 5047 5048 if (rawHints == null) { 5049 if (rawString == null) { 5050 throw new IllegalArgumentException( 5051 "Could not resolve autofillHint"); 5052 } else { 5053 rawHints = rawString.split(","); 5054 } 5055 } 5056 5057 String[] hints = new String[rawHints.length]; 5058 5059 int numHints = rawHints.length; 5060 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5061 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5062 } 5063 setAutofillHint(hints); 5064 } 5065 break; 5066 case R.styleable.View_importantForAutofill: 5067 if (a.peekValue(attr) != null) { 5068 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5069 } 5070 break; 5071 } 5072 } 5073 5074 setOverScrollMode(overScrollMode); 5075 5076 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 5077 // the resolved layout direction). Those cached values will be used later during padding 5078 // resolution. 5079 mUserPaddingStart = startPadding; 5080 mUserPaddingEnd = endPadding; 5081 5082 if (background != null) { 5083 setBackground(background); 5084 } 5085 5086 // setBackground above will record that padding is currently provided by the background. 5087 // If we have padding specified via xml, record that here instead and use it. 5088 mLeftPaddingDefined = leftPaddingDefined; 5089 mRightPaddingDefined = rightPaddingDefined; 5090 5091 if (padding >= 0) { 5092 leftPadding = padding; 5093 topPadding = padding; 5094 rightPadding = padding; 5095 bottomPadding = padding; 5096 mUserPaddingLeftInitial = padding; 5097 mUserPaddingRightInitial = padding; 5098 } else { 5099 if (paddingHorizontal >= 0) { 5100 leftPadding = paddingHorizontal; 5101 rightPadding = paddingHorizontal; 5102 mUserPaddingLeftInitial = paddingHorizontal; 5103 mUserPaddingRightInitial = paddingHorizontal; 5104 } 5105 if (paddingVertical >= 0) { 5106 topPadding = paddingVertical; 5107 bottomPadding = paddingVertical; 5108 } 5109 } 5110 5111 if (isRtlCompatibilityMode()) { 5112 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 5113 // left / right padding are used if defined (meaning here nothing to do). If they are not 5114 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 5115 // start / end and resolve them as left / right (layout direction is not taken into account). 5116 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5117 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5118 // defined. 5119 if (!mLeftPaddingDefined && startPaddingDefined) { 5120 leftPadding = startPadding; 5121 } 5122 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 5123 if (!mRightPaddingDefined && endPaddingDefined) { 5124 rightPadding = endPadding; 5125 } 5126 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 5127 } else { 5128 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 5129 // values defined. Otherwise, left /right values are used. 5130 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5131 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5132 // defined. 5133 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 5134 5135 if (mLeftPaddingDefined && !hasRelativePadding) { 5136 mUserPaddingLeftInitial = leftPadding; 5137 } 5138 if (mRightPaddingDefined && !hasRelativePadding) { 5139 mUserPaddingRightInitial = rightPadding; 5140 } 5141 } 5142 5143 internalSetPadding( 5144 mUserPaddingLeftInitial, 5145 topPadding >= 0 ? topPadding : mPaddingTop, 5146 mUserPaddingRightInitial, 5147 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 5148 5149 if (viewFlagMasks != 0) { 5150 setFlags(viewFlagValues, viewFlagMasks); 5151 } 5152 5153 if (initializeScrollbars) { 5154 initializeScrollbarsInternal(a); 5155 } 5156 5157 if (initializeScrollIndicators) { 5158 initializeScrollIndicatorsInternal(); 5159 } 5160 5161 a.recycle(); 5162 5163 // Needs to be called after mViewFlags is set 5164 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5165 recomputePadding(); 5166 } 5167 5168 if (x != 0 || y != 0) { 5169 scrollTo(x, y); 5170 } 5171 5172 if (transformSet) { 5173 setTranslationX(tx); 5174 setTranslationY(ty); 5175 setTranslationZ(tz); 5176 setElevation(elevation); 5177 setRotation(rotation); 5178 setRotationX(rotationX); 5179 setRotationY(rotationY); 5180 setScaleX(sx); 5181 setScaleY(sy); 5182 } 5183 5184 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 5185 setScrollContainer(true); 5186 } 5187 5188 computeOpaqueFlags(); 5189 } 5190 5191 /** 5192 * An implementation of OnClickListener that attempts to lazily load a 5193 * named click handling method from a parent or ancestor context. 5194 */ 5195 private static class DeclaredOnClickListener implements OnClickListener { 5196 private final View mHostView; 5197 private final String mMethodName; 5198 5199 private Method mResolvedMethod; 5200 private Context mResolvedContext; 5201 5202 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 5203 mHostView = hostView; 5204 mMethodName = methodName; 5205 } 5206 5207 @Override 5208 public void onClick(@NonNull View v) { 5209 if (mResolvedMethod == null) { 5210 resolveMethod(mHostView.getContext(), mMethodName); 5211 } 5212 5213 try { 5214 mResolvedMethod.invoke(mResolvedContext, v); 5215 } catch (IllegalAccessException e) { 5216 throw new IllegalStateException( 5217 "Could not execute non-public method for android:onClick", e); 5218 } catch (InvocationTargetException e) { 5219 throw new IllegalStateException( 5220 "Could not execute method for android:onClick", e); 5221 } 5222 } 5223 5224 @NonNull 5225 private void resolveMethod(@Nullable Context context, @NonNull String name) { 5226 while (context != null) { 5227 try { 5228 if (!context.isRestricted()) { 5229 final Method method = context.getClass().getMethod(mMethodName, View.class); 5230 if (method != null) { 5231 mResolvedMethod = method; 5232 mResolvedContext = context; 5233 return; 5234 } 5235 } 5236 } catch (NoSuchMethodException e) { 5237 // Failed to find method, keep searching up the hierarchy. 5238 } 5239 5240 if (context instanceof ContextWrapper) { 5241 context = ((ContextWrapper) context).getBaseContext(); 5242 } else { 5243 // Can't search up the hierarchy, null out and fail. 5244 context = null; 5245 } 5246 } 5247 5248 final int id = mHostView.getId(); 5249 final String idText = id == NO_ID ? "" : " with id '" 5250 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 5251 throw new IllegalStateException("Could not find method " + mMethodName 5252 + "(View) in a parent or ancestor Context for android:onClick " 5253 + "attribute defined on view " + mHostView.getClass() + idText); 5254 } 5255 } 5256 5257 /** 5258 * Non-public constructor for use in testing 5259 */ 5260 View() { 5261 mResources = null; 5262 mRenderNode = RenderNode.create(getClass().getName(), this); 5263 } 5264 5265 final boolean debugDraw() { 5266 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 5267 } 5268 5269 private static SparseArray<String> getAttributeMap() { 5270 if (mAttributeMap == null) { 5271 mAttributeMap = new SparseArray<>(); 5272 } 5273 return mAttributeMap; 5274 } 5275 5276 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 5277 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 5278 final int indexCount = t.getIndexCount(); 5279 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 5280 5281 int i = 0; 5282 5283 // Store raw XML attributes. 5284 for (int j = 0; j < attrsCount; ++j) { 5285 attributes[i] = attrs.getAttributeName(j); 5286 attributes[i + 1] = attrs.getAttributeValue(j); 5287 i += 2; 5288 } 5289 5290 // Store resolved styleable attributes. 5291 final Resources res = t.getResources(); 5292 final SparseArray<String> attributeMap = getAttributeMap(); 5293 for (int j = 0; j < indexCount; ++j) { 5294 final int index = t.getIndex(j); 5295 if (!t.hasValueOrEmpty(index)) { 5296 // Value is undefined. Skip it. 5297 continue; 5298 } 5299 5300 final int resourceId = t.getResourceId(index, 0); 5301 if (resourceId == 0) { 5302 // Value is not a reference. Skip it. 5303 continue; 5304 } 5305 5306 String resourceName = attributeMap.get(resourceId); 5307 if (resourceName == null) { 5308 try { 5309 resourceName = res.getResourceName(resourceId); 5310 } catch (Resources.NotFoundException e) { 5311 resourceName = "0x" + Integer.toHexString(resourceId); 5312 } 5313 attributeMap.put(resourceId, resourceName); 5314 } 5315 5316 attributes[i] = resourceName; 5317 attributes[i + 1] = t.getString(index); 5318 i += 2; 5319 } 5320 5321 // Trim to fit contents. 5322 final String[] trimmed = new String[i]; 5323 System.arraycopy(attributes, 0, trimmed, 0, i); 5324 mAttributes = trimmed; 5325 } 5326 5327 public String toString() { 5328 StringBuilder out = new StringBuilder(128); 5329 out.append(getClass().getName()); 5330 out.append('{'); 5331 out.append(Integer.toHexString(System.identityHashCode(this))); 5332 out.append(' '); 5333 switch (mViewFlags&VISIBILITY_MASK) { 5334 case VISIBLE: out.append('V'); break; 5335 case INVISIBLE: out.append('I'); break; 5336 case GONE: out.append('G'); break; 5337 default: out.append('.'); break; 5338 } 5339 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 5340 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5341 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5342 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5343 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5344 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5345 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5346 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5347 out.append(' '); 5348 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5349 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5350 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5351 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5352 out.append('p'); 5353 } else { 5354 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5355 } 5356 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5357 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5358 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5359 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5360 out.append(' '); 5361 out.append(mLeft); 5362 out.append(','); 5363 out.append(mTop); 5364 out.append('-'); 5365 out.append(mRight); 5366 out.append(','); 5367 out.append(mBottom); 5368 final int id = getId(); 5369 if (id != NO_ID) { 5370 out.append(" #"); 5371 out.append(Integer.toHexString(id)); 5372 final Resources r = mResources; 5373 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5374 try { 5375 String pkgname; 5376 switch (id&0xff000000) { 5377 case 0x7f000000: 5378 pkgname="app"; 5379 break; 5380 case 0x01000000: 5381 pkgname="android"; 5382 break; 5383 default: 5384 pkgname = r.getResourcePackageName(id); 5385 break; 5386 } 5387 String typename = r.getResourceTypeName(id); 5388 String entryname = r.getResourceEntryName(id); 5389 out.append(" "); 5390 out.append(pkgname); 5391 out.append(":"); 5392 out.append(typename); 5393 out.append("/"); 5394 out.append(entryname); 5395 } catch (Resources.NotFoundException e) { 5396 } 5397 } 5398 } 5399 out.append("}"); 5400 return out.toString(); 5401 } 5402 5403 /** 5404 * <p> 5405 * Initializes the fading edges from a given set of styled attributes. This 5406 * method should be called by subclasses that need fading edges and when an 5407 * instance of these subclasses is created programmatically rather than 5408 * being inflated from XML. This method is automatically called when the XML 5409 * is inflated. 5410 * </p> 5411 * 5412 * @param a the styled attributes set to initialize the fading edges from 5413 * 5414 * @removed 5415 */ 5416 protected void initializeFadingEdge(TypedArray a) { 5417 // This method probably shouldn't have been included in the SDK to begin with. 5418 // It relies on 'a' having been initialized using an attribute filter array that is 5419 // not publicly available to the SDK. The old method has been renamed 5420 // to initializeFadingEdgeInternal and hidden for framework use only; 5421 // this one initializes using defaults to make it safe to call for apps. 5422 5423 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5424 5425 initializeFadingEdgeInternal(arr); 5426 5427 arr.recycle(); 5428 } 5429 5430 /** 5431 * <p> 5432 * Initializes the fading edges from a given set of styled attributes. This 5433 * method should be called by subclasses that need fading edges and when an 5434 * instance of these subclasses is created programmatically rather than 5435 * being inflated from XML. This method is automatically called when the XML 5436 * is inflated. 5437 * </p> 5438 * 5439 * @param a the styled attributes set to initialize the fading edges from 5440 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5441 */ 5442 protected void initializeFadingEdgeInternal(TypedArray a) { 5443 initScrollCache(); 5444 5445 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5446 R.styleable.View_fadingEdgeLength, 5447 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5448 } 5449 5450 /** 5451 * Returns the size of the vertical faded edges used to indicate that more 5452 * content in this view is visible. 5453 * 5454 * @return The size in pixels of the vertical faded edge or 0 if vertical 5455 * faded edges are not enabled for this view. 5456 * @attr ref android.R.styleable#View_fadingEdgeLength 5457 */ 5458 public int getVerticalFadingEdgeLength() { 5459 if (isVerticalFadingEdgeEnabled()) { 5460 ScrollabilityCache cache = mScrollCache; 5461 if (cache != null) { 5462 return cache.fadingEdgeLength; 5463 } 5464 } 5465 return 0; 5466 } 5467 5468 /** 5469 * Set the size of the faded edge used to indicate that more content in this 5470 * view is available. Will not change whether the fading edge is enabled; use 5471 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5472 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5473 * for the vertical or horizontal fading edges. 5474 * 5475 * @param length The size in pixels of the faded edge used to indicate that more 5476 * content in this view is visible. 5477 */ 5478 public void setFadingEdgeLength(int length) { 5479 initScrollCache(); 5480 mScrollCache.fadingEdgeLength = length; 5481 } 5482 5483 /** 5484 * Returns the size of the horizontal faded edges used to indicate that more 5485 * content in this view is visible. 5486 * 5487 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5488 * faded edges are not enabled for this view. 5489 * @attr ref android.R.styleable#View_fadingEdgeLength 5490 */ 5491 public int getHorizontalFadingEdgeLength() { 5492 if (isHorizontalFadingEdgeEnabled()) { 5493 ScrollabilityCache cache = mScrollCache; 5494 if (cache != null) { 5495 return cache.fadingEdgeLength; 5496 } 5497 } 5498 return 0; 5499 } 5500 5501 /** 5502 * Returns the width of the vertical scrollbar. 5503 * 5504 * @return The width in pixels of the vertical scrollbar or 0 if there 5505 * is no vertical scrollbar. 5506 */ 5507 public int getVerticalScrollbarWidth() { 5508 ScrollabilityCache cache = mScrollCache; 5509 if (cache != null) { 5510 ScrollBarDrawable scrollBar = cache.scrollBar; 5511 if (scrollBar != null) { 5512 int size = scrollBar.getSize(true); 5513 if (size <= 0) { 5514 size = cache.scrollBarSize; 5515 } 5516 return size; 5517 } 5518 return 0; 5519 } 5520 return 0; 5521 } 5522 5523 /** 5524 * Returns the height of the horizontal scrollbar. 5525 * 5526 * @return The height in pixels of the horizontal scrollbar or 0 if 5527 * there is no horizontal scrollbar. 5528 */ 5529 protected int getHorizontalScrollbarHeight() { 5530 ScrollabilityCache cache = mScrollCache; 5531 if (cache != null) { 5532 ScrollBarDrawable scrollBar = cache.scrollBar; 5533 if (scrollBar != null) { 5534 int size = scrollBar.getSize(false); 5535 if (size <= 0) { 5536 size = cache.scrollBarSize; 5537 } 5538 return size; 5539 } 5540 return 0; 5541 } 5542 return 0; 5543 } 5544 5545 /** 5546 * <p> 5547 * Initializes the scrollbars from a given set of styled attributes. This 5548 * method should be called by subclasses that need scrollbars and when an 5549 * instance of these subclasses is created programmatically rather than 5550 * being inflated from XML. This method is automatically called when the XML 5551 * is inflated. 5552 * </p> 5553 * 5554 * @param a the styled attributes set to initialize the scrollbars from 5555 * 5556 * @removed 5557 */ 5558 protected void initializeScrollbars(TypedArray a) { 5559 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5560 // using the View filter array which is not available to the SDK. As such, internal 5561 // framework usage now uses initializeScrollbarsInternal and we grab a default 5562 // TypedArray with the right filter instead here. 5563 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5564 5565 initializeScrollbarsInternal(arr); 5566 5567 // We ignored the method parameter. Recycle the one we actually did use. 5568 arr.recycle(); 5569 } 5570 5571 /** 5572 * <p> 5573 * Initializes the scrollbars from a given set of styled attributes. This 5574 * method should be called by subclasses that need scrollbars and when an 5575 * instance of these subclasses is created programmatically rather than 5576 * being inflated from XML. This method is automatically called when the XML 5577 * is inflated. 5578 * </p> 5579 * 5580 * @param a the styled attributes set to initialize the scrollbars from 5581 * @hide 5582 */ 5583 protected void initializeScrollbarsInternal(TypedArray a) { 5584 initScrollCache(); 5585 5586 final ScrollabilityCache scrollabilityCache = mScrollCache; 5587 5588 if (scrollabilityCache.scrollBar == null) { 5589 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5590 scrollabilityCache.scrollBar.setState(getDrawableState()); 5591 scrollabilityCache.scrollBar.setCallback(this); 5592 } 5593 5594 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5595 5596 if (!fadeScrollbars) { 5597 scrollabilityCache.state = ScrollabilityCache.ON; 5598 } 5599 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5600 5601 5602 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5603 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5604 .getScrollBarFadeDuration()); 5605 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5606 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5607 ViewConfiguration.getScrollDefaultDelay()); 5608 5609 5610 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5611 com.android.internal.R.styleable.View_scrollbarSize, 5612 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5613 5614 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5615 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5616 5617 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5618 if (thumb != null) { 5619 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5620 } 5621 5622 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5623 false); 5624 if (alwaysDraw) { 5625 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5626 } 5627 5628 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5629 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5630 5631 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5632 if (thumb != null) { 5633 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5634 } 5635 5636 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5637 false); 5638 if (alwaysDraw) { 5639 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5640 } 5641 5642 // Apply layout direction to the new Drawables if needed 5643 final int layoutDirection = getLayoutDirection(); 5644 if (track != null) { 5645 track.setLayoutDirection(layoutDirection); 5646 } 5647 if (thumb != null) { 5648 thumb.setLayoutDirection(layoutDirection); 5649 } 5650 5651 // Re-apply user/background padding so that scrollbar(s) get added 5652 resolvePadding(); 5653 } 5654 5655 private void initializeScrollIndicatorsInternal() { 5656 // Some day maybe we'll break this into top/left/start/etc. and let the 5657 // client control it. Until then, you can have any scroll indicator you 5658 // want as long as it's a 1dp foreground-colored rectangle. 5659 if (mScrollIndicatorDrawable == null) { 5660 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5661 } 5662 } 5663 5664 /** 5665 * <p> 5666 * Initalizes the scrollability cache if necessary. 5667 * </p> 5668 */ 5669 private void initScrollCache() { 5670 if (mScrollCache == null) { 5671 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5672 } 5673 } 5674 5675 private ScrollabilityCache getScrollCache() { 5676 initScrollCache(); 5677 return mScrollCache; 5678 } 5679 5680 /** 5681 * Set the position of the vertical scroll bar. Should be one of 5682 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5683 * {@link #SCROLLBAR_POSITION_RIGHT}. 5684 * 5685 * @param position Where the vertical scroll bar should be positioned. 5686 */ 5687 public void setVerticalScrollbarPosition(int position) { 5688 if (mVerticalScrollbarPosition != position) { 5689 mVerticalScrollbarPosition = position; 5690 computeOpaqueFlags(); 5691 resolvePadding(); 5692 } 5693 } 5694 5695 /** 5696 * @return The position where the vertical scroll bar will show, if applicable. 5697 * @see #setVerticalScrollbarPosition(int) 5698 */ 5699 public int getVerticalScrollbarPosition() { 5700 return mVerticalScrollbarPosition; 5701 } 5702 5703 boolean isOnScrollbar(float x, float y) { 5704 if (mScrollCache == null) { 5705 return false; 5706 } 5707 x += getScrollX(); 5708 y += getScrollY(); 5709 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5710 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5711 getVerticalScrollBarBounds(null, touchBounds); 5712 if (touchBounds.contains((int) x, (int) y)) { 5713 return true; 5714 } 5715 } 5716 if (isHorizontalScrollBarEnabled()) { 5717 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5718 getHorizontalScrollBarBounds(null, touchBounds); 5719 if (touchBounds.contains((int) x, (int) y)) { 5720 return true; 5721 } 5722 } 5723 return false; 5724 } 5725 5726 boolean isOnScrollbarThumb(float x, float y) { 5727 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5728 } 5729 5730 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5731 if (mScrollCache == null) { 5732 return false; 5733 } 5734 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5735 x += getScrollX(); 5736 y += getScrollY(); 5737 final Rect bounds = mScrollCache.mScrollBarBounds; 5738 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5739 getVerticalScrollBarBounds(bounds, touchBounds); 5740 final int range = computeVerticalScrollRange(); 5741 final int offset = computeVerticalScrollOffset(); 5742 final int extent = computeVerticalScrollExtent(); 5743 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5744 extent, range); 5745 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5746 extent, range, offset); 5747 final int thumbTop = bounds.top + thumbOffset; 5748 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5749 if (x >= touchBounds.left && x <= touchBounds.right 5750 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 5751 return true; 5752 } 5753 } 5754 return false; 5755 } 5756 5757 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5758 if (mScrollCache == null) { 5759 return false; 5760 } 5761 if (isHorizontalScrollBarEnabled()) { 5762 x += getScrollX(); 5763 y += getScrollY(); 5764 final Rect bounds = mScrollCache.mScrollBarBounds; 5765 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5766 getHorizontalScrollBarBounds(bounds, touchBounds); 5767 final int range = computeHorizontalScrollRange(); 5768 final int offset = computeHorizontalScrollOffset(); 5769 final int extent = computeHorizontalScrollExtent(); 5770 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5771 extent, range); 5772 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5773 extent, range, offset); 5774 final int thumbLeft = bounds.left + thumbOffset; 5775 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5776 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 5777 && y >= touchBounds.top && y <= touchBounds.bottom) { 5778 return true; 5779 } 5780 } 5781 return false; 5782 } 5783 5784 boolean isDraggingScrollBar() { 5785 return mScrollCache != null 5786 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5787 } 5788 5789 /** 5790 * Sets the state of all scroll indicators. 5791 * <p> 5792 * See {@link #setScrollIndicators(int, int)} for usage information. 5793 * 5794 * @param indicators a bitmask of indicators that should be enabled, or 5795 * {@code 0} to disable all indicators 5796 * @see #setScrollIndicators(int, int) 5797 * @see #getScrollIndicators() 5798 * @attr ref android.R.styleable#View_scrollIndicators 5799 */ 5800 public void setScrollIndicators(@ScrollIndicators int indicators) { 5801 setScrollIndicators(indicators, 5802 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5803 } 5804 5805 /** 5806 * Sets the state of the scroll indicators specified by the mask. To change 5807 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5808 * <p> 5809 * When a scroll indicator is enabled, it will be displayed if the view 5810 * can scroll in the direction of the indicator. 5811 * <p> 5812 * Multiple indicator types may be enabled or disabled by passing the 5813 * logical OR of the desired types. If multiple types are specified, they 5814 * will all be set to the same enabled state. 5815 * <p> 5816 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5817 * 5818 * @param indicators the indicator direction, or the logical OR of multiple 5819 * indicator directions. One or more of: 5820 * <ul> 5821 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5822 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5823 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5824 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5825 * <li>{@link #SCROLL_INDICATOR_START}</li> 5826 * <li>{@link #SCROLL_INDICATOR_END}</li> 5827 * </ul> 5828 * @see #setScrollIndicators(int) 5829 * @see #getScrollIndicators() 5830 * @attr ref android.R.styleable#View_scrollIndicators 5831 */ 5832 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5833 // Shift and sanitize mask. 5834 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5835 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5836 5837 // Shift and mask indicators. 5838 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5839 indicators &= mask; 5840 5841 // Merge with non-masked flags. 5842 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5843 5844 if (mPrivateFlags3 != updatedFlags) { 5845 mPrivateFlags3 = updatedFlags; 5846 5847 if (indicators != 0) { 5848 initializeScrollIndicatorsInternal(); 5849 } 5850 invalidate(); 5851 } 5852 } 5853 5854 /** 5855 * Returns a bitmask representing the enabled scroll indicators. 5856 * <p> 5857 * For example, if the top and left scroll indicators are enabled and all 5858 * other indicators are disabled, the return value will be 5859 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5860 * <p> 5861 * To check whether the bottom scroll indicator is enabled, use the value 5862 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5863 * 5864 * @return a bitmask representing the enabled scroll indicators 5865 */ 5866 @ScrollIndicators 5867 public int getScrollIndicators() { 5868 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5869 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5870 } 5871 5872 ListenerInfo getListenerInfo() { 5873 if (mListenerInfo != null) { 5874 return mListenerInfo; 5875 } 5876 mListenerInfo = new ListenerInfo(); 5877 return mListenerInfo; 5878 } 5879 5880 /** 5881 * Register a callback to be invoked when the scroll X or Y positions of 5882 * this view change. 5883 * <p> 5884 * <b>Note:</b> Some views handle scrolling independently from View and may 5885 * have their own separate listeners for scroll-type events. For example, 5886 * {@link android.widget.ListView ListView} allows clients to register an 5887 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 5888 * to listen for changes in list scroll position. 5889 * 5890 * @param l The listener to notify when the scroll X or Y position changes. 5891 * @see android.view.View#getScrollX() 5892 * @see android.view.View#getScrollY() 5893 */ 5894 public void setOnScrollChangeListener(OnScrollChangeListener l) { 5895 getListenerInfo().mOnScrollChangeListener = l; 5896 } 5897 5898 /** 5899 * Register a callback to be invoked when focus of this view changed. 5900 * 5901 * @param l The callback that will run. 5902 */ 5903 public void setOnFocusChangeListener(OnFocusChangeListener l) { 5904 getListenerInfo().mOnFocusChangeListener = l; 5905 } 5906 5907 /** 5908 * Add a listener that will be called when the bounds of the view change due to 5909 * layout processing. 5910 * 5911 * @param listener The listener that will be called when layout bounds change. 5912 */ 5913 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 5914 ListenerInfo li = getListenerInfo(); 5915 if (li.mOnLayoutChangeListeners == null) { 5916 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 5917 } 5918 if (!li.mOnLayoutChangeListeners.contains(listener)) { 5919 li.mOnLayoutChangeListeners.add(listener); 5920 } 5921 } 5922 5923 /** 5924 * Remove a listener for layout changes. 5925 * 5926 * @param listener The listener for layout bounds change. 5927 */ 5928 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 5929 ListenerInfo li = mListenerInfo; 5930 if (li == null || li.mOnLayoutChangeListeners == null) { 5931 return; 5932 } 5933 li.mOnLayoutChangeListeners.remove(listener); 5934 } 5935 5936 /** 5937 * Add a listener for attach state changes. 5938 * 5939 * This listener will be called whenever this view is attached or detached 5940 * from a window. Remove the listener using 5941 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 5942 * 5943 * @param listener Listener to attach 5944 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 5945 */ 5946 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5947 ListenerInfo li = getListenerInfo(); 5948 if (li.mOnAttachStateChangeListeners == null) { 5949 li.mOnAttachStateChangeListeners 5950 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 5951 } 5952 li.mOnAttachStateChangeListeners.add(listener); 5953 } 5954 5955 /** 5956 * Remove a listener for attach state changes. The listener will receive no further 5957 * notification of window attach/detach events. 5958 * 5959 * @param listener Listener to remove 5960 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 5961 */ 5962 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5963 ListenerInfo li = mListenerInfo; 5964 if (li == null || li.mOnAttachStateChangeListeners == null) { 5965 return; 5966 } 5967 li.mOnAttachStateChangeListeners.remove(listener); 5968 } 5969 5970 /** 5971 * Returns the focus-change callback registered for this view. 5972 * 5973 * @return The callback, or null if one is not registered. 5974 */ 5975 public OnFocusChangeListener getOnFocusChangeListener() { 5976 ListenerInfo li = mListenerInfo; 5977 return li != null ? li.mOnFocusChangeListener : null; 5978 } 5979 5980 /** 5981 * Register a callback to be invoked when this view is clicked. If this view is not 5982 * clickable, it becomes clickable. 5983 * 5984 * @param l The callback that will run 5985 * 5986 * @see #setClickable(boolean) 5987 */ 5988 public void setOnClickListener(@Nullable OnClickListener l) { 5989 if (!isClickable()) { 5990 setClickable(true); 5991 } 5992 getListenerInfo().mOnClickListener = l; 5993 } 5994 5995 /** 5996 * Return whether this view has an attached OnClickListener. Returns 5997 * true if there is a listener, false if there is none. 5998 */ 5999 public boolean hasOnClickListeners() { 6000 ListenerInfo li = mListenerInfo; 6001 return (li != null && li.mOnClickListener != null); 6002 } 6003 6004 /** 6005 * Register a callback to be invoked when this view is clicked and held. If this view is not 6006 * long clickable, it becomes long clickable. 6007 * 6008 * @param l The callback that will run 6009 * 6010 * @see #setLongClickable(boolean) 6011 */ 6012 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 6013 if (!isLongClickable()) { 6014 setLongClickable(true); 6015 } 6016 getListenerInfo().mOnLongClickListener = l; 6017 } 6018 6019 /** 6020 * Register a callback to be invoked when this view is context clicked. If the view is not 6021 * context clickable, it becomes context clickable. 6022 * 6023 * @param l The callback that will run 6024 * @see #setContextClickable(boolean) 6025 */ 6026 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 6027 if (!isContextClickable()) { 6028 setContextClickable(true); 6029 } 6030 getListenerInfo().mOnContextClickListener = l; 6031 } 6032 6033 /** 6034 * Register a callback to be invoked when the context menu for this view is 6035 * being built. If this view is not long clickable, it becomes long clickable. 6036 * 6037 * @param l The callback that will run 6038 * 6039 */ 6040 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 6041 if (!isLongClickable()) { 6042 setLongClickable(true); 6043 } 6044 getListenerInfo().mOnCreateContextMenuListener = l; 6045 } 6046 6047 /** 6048 * Set an observer to collect stats for each frame rendered for this view. 6049 * 6050 * @hide 6051 */ 6052 public void addFrameMetricsListener(Window window, 6053 Window.OnFrameMetricsAvailableListener listener, 6054 Handler handler) { 6055 if (mAttachInfo != null) { 6056 if (mAttachInfo.mThreadedRenderer != null) { 6057 if (mFrameMetricsObservers == null) { 6058 mFrameMetricsObservers = new ArrayList<>(); 6059 } 6060 6061 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6062 handler.getLooper(), listener); 6063 mFrameMetricsObservers.add(fmo); 6064 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 6065 } else { 6066 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6067 } 6068 } else { 6069 if (mFrameMetricsObservers == null) { 6070 mFrameMetricsObservers = new ArrayList<>(); 6071 } 6072 6073 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6074 handler.getLooper(), listener); 6075 mFrameMetricsObservers.add(fmo); 6076 } 6077 } 6078 6079 /** 6080 * Remove observer configured to collect frame stats for this view. 6081 * 6082 * @hide 6083 */ 6084 public void removeFrameMetricsListener( 6085 Window.OnFrameMetricsAvailableListener listener) { 6086 ThreadedRenderer renderer = getThreadedRenderer(); 6087 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 6088 if (fmo == null) { 6089 throw new IllegalArgumentException( 6090 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 6091 } 6092 6093 if (mFrameMetricsObservers != null) { 6094 mFrameMetricsObservers.remove(fmo); 6095 if (renderer != null) { 6096 renderer.removeFrameMetricsObserver(fmo); 6097 } 6098 } 6099 } 6100 6101 private void registerPendingFrameMetricsObservers() { 6102 if (mFrameMetricsObservers != null) { 6103 ThreadedRenderer renderer = getThreadedRenderer(); 6104 if (renderer != null) { 6105 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 6106 renderer.addFrameMetricsObserver(fmo); 6107 } 6108 } else { 6109 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6110 } 6111 } 6112 } 6113 6114 private FrameMetricsObserver findFrameMetricsObserver( 6115 Window.OnFrameMetricsAvailableListener listener) { 6116 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 6117 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 6118 if (observer.mListener == listener) { 6119 return observer; 6120 } 6121 } 6122 6123 return null; 6124 } 6125 6126 /** 6127 * Call this view's OnClickListener, if it is defined. Performs all normal 6128 * actions associated with clicking: reporting accessibility event, playing 6129 * a sound, etc. 6130 * 6131 * @return True there was an assigned OnClickListener that was called, false 6132 * otherwise is returned. 6133 */ 6134 public boolean performClick() { 6135 final boolean result; 6136 final ListenerInfo li = mListenerInfo; 6137 if (li != null && li.mOnClickListener != null) { 6138 playSoundEffect(SoundEffectConstants.CLICK); 6139 li.mOnClickListener.onClick(this); 6140 result = true; 6141 } else { 6142 result = false; 6143 } 6144 6145 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 6146 6147 notifyEnterOrExitForAutoFillIfNeeded(true); 6148 6149 return result; 6150 } 6151 6152 /** 6153 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 6154 * this only calls the listener, and does not do any associated clicking 6155 * actions like reporting an accessibility event. 6156 * 6157 * @return True there was an assigned OnClickListener that was called, false 6158 * otherwise is returned. 6159 */ 6160 public boolean callOnClick() { 6161 ListenerInfo li = mListenerInfo; 6162 if (li != null && li.mOnClickListener != null) { 6163 li.mOnClickListener.onClick(this); 6164 return true; 6165 } 6166 return false; 6167 } 6168 6169 /** 6170 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6171 * context menu if the OnLongClickListener did not consume the event. 6172 * 6173 * @return {@code true} if one of the above receivers consumed the event, 6174 * {@code false} otherwise 6175 */ 6176 public boolean performLongClick() { 6177 return performLongClickInternal(mLongClickX, mLongClickY); 6178 } 6179 6180 /** 6181 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6182 * context menu if the OnLongClickListener did not consume the event, 6183 * anchoring it to an (x,y) coordinate. 6184 * 6185 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6186 * to disable anchoring 6187 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6188 * to disable anchoring 6189 * @return {@code true} if one of the above receivers consumed the event, 6190 * {@code false} otherwise 6191 */ 6192 public boolean performLongClick(float x, float y) { 6193 mLongClickX = x; 6194 mLongClickY = y; 6195 final boolean handled = performLongClick(); 6196 mLongClickX = Float.NaN; 6197 mLongClickY = Float.NaN; 6198 return handled; 6199 } 6200 6201 /** 6202 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6203 * context menu if the OnLongClickListener did not consume the event, 6204 * optionally anchoring it to an (x,y) coordinate. 6205 * 6206 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6207 * to disable anchoring 6208 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6209 * to disable anchoring 6210 * @return {@code true} if one of the above receivers consumed the event, 6211 * {@code false} otherwise 6212 */ 6213 private boolean performLongClickInternal(float x, float y) { 6214 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 6215 6216 boolean handled = false; 6217 final ListenerInfo li = mListenerInfo; 6218 if (li != null && li.mOnLongClickListener != null) { 6219 handled = li.mOnLongClickListener.onLongClick(View.this); 6220 } 6221 if (!handled) { 6222 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 6223 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 6224 } 6225 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 6226 if (!handled) { 6227 handled = showLongClickTooltip((int) x, (int) y); 6228 } 6229 } 6230 if (handled) { 6231 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 6232 } 6233 return handled; 6234 } 6235 6236 /** 6237 * Call this view's OnContextClickListener, if it is defined. 6238 * 6239 * @param x the x coordinate of the context click 6240 * @param y the y coordinate of the context click 6241 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6242 * otherwise. 6243 */ 6244 public boolean performContextClick(float x, float y) { 6245 return performContextClick(); 6246 } 6247 6248 /** 6249 * Call this view's OnContextClickListener, if it is defined. 6250 * 6251 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6252 * otherwise. 6253 */ 6254 public boolean performContextClick() { 6255 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 6256 6257 boolean handled = false; 6258 ListenerInfo li = mListenerInfo; 6259 if (li != null && li.mOnContextClickListener != null) { 6260 handled = li.mOnContextClickListener.onContextClick(View.this); 6261 } 6262 if (handled) { 6263 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 6264 } 6265 return handled; 6266 } 6267 6268 /** 6269 * Performs button-related actions during a touch down event. 6270 * 6271 * @param event The event. 6272 * @return True if the down was consumed. 6273 * 6274 * @hide 6275 */ 6276 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 6277 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 6278 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 6279 showContextMenu(event.getX(), event.getY()); 6280 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 6281 return true; 6282 } 6283 return false; 6284 } 6285 6286 /** 6287 * Shows the context menu for this view. 6288 * 6289 * @return {@code true} if the context menu was shown, {@code false} 6290 * otherwise 6291 * @see #showContextMenu(float, float) 6292 */ 6293 public boolean showContextMenu() { 6294 return getParent().showContextMenuForChild(this); 6295 } 6296 6297 /** 6298 * Shows the context menu for this view anchored to the specified 6299 * view-relative coordinate. 6300 * 6301 * @param x the X coordinate in pixels relative to the view to which the 6302 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6303 * @param y the Y coordinate in pixels relative to the view to which the 6304 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6305 * @return {@code true} if the context menu was shown, {@code false} 6306 * otherwise 6307 */ 6308 public boolean showContextMenu(float x, float y) { 6309 return getParent().showContextMenuForChild(this, x, y); 6310 } 6311 6312 /** 6313 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 6314 * 6315 * @param callback Callback that will control the lifecycle of the action mode 6316 * @return The new action mode if it is started, null otherwise 6317 * 6318 * @see ActionMode 6319 * @see #startActionMode(android.view.ActionMode.Callback, int) 6320 */ 6321 public ActionMode startActionMode(ActionMode.Callback callback) { 6322 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 6323 } 6324 6325 /** 6326 * Start an action mode with the given type. 6327 * 6328 * @param callback Callback that will control the lifecycle of the action mode 6329 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 6330 * @return The new action mode if it is started, null otherwise 6331 * 6332 * @see ActionMode 6333 */ 6334 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6335 ViewParent parent = getParent(); 6336 if (parent == null) return null; 6337 try { 6338 return parent.startActionModeForChild(this, callback, type); 6339 } catch (AbstractMethodError ame) { 6340 // Older implementations of custom views might not implement this. 6341 return parent.startActionModeForChild(this, callback); 6342 } 6343 } 6344 6345 /** 6346 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6347 * Context, creating a unique View identifier to retrieve the result. 6348 * 6349 * @param intent The Intent to be started. 6350 * @param requestCode The request code to use. 6351 * @hide 6352 */ 6353 public void startActivityForResult(Intent intent, int requestCode) { 6354 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6355 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6356 } 6357 6358 /** 6359 * If this View corresponds to the calling who, dispatches the activity result. 6360 * @param who The identifier for the targeted View to receive the result. 6361 * @param requestCode The integer request code originally supplied to 6362 * startActivityForResult(), allowing you to identify who this 6363 * result came from. 6364 * @param resultCode The integer result code returned by the child activity 6365 * through its setResult(). 6366 * @param data An Intent, which can return result data to the caller 6367 * (various data can be attached to Intent "extras"). 6368 * @return {@code true} if the activity result was dispatched. 6369 * @hide 6370 */ 6371 public boolean dispatchActivityResult( 6372 String who, int requestCode, int resultCode, Intent data) { 6373 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6374 onActivityResult(requestCode, resultCode, data); 6375 mStartActivityRequestWho = null; 6376 return true; 6377 } 6378 return false; 6379 } 6380 6381 /** 6382 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6383 * 6384 * @param requestCode The integer request code originally supplied to 6385 * startActivityForResult(), allowing you to identify who this 6386 * result came from. 6387 * @param resultCode The integer result code returned by the child activity 6388 * through its setResult(). 6389 * @param data An Intent, which can return result data to the caller 6390 * (various data can be attached to Intent "extras"). 6391 * @hide 6392 */ 6393 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6394 // Do nothing. 6395 } 6396 6397 /** 6398 * Register a callback to be invoked when a hardware key is pressed in this view. 6399 * Key presses in software input methods will generally not trigger the methods of 6400 * this listener. 6401 * @param l the key listener to attach to this view 6402 */ 6403 public void setOnKeyListener(OnKeyListener l) { 6404 getListenerInfo().mOnKeyListener = l; 6405 } 6406 6407 /** 6408 * Register a callback to be invoked when a touch event is sent to this view. 6409 * @param l the touch listener to attach to this view 6410 */ 6411 public void setOnTouchListener(OnTouchListener l) { 6412 getListenerInfo().mOnTouchListener = l; 6413 } 6414 6415 /** 6416 * Register a callback to be invoked when a generic motion event is sent to this view. 6417 * @param l the generic motion listener to attach to this view 6418 */ 6419 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6420 getListenerInfo().mOnGenericMotionListener = l; 6421 } 6422 6423 /** 6424 * Register a callback to be invoked when a hover event is sent to this view. 6425 * @param l the hover listener to attach to this view 6426 */ 6427 public void setOnHoverListener(OnHoverListener l) { 6428 getListenerInfo().mOnHoverListener = l; 6429 } 6430 6431 /** 6432 * Register a drag event listener callback object for this View. The parameter is 6433 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6434 * View, the system calls the 6435 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6436 * @param l An implementation of {@link android.view.View.OnDragListener}. 6437 */ 6438 public void setOnDragListener(OnDragListener l) { 6439 getListenerInfo().mOnDragListener = l; 6440 } 6441 6442 /** 6443 * Give this view focus. This will cause 6444 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6445 * 6446 * Note: this does not check whether this {@link View} should get focus, it just 6447 * gives it focus no matter what. It should only be called internally by framework 6448 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6449 * 6450 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6451 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6452 * focus moved when requestFocus() is called. It may not always 6453 * apply, in which case use the default View.FOCUS_DOWN. 6454 * @param previouslyFocusedRect The rectangle of the view that had focus 6455 * prior in this View's coordinate system. 6456 */ 6457 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6458 if (DBG) { 6459 System.out.println(this + " requestFocus()"); 6460 } 6461 6462 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6463 mPrivateFlags |= PFLAG_FOCUSED; 6464 6465 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6466 6467 if (mParent != null) { 6468 mParent.requestChildFocus(this, this); 6469 setFocusedInCluster(); 6470 } 6471 6472 if (mAttachInfo != null) { 6473 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6474 } 6475 6476 onFocusChanged(true, direction, previouslyFocusedRect); 6477 refreshDrawableState(); 6478 } 6479 } 6480 6481 /** 6482 * Sets this view's preference for reveal behavior when it gains focus. 6483 * 6484 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6485 * this view would prefer to be brought fully into view when it gains focus. 6486 * For example, a text field that a user is meant to type into. Other views such 6487 * as scrolling containers may prefer to opt-out of this behavior.</p> 6488 * 6489 * <p>The default value for views is true, though subclasses may change this 6490 * based on their preferred behavior.</p> 6491 * 6492 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6493 * 6494 * @see #getRevealOnFocusHint() 6495 */ 6496 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6497 if (revealOnFocus) { 6498 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6499 } else { 6500 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6501 } 6502 } 6503 6504 /** 6505 * Returns this view's preference for reveal behavior when it gains focus. 6506 * 6507 * <p>When this method returns true for a child view requesting focus, ancestor 6508 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6509 * should make a best effort to make the newly focused child fully visible to the user. 6510 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6511 * other properties affecting visibility to the user as part of the focus change.</p> 6512 * 6513 * @return true if this view would prefer to become fully visible when it gains focus, 6514 * false if it would prefer not to disrupt scroll positioning 6515 * 6516 * @see #setRevealOnFocusHint(boolean) 6517 */ 6518 public final boolean getRevealOnFocusHint() { 6519 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6520 } 6521 6522 /** 6523 * Populates <code>outRect</code> with the hotspot bounds. By default, 6524 * the hotspot bounds are identical to the screen bounds. 6525 * 6526 * @param outRect rect to populate with hotspot bounds 6527 * @hide Only for internal use by views and widgets. 6528 */ 6529 public void getHotspotBounds(Rect outRect) { 6530 final Drawable background = getBackground(); 6531 if (background != null) { 6532 background.getHotspotBounds(outRect); 6533 } else { 6534 getBoundsOnScreen(outRect); 6535 } 6536 } 6537 6538 /** 6539 * Request that a rectangle of this view be visible on the screen, 6540 * scrolling if necessary just enough. 6541 * 6542 * <p>A View should call this if it maintains some notion of which part 6543 * of its content is interesting. For example, a text editing view 6544 * should call this when its cursor moves. 6545 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6546 * It should not be affected by which part of the View is currently visible or its scroll 6547 * position. 6548 * 6549 * @param rectangle The rectangle in the View's content coordinate space 6550 * @return Whether any parent scrolled. 6551 */ 6552 public boolean requestRectangleOnScreen(Rect rectangle) { 6553 return requestRectangleOnScreen(rectangle, false); 6554 } 6555 6556 /** 6557 * Request that a rectangle of this view be visible on the screen, 6558 * scrolling if necessary just enough. 6559 * 6560 * <p>A View should call this if it maintains some notion of which part 6561 * of its content is interesting. For example, a text editing view 6562 * should call this when its cursor moves. 6563 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6564 * It should not be affected by which part of the View is currently visible or its scroll 6565 * position. 6566 * <p>When <code>immediate</code> is set to true, scrolling will not be 6567 * animated. 6568 * 6569 * @param rectangle The rectangle in the View's content coordinate space 6570 * @param immediate True to forbid animated scrolling, false otherwise 6571 * @return Whether any parent scrolled. 6572 */ 6573 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6574 if (mParent == null) { 6575 return false; 6576 } 6577 6578 View child = this; 6579 6580 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6581 position.set(rectangle); 6582 6583 ViewParent parent = mParent; 6584 boolean scrolled = false; 6585 while (parent != null) { 6586 rectangle.set((int) position.left, (int) position.top, 6587 (int) position.right, (int) position.bottom); 6588 6589 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6590 6591 if (!(parent instanceof View)) { 6592 break; 6593 } 6594 6595 // move it from child's content coordinate space to parent's content coordinate space 6596 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6597 6598 child = (View) parent; 6599 parent = child.getParent(); 6600 } 6601 6602 return scrolled; 6603 } 6604 6605 /** 6606 * Called when this view wants to give up focus. If focus is cleared 6607 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6608 * <p> 6609 * <strong>Note:</strong> When a View clears focus the framework is trying 6610 * to give focus to the first focusable View from the top. Hence, if this 6611 * View is the first from the top that can take focus, then all callbacks 6612 * related to clearing focus will be invoked after which the framework will 6613 * give focus to this view. 6614 * </p> 6615 */ 6616 public void clearFocus() { 6617 if (DBG) { 6618 System.out.println(this + " clearFocus()"); 6619 } 6620 6621 clearFocusInternal(null, true, true); 6622 } 6623 6624 /** 6625 * Clears focus from the view, optionally propagating the change up through 6626 * the parent hierarchy and requesting that the root view place new focus. 6627 * 6628 * @param propagate whether to propagate the change up through the parent 6629 * hierarchy 6630 * @param refocus when propagate is true, specifies whether to request the 6631 * root view place new focus 6632 */ 6633 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6634 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6635 mPrivateFlags &= ~PFLAG_FOCUSED; 6636 6637 if (propagate && mParent != null) { 6638 mParent.clearChildFocus(this); 6639 } 6640 6641 onFocusChanged(false, 0, null); 6642 refreshDrawableState(); 6643 6644 if (propagate && (!refocus || !rootViewRequestFocus())) { 6645 notifyGlobalFocusCleared(this); 6646 } 6647 } 6648 } 6649 6650 void notifyGlobalFocusCleared(View oldFocus) { 6651 if (oldFocus != null && mAttachInfo != null) { 6652 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6653 } 6654 } 6655 6656 boolean rootViewRequestFocus() { 6657 final View root = getRootView(); 6658 return root != null && root.requestFocus(); 6659 } 6660 6661 /** 6662 * Called internally by the view system when a new view is getting focus. 6663 * This is what clears the old focus. 6664 * <p> 6665 * <b>NOTE:</b> The parent view's focused child must be updated manually 6666 * after calling this method. Otherwise, the view hierarchy may be left in 6667 * an inconstent state. 6668 */ 6669 void unFocus(View focused) { 6670 if (DBG) { 6671 System.out.println(this + " unFocus()"); 6672 } 6673 6674 clearFocusInternal(focused, false, false); 6675 } 6676 6677 /** 6678 * Returns true if this view has focus itself, or is the ancestor of the 6679 * view that has focus. 6680 * 6681 * @return True if this view has or contains focus, false otherwise. 6682 */ 6683 @ViewDebug.ExportedProperty(category = "focus") 6684 public boolean hasFocus() { 6685 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6686 } 6687 6688 /** 6689 * Returns true if this view is focusable or if it contains a reachable View 6690 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 6691 * is a view whose parents do not block descendants focus. 6692 * Only {@link #VISIBLE} views are considered focusable. 6693 * 6694 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 6695 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 6696 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 6697 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 6698 * {@code false} for views not explicitly marked as focusable. 6699 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 6700 * behavior.</p> 6701 * 6702 * @return {@code true} if the view is focusable or if the view contains a focusable 6703 * view, {@code false} otherwise 6704 * 6705 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6706 * @see ViewGroup#getTouchscreenBlocksFocus() 6707 * @see #hasExplicitFocusable() 6708 */ 6709 public boolean hasFocusable() { 6710 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 6711 } 6712 6713 /** 6714 * Returns true if this view is focusable or if it contains a reachable View 6715 * for which {@link #hasExplicitFocusable()} returns {@code true}. 6716 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 6717 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 6718 * {@link #FOCUSABLE} are considered focusable. 6719 * 6720 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 6721 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 6722 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 6723 * to focusable will not.</p> 6724 * 6725 * @return {@code true} if the view is focusable or if the view contains a focusable 6726 * view, {@code false} otherwise 6727 * 6728 * @see #hasFocusable() 6729 */ 6730 public boolean hasExplicitFocusable() { 6731 return hasFocusable(false, true); 6732 } 6733 6734 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 6735 if (!isFocusableInTouchMode()) { 6736 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6737 final ViewGroup g = (ViewGroup) p; 6738 if (g.shouldBlockFocusForTouchscreen()) { 6739 return false; 6740 } 6741 } 6742 } 6743 6744 // Invisible and gone views are never focusable. 6745 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 6746 return false; 6747 } 6748 6749 // Only use effective focusable value when allowed. 6750 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 6751 return true; 6752 } 6753 6754 return false; 6755 } 6756 6757 /** 6758 * Called by the view system when the focus state of this view changes. 6759 * When the focus change event is caused by directional navigation, direction 6760 * and previouslyFocusedRect provide insight into where the focus is coming from. 6761 * When overriding, be sure to call up through to the super class so that 6762 * the standard focus handling will occur. 6763 * 6764 * @param gainFocus True if the View has focus; false otherwise. 6765 * @param direction The direction focus has moved when requestFocus() 6766 * is called to give this view focus. Values are 6767 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6768 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6769 * It may not always apply, in which case use the default. 6770 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6771 * system, of the previously focused view. If applicable, this will be 6772 * passed in as finer grained information about where the focus is coming 6773 * from (in addition to direction). Will be <code>null</code> otherwise. 6774 */ 6775 @CallSuper 6776 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6777 @Nullable Rect previouslyFocusedRect) { 6778 if (gainFocus) { 6779 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6780 } else { 6781 notifyViewAccessibilityStateChangedIfNeeded( 6782 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6783 } 6784 6785 InputMethodManager imm = InputMethodManager.peekInstance(); 6786 if (!gainFocus) { 6787 if (isPressed()) { 6788 setPressed(false); 6789 } 6790 if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6791 imm.focusOut(this); 6792 } 6793 onFocusLost(); 6794 } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6795 imm.focusIn(this); 6796 } 6797 6798 invalidate(true); 6799 ListenerInfo li = mListenerInfo; 6800 if (li != null && li.mOnFocusChangeListener != null) { 6801 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6802 } 6803 6804 if (mAttachInfo != null) { 6805 mAttachInfo.mKeyDispatchState.reset(this); 6806 } 6807 6808 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 6809 } 6810 6811 private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 6812 if (isAutofillable() && isAttachedToWindow() 6813 && getResolvedAutofillMode() == AUTOFILL_MODE_AUTO) { 6814 AutofillManager afm = getAutofillManager(); 6815 if (afm != null) { 6816 if (enter && hasWindowFocus() && isFocused()) { 6817 afm.notifyViewEntered(this); 6818 } else if (!hasWindowFocus() || !isFocused()) { 6819 afm.notifyViewExited(this); 6820 } 6821 } 6822 } 6823 } 6824 6825 /** 6826 * Sends an accessibility event of the given type. If accessibility is 6827 * not enabled this method has no effect. The default implementation calls 6828 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6829 * to populate information about the event source (this View), then calls 6830 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6831 * populate the text content of the event source including its descendants, 6832 * and last calls 6833 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6834 * on its parent to request sending of the event to interested parties. 6835 * <p> 6836 * If an {@link AccessibilityDelegate} has been specified via calling 6837 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6838 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6839 * responsible for handling this call. 6840 * </p> 6841 * 6842 * @param eventType The type of the event to send, as defined by several types from 6843 * {@link android.view.accessibility.AccessibilityEvent}, such as 6844 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6845 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6846 * 6847 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6848 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6849 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6850 * @see AccessibilityDelegate 6851 */ 6852 public void sendAccessibilityEvent(int eventType) { 6853 if (mAccessibilityDelegate != null) { 6854 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6855 } else { 6856 sendAccessibilityEventInternal(eventType); 6857 } 6858 } 6859 6860 /** 6861 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6862 * {@link AccessibilityEvent} to make an announcement which is related to some 6863 * sort of a context change for which none of the events representing UI transitions 6864 * is a good fit. For example, announcing a new page in a book. If accessibility 6865 * is not enabled this method does nothing. 6866 * 6867 * @param text The announcement text. 6868 */ 6869 public void announceForAccessibility(CharSequence text) { 6870 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6871 AccessibilityEvent event = AccessibilityEvent.obtain( 6872 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6873 onInitializeAccessibilityEvent(event); 6874 event.getText().add(text); 6875 event.setContentDescription(null); 6876 mParent.requestSendAccessibilityEvent(this, event); 6877 } 6878 } 6879 6880 /** 6881 * @see #sendAccessibilityEvent(int) 6882 * 6883 * Note: Called from the default {@link AccessibilityDelegate}. 6884 * 6885 * @hide 6886 */ 6887 public void sendAccessibilityEventInternal(int eventType) { 6888 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 6889 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 6890 } 6891 } 6892 6893 /** 6894 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 6895 * takes as an argument an empty {@link AccessibilityEvent} and does not 6896 * perform a check whether accessibility is enabled. 6897 * <p> 6898 * If an {@link AccessibilityDelegate} has been specified via calling 6899 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6900 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 6901 * is responsible for handling this call. 6902 * </p> 6903 * 6904 * @param event The event to send. 6905 * 6906 * @see #sendAccessibilityEvent(int) 6907 */ 6908 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 6909 if (mAccessibilityDelegate != null) { 6910 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 6911 } else { 6912 sendAccessibilityEventUncheckedInternal(event); 6913 } 6914 } 6915 6916 /** 6917 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 6918 * 6919 * Note: Called from the default {@link AccessibilityDelegate}. 6920 * 6921 * @hide 6922 */ 6923 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 6924 if (!isShown()) { 6925 return; 6926 } 6927 onInitializeAccessibilityEvent(event); 6928 // Only a subset of accessibility events populates text content. 6929 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 6930 dispatchPopulateAccessibilityEvent(event); 6931 } 6932 // In the beginning we called #isShown(), so we know that getParent() is not null. 6933 getParent().requestSendAccessibilityEvent(this, event); 6934 } 6935 6936 /** 6937 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 6938 * to its children for adding their text content to the event. Note that the 6939 * event text is populated in a separate dispatch path since we add to the 6940 * event not only the text of the source but also the text of all its descendants. 6941 * A typical implementation will call 6942 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 6943 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6944 * on each child. Override this method if custom population of the event text 6945 * content is required. 6946 * <p> 6947 * If an {@link AccessibilityDelegate} has been specified via calling 6948 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6949 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 6950 * is responsible for handling this call. 6951 * </p> 6952 * <p> 6953 * <em>Note:</em> Accessibility events of certain types are not dispatched for 6954 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 6955 * </p> 6956 * 6957 * @param event The event. 6958 * 6959 * @return True if the event population was completed. 6960 */ 6961 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 6962 if (mAccessibilityDelegate != null) { 6963 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 6964 } else { 6965 return dispatchPopulateAccessibilityEventInternal(event); 6966 } 6967 } 6968 6969 /** 6970 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6971 * 6972 * Note: Called from the default {@link AccessibilityDelegate}. 6973 * 6974 * @hide 6975 */ 6976 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6977 onPopulateAccessibilityEvent(event); 6978 return false; 6979 } 6980 6981 /** 6982 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6983 * giving a chance to this View to populate the accessibility event with its 6984 * text content. While this method is free to modify event 6985 * attributes other than text content, doing so should normally be performed in 6986 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 6987 * <p> 6988 * Example: Adding formatted date string to an accessibility event in addition 6989 * to the text added by the super implementation: 6990 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6991 * super.onPopulateAccessibilityEvent(event); 6992 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 6993 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 6994 * mCurrentDate.getTimeInMillis(), flags); 6995 * event.getText().add(selectedDateUtterance); 6996 * }</pre> 6997 * <p> 6998 * If an {@link AccessibilityDelegate} has been specified via calling 6999 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7000 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 7001 * is responsible for handling this call. 7002 * </p> 7003 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7004 * information to the event, in case the default implementation has basic information to add. 7005 * </p> 7006 * 7007 * @param event The accessibility event which to populate. 7008 * 7009 * @see #sendAccessibilityEvent(int) 7010 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7011 */ 7012 @CallSuper 7013 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7014 if (mAccessibilityDelegate != null) { 7015 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 7016 } else { 7017 onPopulateAccessibilityEventInternal(event); 7018 } 7019 } 7020 7021 /** 7022 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 7023 * 7024 * Note: Called from the default {@link AccessibilityDelegate}. 7025 * 7026 * @hide 7027 */ 7028 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7029 } 7030 7031 /** 7032 * Initializes an {@link AccessibilityEvent} with information about 7033 * this View which is the event source. In other words, the source of 7034 * an accessibility event is the view whose state change triggered firing 7035 * the event. 7036 * <p> 7037 * Example: Setting the password property of an event in addition 7038 * to properties set by the super implementation: 7039 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7040 * super.onInitializeAccessibilityEvent(event); 7041 * event.setPassword(true); 7042 * }</pre> 7043 * <p> 7044 * If an {@link AccessibilityDelegate} has been specified via calling 7045 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7046 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 7047 * is responsible for handling this call. 7048 * </p> 7049 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7050 * information to the event, in case the default implementation has basic information to add. 7051 * </p> 7052 * @param event The event to initialize. 7053 * 7054 * @see #sendAccessibilityEvent(int) 7055 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7056 */ 7057 @CallSuper 7058 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7059 if (mAccessibilityDelegate != null) { 7060 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 7061 } else { 7062 onInitializeAccessibilityEventInternal(event); 7063 } 7064 } 7065 7066 /** 7067 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 7068 * 7069 * Note: Called from the default {@link AccessibilityDelegate}. 7070 * 7071 * @hide 7072 */ 7073 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 7074 event.setSource(this); 7075 event.setClassName(getAccessibilityClassName()); 7076 event.setPackageName(getContext().getPackageName()); 7077 event.setEnabled(isEnabled()); 7078 event.setContentDescription(mContentDescription); 7079 7080 switch (event.getEventType()) { 7081 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 7082 ArrayList<View> focusablesTempList = (mAttachInfo != null) 7083 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 7084 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 7085 event.setItemCount(focusablesTempList.size()); 7086 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 7087 if (mAttachInfo != null) { 7088 focusablesTempList.clear(); 7089 } 7090 } break; 7091 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 7092 CharSequence text = getIterableTextForAccessibility(); 7093 if (text != null && text.length() > 0) { 7094 event.setFromIndex(getAccessibilitySelectionStart()); 7095 event.setToIndex(getAccessibilitySelectionEnd()); 7096 event.setItemCount(text.length()); 7097 } 7098 } break; 7099 } 7100 } 7101 7102 /** 7103 * Returns an {@link AccessibilityNodeInfo} representing this view from the 7104 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 7105 * This method is responsible for obtaining an accessibility node info from a 7106 * pool of reusable instances and calling 7107 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 7108 * initialize the former. 7109 * <p> 7110 * Note: The client is responsible for recycling the obtained instance by calling 7111 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 7112 * </p> 7113 * 7114 * @return A populated {@link AccessibilityNodeInfo}. 7115 * 7116 * @see AccessibilityNodeInfo 7117 */ 7118 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 7119 if (mAccessibilityDelegate != null) { 7120 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 7121 } else { 7122 return createAccessibilityNodeInfoInternal(); 7123 } 7124 } 7125 7126 /** 7127 * @see #createAccessibilityNodeInfo() 7128 * 7129 * @hide 7130 */ 7131 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 7132 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7133 if (provider != null) { 7134 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 7135 } else { 7136 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 7137 onInitializeAccessibilityNodeInfo(info); 7138 return info; 7139 } 7140 } 7141 7142 /** 7143 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 7144 * The base implementation sets: 7145 * <ul> 7146 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 7147 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 7148 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 7149 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 7150 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 7151 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 7152 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 7153 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 7154 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 7155 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 7156 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 7157 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 7158 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 7159 * </ul> 7160 * <p> 7161 * Subclasses should override this method, call the super implementation, 7162 * and set additional attributes. 7163 * </p> 7164 * <p> 7165 * If an {@link AccessibilityDelegate} has been specified via calling 7166 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7167 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 7168 * is responsible for handling this call. 7169 * </p> 7170 * 7171 * @param info The instance to initialize. 7172 */ 7173 @CallSuper 7174 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 7175 if (mAccessibilityDelegate != null) { 7176 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 7177 } else { 7178 onInitializeAccessibilityNodeInfoInternal(info); 7179 } 7180 } 7181 7182 /** 7183 * Gets the location of this view in screen coordinates. 7184 * 7185 * @param outRect The output location 7186 * @hide 7187 */ 7188 public void getBoundsOnScreen(Rect outRect) { 7189 getBoundsOnScreen(outRect, false); 7190 } 7191 7192 /** 7193 * Gets the location of this view in screen coordinates. 7194 * 7195 * @param outRect The output location 7196 * @param clipToParent Whether to clip child bounds to the parent ones. 7197 * @hide 7198 */ 7199 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 7200 if (mAttachInfo == null) { 7201 return; 7202 } 7203 7204 RectF position = mAttachInfo.mTmpTransformRect; 7205 position.set(0, 0, mRight - mLeft, mBottom - mTop); 7206 7207 if (!hasIdentityMatrix()) { 7208 getMatrix().mapRect(position); 7209 } 7210 7211 position.offset(mLeft, mTop); 7212 7213 ViewParent parent = mParent; 7214 while (parent instanceof View) { 7215 View parentView = (View) parent; 7216 7217 position.offset(-parentView.mScrollX, -parentView.mScrollY); 7218 7219 if (clipToParent) { 7220 position.left = Math.max(position.left, 0); 7221 position.top = Math.max(position.top, 0); 7222 position.right = Math.min(position.right, parentView.getWidth()); 7223 position.bottom = Math.min(position.bottom, parentView.getHeight()); 7224 } 7225 7226 if (!parentView.hasIdentityMatrix()) { 7227 parentView.getMatrix().mapRect(position); 7228 } 7229 7230 position.offset(parentView.mLeft, parentView.mTop); 7231 7232 parent = parentView.mParent; 7233 } 7234 7235 if (parent instanceof ViewRootImpl) { 7236 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 7237 position.offset(0, -viewRootImpl.mCurScrollY); 7238 } 7239 7240 position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 7241 7242 outRect.set(Math.round(position.left), Math.round(position.top), 7243 Math.round(position.right), Math.round(position.bottom)); 7244 } 7245 7246 /** 7247 * Return the class name of this object to be used for accessibility purposes. 7248 * Subclasses should only override this if they are implementing something that 7249 * should be seen as a completely new class of view when used by accessibility, 7250 * unrelated to the class it is deriving from. This is used to fill in 7251 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 7252 */ 7253 public CharSequence getAccessibilityClassName() { 7254 return View.class.getName(); 7255 } 7256 7257 /** 7258 * Called when assist structure is being retrieved from a view as part of 7259 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 7260 * @param structure Fill in with structured view data. The default implementation 7261 * fills in all data that can be inferred from the view itself. 7262 */ 7263 public void onProvideStructure(ViewStructure structure) { 7264 onProvideStructureForAssistOrAutofill(structure, false); 7265 } 7266 7267 /** 7268 * Called when assist structure is being retrieved from a view as part of an autofill request. 7269 * 7270 * <p>This method already provides most of what's needed for autofill, but should be overridden 7271 * when: 7272 * <ol> 7273 * <li>The view contents does not include PII (Personally Identifiable Information), so it 7274 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 7275 * <li>It must set fields such {@link ViewStructure#setText(CharSequence)}, 7276 * {@link ViewStructure#setAutofillOptions(String[])}, or {@link ViewStructure#setUrl(String)}. 7277 * </ol> 7278 * 7279 * @param structure Fill in with structured view data. The default implementation 7280 * fills in all data that can be inferred from the view itself. 7281 * @param flags optional flags (currently {@code 0}). 7282 */ 7283 @CallSuper 7284 public void onProvideAutofillStructure(ViewStructure structure, int flags) { 7285 onProvideStructureForAssistOrAutofill(structure, true); 7286 } 7287 7288 private void onProvideStructureForAssistOrAutofill(ViewStructure structure, 7289 boolean forAutofill) { 7290 final int id = mID; 7291 if (id != NO_ID && !isViewIdGenerated(id)) { 7292 String pkg, type, entry; 7293 try { 7294 final Resources res = getResources(); 7295 entry = res.getResourceEntryName(id); 7296 type = res.getResourceTypeName(id); 7297 pkg = res.getResourcePackageName(id); 7298 } catch (Resources.NotFoundException e) { 7299 entry = type = pkg = null; 7300 } 7301 structure.setId(id, pkg, type, entry); 7302 } else { 7303 structure.setId(id, null, null, null); 7304 } 7305 7306 if (forAutofill) { 7307 final @AutofillType int autofillType = getAutofillType(); 7308 // Don't need to fill autofill info if view does not support it. 7309 // For example, only TextViews that are editable support autofill 7310 if (autofillType != AUTOFILL_TYPE_NONE) { 7311 // The autofill id needs to be unique, but its value doesn't matter, so it's better 7312 // to reuse the accessibility id to save space. 7313 structure.setAutofillId(getAccessibilityViewId()); 7314 structure.setAutofillType(autofillType); 7315 structure.setAutofillHint(getAutofillHint()); 7316 structure.setAutofillValue(getAutofillValue()); 7317 } 7318 } 7319 7320 structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop); 7321 if (!hasIdentityMatrix()) { 7322 structure.setTransformation(getMatrix()); 7323 } 7324 structure.setElevation(getZ()); 7325 structure.setVisibility(getVisibility()); 7326 structure.setEnabled(isEnabled()); 7327 if (isClickable()) { 7328 structure.setClickable(true); 7329 } 7330 if (isFocusable()) { 7331 structure.setFocusable(true); 7332 } 7333 if (isFocused()) { 7334 structure.setFocused(true); 7335 } 7336 if (isAccessibilityFocused()) { 7337 structure.setAccessibilityFocused(true); 7338 } 7339 if (isSelected()) { 7340 structure.setSelected(true); 7341 } 7342 if (isActivated()) { 7343 structure.setActivated(true); 7344 } 7345 if (isLongClickable()) { 7346 structure.setLongClickable(true); 7347 } 7348 if (this instanceof Checkable) { 7349 structure.setCheckable(true); 7350 if (((Checkable)this).isChecked()) { 7351 structure.setChecked(true); 7352 } 7353 } 7354 if (isOpaque()) { 7355 structure.setOpaque(true); 7356 } 7357 if (isContextClickable()) { 7358 structure.setContextClickable(true); 7359 } 7360 structure.setClassName(getAccessibilityClassName().toString()); 7361 structure.setContentDescription(getContentDescription()); 7362 } 7363 7364 /** 7365 * Called when assist structure is being retrieved from a view as part of 7366 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 7367 * generate additional virtual structure under this view. The defaullt implementation 7368 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 7369 * view's virtual accessibility nodes, if any. You can override this for a more 7370 * optimal implementation providing this data. 7371 */ 7372 public void onProvideVirtualStructure(ViewStructure structure) { 7373 onProvideVirtualStructureForAssistOrAutofill(structure, false); 7374 } 7375 7376 /** 7377 * Called when assist structure is being retrieved from a view as part of an autofill request 7378 * to generate additional virtual structure under this view. 7379 * 7380 * <p>The default implementation uses {@link #getAccessibilityNodeProvider()} to try to 7381 * generate this from the view's virtual accessibility nodes, if any. You can override this 7382 * for a more optimal implementation providing this data. 7383 * 7384 * <p>When implementing this method, subclasses must follow the rules below: 7385 * 7386 * <ol> 7387 * <li>Also implement {@link #autofillVirtual(int, AutofillValue)} to autofill the virtual 7388 * children. 7389 * <li>Call 7390 * {@link android.view.autofill.AutofillManager#notifyVirtualViewEntered} and 7391 * {@link android.view.autofill.AutofillManager#notifyVirtualViewExited(View, int)} 7392 * when the focus inside the view changed. 7393 * <li>Call {@link android.view.autofill.AutofillManager#notifyVirtualValueChanged(View, int, 7394 * AutofillValue)} when the value of a child changed. 7395 * <li>Call {@link AutofillManager#commit()} when the autofill context 7396 * of the view structure changed and you want the current autofill interaction if such 7397 * to be commited. 7398 * <li>Call {@link AutofillManager#cancel()} ()} when the autofill context 7399 * of the view structure changed and you want the current autofill interaction if such 7400 * to be cancelled. 7401 * </ol> 7402 * 7403 * @param structure Fill in with structured view data. 7404 * @param flags optional flags (currently {@code 0}). 7405 */ 7406 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 7407 onProvideVirtualStructureForAssistOrAutofill(structure, true); 7408 } 7409 7410 private void onProvideVirtualStructureForAssistOrAutofill(ViewStructure structure, 7411 boolean forAutofill) { 7412 // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well, 7413 // this method should take a boolean with the type of request. 7414 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7415 if (provider != null) { 7416 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7417 structure.setChildCount(1); 7418 ViewStructure root = structure.newChild(0); 7419 populateVirtualStructure(root, provider, info, forAutofill); 7420 info.recycle(); 7421 } 7422 } 7423 7424 /** 7425 * Automatically fills the content of this view with the {@code value}. 7426 * 7427 * <p>By default does nothing, but views should override it (and {@link #getAutofillType()}, 7428 * {@link #getAutofillValue()}, and {@link #onProvideAutofillStructure(ViewStructure, int)} 7429 * to support the Autofill Framework. 7430 * 7431 * <p>Typically, it is implemented by: 7432 * 7433 * <ol> 7434 * <li>Calling the proper getter method on {@link AutofillValue} to fetch the actual value. 7435 * <li>Passing the actual value to the equivalent setter in the view. 7436 * <ol> 7437 * 7438 * <p>For example, a text-field view would call: 7439 * 7440 * <pre class="prettyprint"> 7441 * CharSequence text = value.getTextValue(); 7442 * if (text != null) { 7443 * setText(text); 7444 * } 7445 * </pre> 7446 * 7447 * @param value value to be autofilled. 7448 */ 7449 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 7450 } 7451 7452 /** 7453 * Automatically fills the content of a virtual view with the {@code value} 7454 * 7455 * <p>See {@link #autofill(AutofillValue)} and 7456 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info. 7457 * 7458 * @param value value to be autofilled. 7459 * @param virtualId id identifying the virtual child inside the custom view. 7460 */ 7461 public void autofillVirtual(@SuppressWarnings("unused") int virtualId, 7462 @SuppressWarnings("unused") AutofillValue value) { 7463 } 7464 7465 /** 7466 * Describes the autofill type that should be used on calls to 7467 * {@link #autofill(AutofillValue)} and {@link #autofillVirtual(int, AutofillValue)}. 7468 * 7469 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it (and 7470 * {@link #autofill(AutofillValue)} to support the Autofill Framework. 7471 */ 7472 public @AutofillType int getAutofillType() { 7473 return AUTOFILL_TYPE_NONE; 7474 } 7475 7476 /** 7477 * Describes the content of a view so that a autofill service can fill in the appropriate data. 7478 * 7479 * @return The hint set via the attribute or {@code null} if no hint it set. 7480 * 7481 * @attr ref android.R.styleable#View_autofillHint 7482 */ 7483 @ViewDebug.ExportedProperty() 7484 @Nullable public String[] getAutofillHint() { 7485 return mAutofillHint; 7486 } 7487 7488 /** 7489 * Gets the {@link View}'s current autofill value. 7490 * 7491 * <p>By default returns {@code null}, but views should override it (and 7492 * {@link #autofill(AutofillValue)}, and {@link #getAutofillType()} to support the Autofill 7493 * Framework. 7494 */ 7495 @Nullable 7496 public AutofillValue getAutofillValue() { 7497 return null; 7498 } 7499 7500 /** 7501 * Gets the mode for determining whether this View is important for autofill. 7502 * 7503 * <p>See {@link #setImportantForAutofill(int)} for more info about this mode. 7504 * 7505 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 7506 * {@link #setImportantForAutofill(int)}. 7507 * 7508 * @attr ref android.R.styleable#View_importantForAutofill 7509 */ 7510 @ViewDebug.ExportedProperty(mapping = { 7511 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 7512 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 7513 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no")}) 7514 public @AutofillImportance int getImportantForAutofill() { 7515 return (mPrivateFlags3 7516 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 7517 } 7518 7519 /** 7520 * Sets the mode for determining whether this View is important for autofill. 7521 * 7522 * <p>See {@link #setImportantForAutofill(int)} for more info about this mode. 7523 * 7524 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 7525 * or {@link #IMPORTANT_FOR_AUTOFILL_NO}. 7526 * 7527 * @attr ref android.R.styleable#View_importantForAutofill 7528 */ 7529 public void setImportantForAutofill(@AutofillImportance int mode) { 7530 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7531 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 7532 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7533 } 7534 7535 /** 7536 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 7537 * associated with this View should be included in a {@link ViewStructure} used for 7538 * autofill purposes. 7539 * 7540 * <p>Generally speaking, a view is important for autofill if: 7541 * <ol> 7542 * <li>The view can-be autofilled by an {@link android.service.autofill.AutofillService}. 7543 * <li>The view contents can help an {@link android.service.autofill.AutofillService} to 7544 * autofill other views. 7545 * <ol> 7546 * 7547 * <p>For example, view containers should typically return {@code false} for performance reasons 7548 * (since the important info is provided by their children), but if the container is actually 7549 * whose children are part of a compound view, it should return {@code true} (and then override 7550 * {@link #dispatchProvideAutofillStructure(ViewStructure, int)} to simply call 7551 * {@link #onProvideAutofillStructure(ViewStructure, int)} so its children are not included in 7552 * the structure). On the other hand, views representing labels or editable fields should 7553 * typically return {@code true}, but in some cases they could return {@code false} (for 7554 * example, if they're part of a "Captcha" mechanism). 7555 * 7556 * <p>By default, this method returns {@code true} if {@link #getImportantForAutofill()} returns 7557 * {@link #IMPORTANT_FOR_AUTOFILL_YES}, {@code false } if it returns 7558 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, and use some heuristics to define the importance when it 7559 * returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}. Hence, it should rarely be overridden - Views 7560 * should use {@link #setImportantForAutofill(int)} instead. 7561 * 7562 * <p><strong>Note:</strong> returning {@code false} does not guarantee the view will be 7563 * excluded from the structure; for example, if the user explicitly requested auto-fill, the 7564 * View might be always included. 7565 * 7566 * <p>This decision applies just for the view, not its children - if the view children are not 7567 * important for autofill, the view should override 7568 * {@link #dispatchProvideAutofillStructure(ViewStructure, int)} to simply call 7569 * {@link #onProvideAutofillStructure(ViewStructure, int)} (instead of calling 7570 * {@link #dispatchProvideAutofillStructure(ViewStructure, int)} for each child). 7571 * 7572 * @return whether the view is considered important for autofill. 7573 * 7574 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 7575 * @see #IMPORTANT_FOR_AUTOFILL_YES 7576 * @see #IMPORTANT_FOR_AUTOFILL_NO 7577 */ 7578 public final boolean isImportantForAutofill() { 7579 final int flag = getImportantForAutofill(); 7580 7581 // First, check if view explicity set it to YES or NO 7582 if ((flag & IMPORTANT_FOR_AUTOFILL_YES) != 0) { 7583 return true; 7584 } 7585 if ((flag & IMPORTANT_FOR_AUTOFILL_NO) != 0) { 7586 return false; 7587 } 7588 7589 // Then use some heuristics to handle AUTO. 7590 7591 // Always include views that have a explicity resource id. 7592 final int id = mID; 7593 if (id != NO_ID && !isViewIdGenerated(id)) { 7594 final Resources res = getResources(); 7595 String entry = null; 7596 String pkg = null; 7597 try { 7598 entry = res.getResourceEntryName(id); 7599 pkg = res.getResourcePackageName(id); 7600 } catch (Resources.NotFoundException e) { 7601 // ignore 7602 } 7603 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 7604 return true; 7605 } 7606 } 7607 7608 // Otherwise, assume it's not important... 7609 return false; 7610 } 7611 7612 @Nullable 7613 private AutofillManager getAutofillManager() { 7614 return mContext.getSystemService(AutofillManager.class); 7615 } 7616 7617 private boolean isAutofillable() { 7618 return getAutofillType() != AUTOFILL_TYPE_NONE && !isAutofillBlocked(); 7619 } 7620 7621 private void populateVirtualStructure(ViewStructure structure, 7622 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, boolean forAutofill) { 7623 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 7624 null, null, null); 7625 Rect rect = structure.getTempRect(); 7626 info.getBoundsInParent(rect); 7627 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 7628 structure.setVisibility(VISIBLE); 7629 structure.setEnabled(info.isEnabled()); 7630 if (info.isClickable()) { 7631 structure.setClickable(true); 7632 } 7633 if (info.isFocusable()) { 7634 structure.setFocusable(true); 7635 } 7636 if (info.isFocused()) { 7637 structure.setFocused(true); 7638 } 7639 if (info.isAccessibilityFocused()) { 7640 structure.setAccessibilityFocused(true); 7641 } 7642 if (info.isSelected()) { 7643 structure.setSelected(true); 7644 } 7645 if (info.isLongClickable()) { 7646 structure.setLongClickable(true); 7647 } 7648 if (info.isCheckable()) { 7649 structure.setCheckable(true); 7650 if (info.isChecked()) { 7651 structure.setChecked(true); 7652 } 7653 } 7654 if (info.isContextClickable()) { 7655 structure.setContextClickable(true); 7656 } 7657 CharSequence cname = info.getClassName(); 7658 structure.setClassName(cname != null ? cname.toString() : null); 7659 structure.setContentDescription(info.getContentDescription()); 7660 if (!forAutofill && (info.getText() != null || info.getError() != null)) { 7661 // TODO(b/33197203) (b/33269702): when sanitized, try to use the Accessibility API to 7662 // just set sanitized values (like text coming from resource files), rather than not 7663 // setting it at all. 7664 structure.setText(info.getText(), info.getTextSelectionStart(), 7665 info.getTextSelectionEnd()); 7666 } 7667 final int NCHILDREN = info.getChildCount(); 7668 if (NCHILDREN > 0) { 7669 structure.setChildCount(NCHILDREN); 7670 for (int i=0; i<NCHILDREN; i++) { 7671 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 7672 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 7673 ViewStructure child = structure.newChild(i); 7674 populateVirtualStructure(child, provider, cinfo, forAutofill); 7675 cinfo.recycle(); 7676 } 7677 } 7678 } 7679 7680 /** 7681 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 7682 * implementation calls {@link #onProvideStructure} and 7683 * {@link #onProvideVirtualStructure}. 7684 */ 7685 public void dispatchProvideStructure(ViewStructure structure) { 7686 dispatchProvideStructureForAssistOrAutofill(structure, false); 7687 } 7688 7689 /** 7690 * Dispatch creation of {@link ViewStructure} down the hierarchy. 7691 * 7692 * <p>The structure must be filled according to the request type, which is set in the 7693 * {@code flags} parameter - see the documentation on each flag for more details. 7694 * 7695 * <p>The default implementation calls {@link #onProvideAutofillStructure(ViewStructure, int)} 7696 * and {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 7697 * 7698 * @param structure Fill in with structured view data. 7699 * @param flags optional flags (currently {@code 0}). 7700 */ 7701 public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) { 7702 dispatchProvideStructureForAssistOrAutofill(structure, true); 7703 } 7704 7705 private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure, 7706 boolean forAutofill) { 7707 boolean blocked = forAutofill ? isAutofillBlocked() : isAssistBlocked(); 7708 if (!blocked) { 7709 if (forAutofill) { 7710 // The autofill id needs to be unique, but its value doesn't matter, 7711 // so it's better to reuse the accessibility id to save space. 7712 structure.setAutofillId(getAccessibilityViewId()); 7713 // NOTE: flags are not currently supported, hence 0 7714 onProvideAutofillStructure(structure, 0); 7715 onProvideAutofillVirtualStructure(structure, 0); 7716 } else { 7717 onProvideStructure(structure); 7718 onProvideVirtualStructure(structure); 7719 } 7720 } else { 7721 structure.setClassName(getAccessibilityClassName().toString()); 7722 structure.setAssistBlocked(true); 7723 } 7724 } 7725 7726 /** 7727 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 7728 * 7729 * Note: Called from the default {@link AccessibilityDelegate}. 7730 * 7731 * @hide 7732 */ 7733 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 7734 if (mAttachInfo == null) { 7735 return; 7736 } 7737 7738 Rect bounds = mAttachInfo.mTmpInvalRect; 7739 7740 getDrawingRect(bounds); 7741 info.setBoundsInParent(bounds); 7742 7743 getBoundsOnScreen(bounds, true); 7744 info.setBoundsInScreen(bounds); 7745 7746 ViewParent parent = getParentForAccessibility(); 7747 if (parent instanceof View) { 7748 info.setParent((View) parent); 7749 } 7750 7751 if (mID != View.NO_ID) { 7752 View rootView = getRootView(); 7753 if (rootView == null) { 7754 rootView = this; 7755 } 7756 7757 View label = rootView.findLabelForView(this, mID); 7758 if (label != null) { 7759 info.setLabeledBy(label); 7760 } 7761 7762 if ((mAttachInfo.mAccessibilityFetchFlags 7763 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 7764 && Resources.resourceHasPackage(mID)) { 7765 try { 7766 String viewId = getResources().getResourceName(mID); 7767 info.setViewIdResourceName(viewId); 7768 } catch (Resources.NotFoundException nfe) { 7769 /* ignore */ 7770 } 7771 } 7772 } 7773 7774 if (mLabelForId != View.NO_ID) { 7775 View rootView = getRootView(); 7776 if (rootView == null) { 7777 rootView = this; 7778 } 7779 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 7780 if (labeled != null) { 7781 info.setLabelFor(labeled); 7782 } 7783 } 7784 7785 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 7786 View rootView = getRootView(); 7787 if (rootView == null) { 7788 rootView = this; 7789 } 7790 View next = rootView.findViewInsideOutShouldExist(this, 7791 mAccessibilityTraversalBeforeId); 7792 if (next != null && next.includeForAccessibility()) { 7793 info.setTraversalBefore(next); 7794 } 7795 } 7796 7797 if (mAccessibilityTraversalAfterId != View.NO_ID) { 7798 View rootView = getRootView(); 7799 if (rootView == null) { 7800 rootView = this; 7801 } 7802 View next = rootView.findViewInsideOutShouldExist(this, 7803 mAccessibilityTraversalAfterId); 7804 if (next != null && next.includeForAccessibility()) { 7805 info.setTraversalAfter(next); 7806 } 7807 } 7808 7809 info.setVisibleToUser(isVisibleToUser()); 7810 7811 info.setImportantForAccessibility(isImportantForAccessibility()); 7812 info.setPackageName(mContext.getPackageName()); 7813 info.setClassName(getAccessibilityClassName()); 7814 info.setContentDescription(getContentDescription()); 7815 7816 info.setEnabled(isEnabled()); 7817 info.setClickable(isClickable()); 7818 info.setFocusable(isFocusable()); 7819 info.setFocused(isFocused()); 7820 info.setAccessibilityFocused(isAccessibilityFocused()); 7821 info.setSelected(isSelected()); 7822 info.setLongClickable(isLongClickable()); 7823 info.setContextClickable(isContextClickable()); 7824 info.setLiveRegion(getAccessibilityLiveRegion()); 7825 7826 // TODO: These make sense only if we are in an AdapterView but all 7827 // views can be selected. Maybe from accessibility perspective 7828 // we should report as selectable view in an AdapterView. 7829 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 7830 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 7831 7832 if (isFocusable()) { 7833 if (isFocused()) { 7834 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 7835 } else { 7836 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 7837 } 7838 } 7839 7840 if (!isAccessibilityFocused()) { 7841 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 7842 } else { 7843 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 7844 } 7845 7846 if (isClickable() && isEnabled()) { 7847 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 7848 } 7849 7850 if (isLongClickable() && isEnabled()) { 7851 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 7852 } 7853 7854 if (isContextClickable() && isEnabled()) { 7855 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 7856 } 7857 7858 CharSequence text = getIterableTextForAccessibility(); 7859 if (text != null && text.length() > 0) { 7860 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 7861 7862 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 7863 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 7864 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 7865 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 7866 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 7867 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 7868 } 7869 7870 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 7871 populateAccessibilityNodeInfoDrawingOrderInParent(info); 7872 } 7873 7874 /** 7875 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 7876 * additional data. 7877 * <p> 7878 * This method only needs overloading if the node is marked as having extra data available. 7879 * </p> 7880 * 7881 * @param info The info to which to add the extra data. Never {@code null}. 7882 * @param extraDataKey A key specifying the type of extra data to add to the info. The 7883 * extra data should be added to the {@link Bundle} returned by 7884 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 7885 * {@code null}. 7886 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 7887 * {@code null} if the service provided no arguments. 7888 * 7889 * @see AccessibilityNodeInfo#setExtraAvailableData 7890 */ 7891 public void addExtraDataToAccessibilityNodeInfo( 7892 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 7893 @Nullable Bundle arguments) { 7894 } 7895 7896 /** 7897 * Determine the order in which this view will be drawn relative to its siblings for a11y 7898 * 7899 * @param info The info whose drawing order should be populated 7900 */ 7901 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 7902 /* 7903 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 7904 * drawing order may not be well-defined, and some Views with custom drawing order may 7905 * not be initialized sufficiently to respond properly getChildDrawingOrder. 7906 */ 7907 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 7908 info.setDrawingOrder(0); 7909 return; 7910 } 7911 int drawingOrderInParent = 1; 7912 // Iterate up the hierarchy if parents are not important for a11y 7913 View viewAtDrawingLevel = this; 7914 final ViewParent parent = getParentForAccessibility(); 7915 while (viewAtDrawingLevel != parent) { 7916 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 7917 if (!(currentParent instanceof ViewGroup)) { 7918 // Should only happen for the Decor 7919 drawingOrderInParent = 0; 7920 break; 7921 } else { 7922 final ViewGroup parentGroup = (ViewGroup) currentParent; 7923 final int childCount = parentGroup.getChildCount(); 7924 if (childCount > 1) { 7925 List<View> preorderedList = parentGroup.buildOrderedChildList(); 7926 if (preorderedList != null) { 7927 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 7928 for (int i = 0; i < childDrawIndex; i++) { 7929 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 7930 } 7931 } else { 7932 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 7933 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 7934 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 7935 .getChildDrawingOrder(childCount, childIndex) : childIndex; 7936 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 7937 if (childDrawIndex != 0) { 7938 for (int i = 0; i < numChildrenToIterate; i++) { 7939 final int otherDrawIndex = (customOrder ? 7940 parentGroup.getChildDrawingOrder(childCount, i) : i); 7941 if (otherDrawIndex < childDrawIndex) { 7942 drawingOrderInParent += 7943 numViewsForAccessibility(parentGroup.getChildAt(i)); 7944 } 7945 } 7946 } 7947 } 7948 } 7949 } 7950 viewAtDrawingLevel = (View) currentParent; 7951 } 7952 info.setDrawingOrder(drawingOrderInParent); 7953 } 7954 7955 private static int numViewsForAccessibility(View view) { 7956 if (view != null) { 7957 if (view.includeForAccessibility()) { 7958 return 1; 7959 } else if (view instanceof ViewGroup) { 7960 return ((ViewGroup) view).getNumChildrenForAccessibility(); 7961 } 7962 } 7963 return 0; 7964 } 7965 7966 private View findLabelForView(View view, int labeledId) { 7967 if (mMatchLabelForPredicate == null) { 7968 mMatchLabelForPredicate = new MatchLabelForPredicate(); 7969 } 7970 mMatchLabelForPredicate.mLabeledId = labeledId; 7971 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 7972 } 7973 7974 /** 7975 * Computes whether this view is visible to the user. Such a view is 7976 * attached, visible, all its predecessors are visible, it is not clipped 7977 * entirely by its predecessors, and has an alpha greater than zero. 7978 * 7979 * @return Whether the view is visible on the screen. 7980 * 7981 * @hide 7982 */ 7983 protected boolean isVisibleToUser() { 7984 return isVisibleToUser(null); 7985 } 7986 7987 /** 7988 * Computes whether the given portion of this view is visible to the user. 7989 * Such a view is attached, visible, all its predecessors are visible, 7990 * has an alpha greater than zero, and the specified portion is not 7991 * clipped entirely by its predecessors. 7992 * 7993 * @param boundInView the portion of the view to test; coordinates should be relative; may be 7994 * <code>null</code>, and the entire view will be tested in this case. 7995 * When <code>true</code> is returned by the function, the actual visible 7996 * region will be stored in this parameter; that is, if boundInView is fully 7997 * contained within the view, no modification will be made, otherwise regions 7998 * outside of the visible area of the view will be clipped. 7999 * 8000 * @return Whether the specified portion of the view is visible on the screen. 8001 * 8002 * @hide 8003 */ 8004 protected boolean isVisibleToUser(Rect boundInView) { 8005 if (mAttachInfo != null) { 8006 // Attached to invisible window means this view is not visible. 8007 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 8008 return false; 8009 } 8010 // An invisible predecessor or one with alpha zero means 8011 // that this view is not visible to the user. 8012 Object current = this; 8013 while (current instanceof View) { 8014 View view = (View) current; 8015 // We have attach info so this view is attached and there is no 8016 // need to check whether we reach to ViewRootImpl on the way up. 8017 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 8018 view.getVisibility() != VISIBLE) { 8019 return false; 8020 } 8021 current = view.mParent; 8022 } 8023 // Check if the view is entirely covered by its predecessors. 8024 Rect visibleRect = mAttachInfo.mTmpInvalRect; 8025 Point offset = mAttachInfo.mPoint; 8026 if (!getGlobalVisibleRect(visibleRect, offset)) { 8027 return false; 8028 } 8029 // Check if the visible portion intersects the rectangle of interest. 8030 if (boundInView != null) { 8031 visibleRect.offset(-offset.x, -offset.y); 8032 return boundInView.intersect(visibleRect); 8033 } 8034 return true; 8035 } 8036 return false; 8037 } 8038 8039 /** 8040 * Returns the delegate for implementing accessibility support via 8041 * composition. For more details see {@link AccessibilityDelegate}. 8042 * 8043 * @return The delegate, or null if none set. 8044 * 8045 * @hide 8046 */ 8047 public AccessibilityDelegate getAccessibilityDelegate() { 8048 return mAccessibilityDelegate; 8049 } 8050 8051 /** 8052 * Sets a delegate for implementing accessibility support via composition 8053 * (as opposed to inheritance). For more details, see 8054 * {@link AccessibilityDelegate}. 8055 * <p> 8056 * <strong>Note:</strong> On platform versions prior to 8057 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 8058 * views in the {@code android.widget.*} package are called <i>before</i> 8059 * host methods. This prevents certain properties such as class name from 8060 * being modified by overriding 8061 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 8062 * as any changes will be overwritten by the host class. 8063 * <p> 8064 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 8065 * methods are called <i>after</i> host methods, which all properties to be 8066 * modified without being overwritten by the host class. 8067 * 8068 * @param delegate the object to which accessibility method calls should be 8069 * delegated 8070 * @see AccessibilityDelegate 8071 */ 8072 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 8073 mAccessibilityDelegate = delegate; 8074 } 8075 8076 /** 8077 * Gets the provider for managing a virtual view hierarchy rooted at this View 8078 * and reported to {@link android.accessibilityservice.AccessibilityService}s 8079 * that explore the window content. 8080 * <p> 8081 * If this method returns an instance, this instance is responsible for managing 8082 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 8083 * View including the one representing the View itself. Similarly the returned 8084 * instance is responsible for performing accessibility actions on any virtual 8085 * view or the root view itself. 8086 * </p> 8087 * <p> 8088 * If an {@link AccessibilityDelegate} has been specified via calling 8089 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8090 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 8091 * is responsible for handling this call. 8092 * </p> 8093 * 8094 * @return The provider. 8095 * 8096 * @see AccessibilityNodeProvider 8097 */ 8098 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 8099 if (mAccessibilityDelegate != null) { 8100 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 8101 } else { 8102 return null; 8103 } 8104 } 8105 8106 /** 8107 * Gets the unique identifier of this view on the screen for accessibility purposes. 8108 * 8109 * @return The view accessibility id. 8110 * 8111 * @hide 8112 */ 8113 public int getAccessibilityViewId() { 8114 if (mAccessibilityViewId == NO_ID) { 8115 mAccessibilityViewId = sNextAccessibilityViewId++; 8116 } 8117 return mAccessibilityViewId; 8118 } 8119 8120 /** 8121 * Gets the unique identifier of the window in which this View reseides. 8122 * 8123 * @return The window accessibility id. 8124 * 8125 * @hide 8126 */ 8127 public int getAccessibilityWindowId() { 8128 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 8129 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 8130 } 8131 8132 /** 8133 * Returns the {@link View}'s content description. 8134 * <p> 8135 * <strong>Note:</strong> Do not override this method, as it will have no 8136 * effect on the content description presented to accessibility services. 8137 * You must call {@link #setContentDescription(CharSequence)} to modify the 8138 * content description. 8139 * 8140 * @return the content description 8141 * @see #setContentDescription(CharSequence) 8142 * @attr ref android.R.styleable#View_contentDescription 8143 */ 8144 @ViewDebug.ExportedProperty(category = "accessibility") 8145 public CharSequence getContentDescription() { 8146 return mContentDescription; 8147 } 8148 8149 /** 8150 * Sets the {@link View}'s content description. 8151 * <p> 8152 * A content description briefly describes the view and is primarily used 8153 * for accessibility support to determine how a view should be presented to 8154 * the user. In the case of a view with no textual representation, such as 8155 * {@link android.widget.ImageButton}, a useful content description 8156 * explains what the view does. For example, an image button with a phone 8157 * icon that is used to place a call may use "Call" as its content 8158 * description. An image of a floppy disk that is used to save a file may 8159 * use "Save". 8160 * 8161 * @param contentDescription The content description. 8162 * @see #getContentDescription() 8163 * @attr ref android.R.styleable#View_contentDescription 8164 */ 8165 @RemotableViewMethod 8166 public void setContentDescription(CharSequence contentDescription) { 8167 if (mContentDescription == null) { 8168 if (contentDescription == null) { 8169 return; 8170 } 8171 } else if (mContentDescription.equals(contentDescription)) { 8172 return; 8173 } 8174 mContentDescription = contentDescription; 8175 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 8176 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 8177 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 8178 notifySubtreeAccessibilityStateChangedIfNeeded(); 8179 } else { 8180 notifyViewAccessibilityStateChangedIfNeeded( 8181 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 8182 } 8183 } 8184 8185 /** 8186 * Sets the id of a view before which this one is visited in accessibility traversal. 8187 * A screen-reader must visit the content of this view before the content of the one 8188 * it precedes. For example, if view B is set to be before view A, then a screen-reader 8189 * will traverse the entire content of B before traversing the entire content of A, 8190 * regardles of what traversal strategy it is using. 8191 * <p> 8192 * Views that do not have specified before/after relationships are traversed in order 8193 * determined by the screen-reader. 8194 * </p> 8195 * <p> 8196 * Setting that this view is before a view that is not important for accessibility 8197 * or if this view is not important for accessibility will have no effect as the 8198 * screen-reader is not aware of unimportant views. 8199 * </p> 8200 * 8201 * @param beforeId The id of a view this one precedes in accessibility traversal. 8202 * 8203 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 8204 * 8205 * @see #setImportantForAccessibility(int) 8206 */ 8207 @RemotableViewMethod 8208 public void setAccessibilityTraversalBefore(int beforeId) { 8209 if (mAccessibilityTraversalBeforeId == beforeId) { 8210 return; 8211 } 8212 mAccessibilityTraversalBeforeId = beforeId; 8213 notifyViewAccessibilityStateChangedIfNeeded( 8214 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8215 } 8216 8217 /** 8218 * Gets the id of a view before which this one is visited in accessibility traversal. 8219 * 8220 * @return The id of a view this one precedes in accessibility traversal if 8221 * specified, otherwise {@link #NO_ID}. 8222 * 8223 * @see #setAccessibilityTraversalBefore(int) 8224 */ 8225 public int getAccessibilityTraversalBefore() { 8226 return mAccessibilityTraversalBeforeId; 8227 } 8228 8229 /** 8230 * Sets the id of a view after which this one is visited in accessibility traversal. 8231 * A screen-reader must visit the content of the other view before the content of this 8232 * one. For example, if view B is set to be after view A, then a screen-reader 8233 * will traverse the entire content of A before traversing the entire content of B, 8234 * regardles of what traversal strategy it is using. 8235 * <p> 8236 * Views that do not have specified before/after relationships are traversed in order 8237 * determined by the screen-reader. 8238 * </p> 8239 * <p> 8240 * Setting that this view is after a view that is not important for accessibility 8241 * or if this view is not important for accessibility will have no effect as the 8242 * screen-reader is not aware of unimportant views. 8243 * </p> 8244 * 8245 * @param afterId The id of a view this one succedees in accessibility traversal. 8246 * 8247 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 8248 * 8249 * @see #setImportantForAccessibility(int) 8250 */ 8251 @RemotableViewMethod 8252 public void setAccessibilityTraversalAfter(int afterId) { 8253 if (mAccessibilityTraversalAfterId == afterId) { 8254 return; 8255 } 8256 mAccessibilityTraversalAfterId = afterId; 8257 notifyViewAccessibilityStateChangedIfNeeded( 8258 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8259 } 8260 8261 /** 8262 * Gets the id of a view after which this one is visited in accessibility traversal. 8263 * 8264 * @return The id of a view this one succeedes in accessibility traversal if 8265 * specified, otherwise {@link #NO_ID}. 8266 * 8267 * @see #setAccessibilityTraversalAfter(int) 8268 */ 8269 public int getAccessibilityTraversalAfter() { 8270 return mAccessibilityTraversalAfterId; 8271 } 8272 8273 /** 8274 * Gets the id of a view for which this view serves as a label for 8275 * accessibility purposes. 8276 * 8277 * @return The labeled view id. 8278 */ 8279 @ViewDebug.ExportedProperty(category = "accessibility") 8280 public int getLabelFor() { 8281 return mLabelForId; 8282 } 8283 8284 /** 8285 * Sets the id of a view for which this view serves as a label for 8286 * accessibility purposes. 8287 * 8288 * @param id The labeled view id. 8289 */ 8290 @RemotableViewMethod 8291 public void setLabelFor(@IdRes int id) { 8292 if (mLabelForId == id) { 8293 return; 8294 } 8295 mLabelForId = id; 8296 if (mLabelForId != View.NO_ID 8297 && mID == View.NO_ID) { 8298 mID = generateViewId(); 8299 } 8300 notifyViewAccessibilityStateChangedIfNeeded( 8301 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8302 } 8303 8304 /** 8305 * Invoked whenever this view loses focus, either by losing window focus or by losing 8306 * focus within its window. This method can be used to clear any state tied to the 8307 * focus. For instance, if a button is held pressed with the trackball and the window 8308 * loses focus, this method can be used to cancel the press. 8309 * 8310 * Subclasses of View overriding this method should always call super.onFocusLost(). 8311 * 8312 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 8313 * @see #onWindowFocusChanged(boolean) 8314 * 8315 * @hide pending API council approval 8316 */ 8317 @CallSuper 8318 protected void onFocusLost() { 8319 resetPressedState(); 8320 } 8321 8322 private void resetPressedState() { 8323 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 8324 return; 8325 } 8326 8327 if (isPressed()) { 8328 setPressed(false); 8329 8330 if (!mHasPerformedLongPress) { 8331 removeLongPressCallback(); 8332 } 8333 } 8334 } 8335 8336 /** 8337 * Returns true if this view has focus 8338 * 8339 * @return True if this view has focus, false otherwise. 8340 */ 8341 @ViewDebug.ExportedProperty(category = "focus") 8342 public boolean isFocused() { 8343 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8344 } 8345 8346 /** 8347 * Find the view in the hierarchy rooted at this view that currently has 8348 * focus. 8349 * 8350 * @return The view that currently has focus, or null if no focused view can 8351 * be found. 8352 */ 8353 public View findFocus() { 8354 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 8355 } 8356 8357 /** 8358 * Indicates whether this view is one of the set of scrollable containers in 8359 * its window. 8360 * 8361 * @return whether this view is one of the set of scrollable containers in 8362 * its window 8363 * 8364 * @attr ref android.R.styleable#View_isScrollContainer 8365 */ 8366 public boolean isScrollContainer() { 8367 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 8368 } 8369 8370 /** 8371 * Change whether this view is one of the set of scrollable containers in 8372 * its window. This will be used to determine whether the window can 8373 * resize or must pan when a soft input area is open -- scrollable 8374 * containers allow the window to use resize mode since the container 8375 * will appropriately shrink. 8376 * 8377 * @attr ref android.R.styleable#View_isScrollContainer 8378 */ 8379 public void setScrollContainer(boolean isScrollContainer) { 8380 if (isScrollContainer) { 8381 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 8382 mAttachInfo.mScrollContainers.add(this); 8383 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 8384 } 8385 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 8386 } else { 8387 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 8388 mAttachInfo.mScrollContainers.remove(this); 8389 } 8390 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 8391 } 8392 } 8393 8394 /** 8395 * Returns the quality of the drawing cache. 8396 * 8397 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8398 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8399 * 8400 * @see #setDrawingCacheQuality(int) 8401 * @see #setDrawingCacheEnabled(boolean) 8402 * @see #isDrawingCacheEnabled() 8403 * 8404 * @attr ref android.R.styleable#View_drawingCacheQuality 8405 */ 8406 @DrawingCacheQuality 8407 public int getDrawingCacheQuality() { 8408 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 8409 } 8410 8411 /** 8412 * Set the drawing cache quality of this view. This value is used only when the 8413 * drawing cache is enabled 8414 * 8415 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8416 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8417 * 8418 * @see #getDrawingCacheQuality() 8419 * @see #setDrawingCacheEnabled(boolean) 8420 * @see #isDrawingCacheEnabled() 8421 * 8422 * @attr ref android.R.styleable#View_drawingCacheQuality 8423 */ 8424 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 8425 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 8426 } 8427 8428 /** 8429 * Returns whether the screen should remain on, corresponding to the current 8430 * value of {@link #KEEP_SCREEN_ON}. 8431 * 8432 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 8433 * 8434 * @see #setKeepScreenOn(boolean) 8435 * 8436 * @attr ref android.R.styleable#View_keepScreenOn 8437 */ 8438 public boolean getKeepScreenOn() { 8439 return (mViewFlags & KEEP_SCREEN_ON) != 0; 8440 } 8441 8442 /** 8443 * Controls whether the screen should remain on, modifying the 8444 * value of {@link #KEEP_SCREEN_ON}. 8445 * 8446 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 8447 * 8448 * @see #getKeepScreenOn() 8449 * 8450 * @attr ref android.R.styleable#View_keepScreenOn 8451 */ 8452 public void setKeepScreenOn(boolean keepScreenOn) { 8453 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 8454 } 8455 8456 /** 8457 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8458 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8459 * 8460 * @attr ref android.R.styleable#View_nextFocusLeft 8461 */ 8462 public int getNextFocusLeftId() { 8463 return mNextFocusLeftId; 8464 } 8465 8466 /** 8467 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8468 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 8469 * decide automatically. 8470 * 8471 * @attr ref android.R.styleable#View_nextFocusLeft 8472 */ 8473 public void setNextFocusLeftId(int nextFocusLeftId) { 8474 mNextFocusLeftId = nextFocusLeftId; 8475 } 8476 8477 /** 8478 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8479 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8480 * 8481 * @attr ref android.R.styleable#View_nextFocusRight 8482 */ 8483 public int getNextFocusRightId() { 8484 return mNextFocusRightId; 8485 } 8486 8487 /** 8488 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8489 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 8490 * decide automatically. 8491 * 8492 * @attr ref android.R.styleable#View_nextFocusRight 8493 */ 8494 public void setNextFocusRightId(int nextFocusRightId) { 8495 mNextFocusRightId = nextFocusRightId; 8496 } 8497 8498 /** 8499 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8500 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8501 * 8502 * @attr ref android.R.styleable#View_nextFocusUp 8503 */ 8504 public int getNextFocusUpId() { 8505 return mNextFocusUpId; 8506 } 8507 8508 /** 8509 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8510 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 8511 * decide automatically. 8512 * 8513 * @attr ref android.R.styleable#View_nextFocusUp 8514 */ 8515 public void setNextFocusUpId(int nextFocusUpId) { 8516 mNextFocusUpId = nextFocusUpId; 8517 } 8518 8519 /** 8520 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8521 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8522 * 8523 * @attr ref android.R.styleable#View_nextFocusDown 8524 */ 8525 public int getNextFocusDownId() { 8526 return mNextFocusDownId; 8527 } 8528 8529 /** 8530 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8531 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 8532 * decide automatically. 8533 * 8534 * @attr ref android.R.styleable#View_nextFocusDown 8535 */ 8536 public void setNextFocusDownId(int nextFocusDownId) { 8537 mNextFocusDownId = nextFocusDownId; 8538 } 8539 8540 /** 8541 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8542 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8543 * 8544 * @attr ref android.R.styleable#View_nextFocusForward 8545 */ 8546 public int getNextFocusForwardId() { 8547 return mNextFocusForwardId; 8548 } 8549 8550 /** 8551 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8552 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 8553 * decide automatically. 8554 * 8555 * @attr ref android.R.styleable#View_nextFocusForward 8556 */ 8557 public void setNextFocusForwardId(int nextFocusForwardId) { 8558 mNextFocusForwardId = nextFocusForwardId; 8559 } 8560 8561 /** 8562 * Gets the id of the root of the next keyboard navigation cluster. 8563 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 8564 * decide automatically. 8565 * 8566 * @attr ref android.R.styleable#View_nextClusterForward 8567 */ 8568 public int getNextClusterForwardId() { 8569 return mNextClusterForwardId; 8570 } 8571 8572 /** 8573 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 8574 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 8575 * decide automatically. 8576 * 8577 * @attr ref android.R.styleable#View_nextClusterForward 8578 */ 8579 public void setNextClusterForwardId(int nextClusterForwardId) { 8580 mNextClusterForwardId = nextClusterForwardId; 8581 } 8582 8583 /** 8584 * Returns the visibility of this view and all of its ancestors 8585 * 8586 * @return True if this view and all of its ancestors are {@link #VISIBLE} 8587 */ 8588 public boolean isShown() { 8589 View current = this; 8590 //noinspection ConstantConditions 8591 do { 8592 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 8593 return false; 8594 } 8595 ViewParent parent = current.mParent; 8596 if (parent == null) { 8597 return false; // We are not attached to the view root 8598 } 8599 if (!(parent instanceof View)) { 8600 return true; 8601 } 8602 current = (View) parent; 8603 } while (current != null); 8604 8605 return false; 8606 } 8607 8608 /** 8609 * Called by the view hierarchy when the content insets for a window have 8610 * changed, to allow it to adjust its content to fit within those windows. 8611 * The content insets tell you the space that the status bar, input method, 8612 * and other system windows infringe on the application's window. 8613 * 8614 * <p>You do not normally need to deal with this function, since the default 8615 * window decoration given to applications takes care of applying it to the 8616 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 8617 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 8618 * and your content can be placed under those system elements. You can then 8619 * use this method within your view hierarchy if you have parts of your UI 8620 * which you would like to ensure are not being covered. 8621 * 8622 * <p>The default implementation of this method simply applies the content 8623 * insets to the view's padding, consuming that content (modifying the 8624 * insets to be 0), and returning true. This behavior is off by default, but can 8625 * be enabled through {@link #setFitsSystemWindows(boolean)}. 8626 * 8627 * <p>This function's traversal down the hierarchy is depth-first. The same content 8628 * insets object is propagated down the hierarchy, so any changes made to it will 8629 * be seen by all following views (including potentially ones above in 8630 * the hierarchy since this is a depth-first traversal). The first view 8631 * that returns true will abort the entire traversal. 8632 * 8633 * <p>The default implementation works well for a situation where it is 8634 * used with a container that covers the entire window, allowing it to 8635 * apply the appropriate insets to its content on all edges. If you need 8636 * a more complicated layout (such as two different views fitting system 8637 * windows, one on the top of the window, and one on the bottom), 8638 * you can override the method and handle the insets however you would like. 8639 * Note that the insets provided by the framework are always relative to the 8640 * far edges of the window, not accounting for the location of the called view 8641 * within that window. (In fact when this method is called you do not yet know 8642 * where the layout will place the view, as it is done before layout happens.) 8643 * 8644 * <p>Note: unlike many View methods, there is no dispatch phase to this 8645 * call. If you are overriding it in a ViewGroup and want to allow the 8646 * call to continue to your children, you must be sure to call the super 8647 * implementation. 8648 * 8649 * <p>Here is a sample layout that makes use of fitting system windows 8650 * to have controls for a video view placed inside of the window decorations 8651 * that it hides and shows. This can be used with code like the second 8652 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 8653 * 8654 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 8655 * 8656 * @param insets Current content insets of the window. Prior to 8657 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 8658 * the insets or else you and Android will be unhappy. 8659 * 8660 * @return {@code true} if this view applied the insets and it should not 8661 * continue propagating further down the hierarchy, {@code false} otherwise. 8662 * @see #getFitsSystemWindows() 8663 * @see #setFitsSystemWindows(boolean) 8664 * @see #setSystemUiVisibility(int) 8665 * 8666 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 8667 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 8668 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 8669 * to implement handling their own insets. 8670 */ 8671 @Deprecated 8672 protected boolean fitSystemWindows(Rect insets) { 8673 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 8674 if (insets == null) { 8675 // Null insets by definition have already been consumed. 8676 // This call cannot apply insets since there are none to apply, 8677 // so return false. 8678 return false; 8679 } 8680 // If we're not in the process of dispatching the newer apply insets call, 8681 // that means we're not in the compatibility path. Dispatch into the newer 8682 // apply insets path and take things from there. 8683 try { 8684 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 8685 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 8686 } finally { 8687 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 8688 } 8689 } else { 8690 // We're being called from the newer apply insets path. 8691 // Perform the standard fallback behavior. 8692 return fitSystemWindowsInt(insets); 8693 } 8694 } 8695 8696 private boolean fitSystemWindowsInt(Rect insets) { 8697 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 8698 mUserPaddingStart = UNDEFINED_PADDING; 8699 mUserPaddingEnd = UNDEFINED_PADDING; 8700 Rect localInsets = sThreadLocal.get(); 8701 if (localInsets == null) { 8702 localInsets = new Rect(); 8703 sThreadLocal.set(localInsets); 8704 } 8705 boolean res = computeFitSystemWindows(insets, localInsets); 8706 mUserPaddingLeftInitial = localInsets.left; 8707 mUserPaddingRightInitial = localInsets.right; 8708 internalSetPadding(localInsets.left, localInsets.top, 8709 localInsets.right, localInsets.bottom); 8710 return res; 8711 } 8712 return false; 8713 } 8714 8715 /** 8716 * Called when the view should apply {@link WindowInsets} according to its internal policy. 8717 * 8718 * <p>This method should be overridden by views that wish to apply a policy different from or 8719 * in addition to the default behavior. Clients that wish to force a view subtree 8720 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 8721 * 8722 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 8723 * it will be called during dispatch instead of this method. The listener may optionally 8724 * call this method from its own implementation if it wishes to apply the view's default 8725 * insets policy in addition to its own.</p> 8726 * 8727 * <p>Implementations of this method should either return the insets parameter unchanged 8728 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 8729 * that this view applied itself. This allows new inset types added in future platform 8730 * versions to pass through existing implementations unchanged without being erroneously 8731 * consumed.</p> 8732 * 8733 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 8734 * property is set then the view will consume the system window insets and apply them 8735 * as padding for the view.</p> 8736 * 8737 * @param insets Insets to apply 8738 * @return The supplied insets with any applied insets consumed 8739 */ 8740 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 8741 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 8742 // We weren't called from within a direct call to fitSystemWindows, 8743 // call into it as a fallback in case we're in a class that overrides it 8744 // and has logic to perform. 8745 if (fitSystemWindows(insets.getSystemWindowInsets())) { 8746 return insets.consumeSystemWindowInsets(); 8747 } 8748 } else { 8749 // We were called from within a direct call to fitSystemWindows. 8750 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 8751 return insets.consumeSystemWindowInsets(); 8752 } 8753 } 8754 return insets; 8755 } 8756 8757 /** 8758 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 8759 * window insets to this view. The listener's 8760 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 8761 * method will be called instead of the view's 8762 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 8763 * 8764 * @param listener Listener to set 8765 * 8766 * @see #onApplyWindowInsets(WindowInsets) 8767 */ 8768 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 8769 getListenerInfo().mOnApplyWindowInsetsListener = listener; 8770 } 8771 8772 /** 8773 * Request to apply the given window insets to this view or another view in its subtree. 8774 * 8775 * <p>This method should be called by clients wishing to apply insets corresponding to areas 8776 * obscured by window decorations or overlays. This can include the status and navigation bars, 8777 * action bars, input methods and more. New inset categories may be added in the future. 8778 * The method returns the insets provided minus any that were applied by this view or its 8779 * children.</p> 8780 * 8781 * <p>Clients wishing to provide custom behavior should override the 8782 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 8783 * {@link OnApplyWindowInsetsListener} via the 8784 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 8785 * method.</p> 8786 * 8787 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 8788 * </p> 8789 * 8790 * @param insets Insets to apply 8791 * @return The provided insets minus the insets that were consumed 8792 */ 8793 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 8794 try { 8795 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 8796 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 8797 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 8798 } else { 8799 return onApplyWindowInsets(insets); 8800 } 8801 } finally { 8802 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 8803 } 8804 } 8805 8806 /** 8807 * Compute the view's coordinate within the surface. 8808 * 8809 * <p>Computes the coordinates of this view in its surface. The argument 8810 * must be an array of two integers. After the method returns, the array 8811 * contains the x and y location in that order.</p> 8812 * @hide 8813 * @param location an array of two integers in which to hold the coordinates 8814 */ 8815 public void getLocationInSurface(@Size(2) int[] location) { 8816 getLocationInWindow(location); 8817 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 8818 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 8819 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 8820 } 8821 } 8822 8823 /** 8824 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 8825 * only available if the view is attached. 8826 * 8827 * @return WindowInsets from the top of the view hierarchy or null if View is detached 8828 */ 8829 public WindowInsets getRootWindowInsets() { 8830 if (mAttachInfo != null) { 8831 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 8832 } 8833 return null; 8834 } 8835 8836 /** 8837 * @hide Compute the insets that should be consumed by this view and the ones 8838 * that should propagate to those under it. 8839 */ 8840 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 8841 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8842 || mAttachInfo == null 8843 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 8844 && !mAttachInfo.mOverscanRequested)) { 8845 outLocalInsets.set(inoutInsets); 8846 inoutInsets.set(0, 0, 0, 0); 8847 return true; 8848 } else { 8849 // The application wants to take care of fitting system window for 8850 // the content... however we still need to take care of any overscan here. 8851 final Rect overscan = mAttachInfo.mOverscanInsets; 8852 outLocalInsets.set(overscan); 8853 inoutInsets.left -= overscan.left; 8854 inoutInsets.top -= overscan.top; 8855 inoutInsets.right -= overscan.right; 8856 inoutInsets.bottom -= overscan.bottom; 8857 return false; 8858 } 8859 } 8860 8861 /** 8862 * Compute insets that should be consumed by this view and the ones that should propagate 8863 * to those under it. 8864 * 8865 * @param in Insets currently being processed by this View, likely received as a parameter 8866 * to {@link #onApplyWindowInsets(WindowInsets)}. 8867 * @param outLocalInsets A Rect that will receive the insets that should be consumed 8868 * by this view 8869 * @return Insets that should be passed along to views under this one 8870 */ 8871 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 8872 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8873 || mAttachInfo == null 8874 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 8875 outLocalInsets.set(in.getSystemWindowInsets()); 8876 return in.consumeSystemWindowInsets(); 8877 } else { 8878 outLocalInsets.set(0, 0, 0, 0); 8879 return in; 8880 } 8881 } 8882 8883 /** 8884 * Sets whether or not this view should account for system screen decorations 8885 * such as the status bar and inset its content; that is, controlling whether 8886 * the default implementation of {@link #fitSystemWindows(Rect)} will be 8887 * executed. See that method for more details. 8888 * 8889 * <p>Note that if you are providing your own implementation of 8890 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 8891 * flag to true -- your implementation will be overriding the default 8892 * implementation that checks this flag. 8893 * 8894 * @param fitSystemWindows If true, then the default implementation of 8895 * {@link #fitSystemWindows(Rect)} will be executed. 8896 * 8897 * @attr ref android.R.styleable#View_fitsSystemWindows 8898 * @see #getFitsSystemWindows() 8899 * @see #fitSystemWindows(Rect) 8900 * @see #setSystemUiVisibility(int) 8901 */ 8902 public void setFitsSystemWindows(boolean fitSystemWindows) { 8903 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 8904 } 8905 8906 /** 8907 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 8908 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 8909 * will be executed. 8910 * 8911 * @return {@code true} if the default implementation of 8912 * {@link #fitSystemWindows(Rect)} will be executed. 8913 * 8914 * @attr ref android.R.styleable#View_fitsSystemWindows 8915 * @see #setFitsSystemWindows(boolean) 8916 * @see #fitSystemWindows(Rect) 8917 * @see #setSystemUiVisibility(int) 8918 */ 8919 @ViewDebug.ExportedProperty 8920 public boolean getFitsSystemWindows() { 8921 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 8922 } 8923 8924 /** @hide */ 8925 public boolean fitsSystemWindows() { 8926 return getFitsSystemWindows(); 8927 } 8928 8929 /** 8930 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 8931 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 8932 */ 8933 @Deprecated 8934 public void requestFitSystemWindows() { 8935 if (mParent != null) { 8936 mParent.requestFitSystemWindows(); 8937 } 8938 } 8939 8940 /** 8941 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 8942 */ 8943 public void requestApplyInsets() { 8944 requestFitSystemWindows(); 8945 } 8946 8947 /** 8948 * For use by PhoneWindow to make its own system window fitting optional. 8949 * @hide 8950 */ 8951 public void makeOptionalFitsSystemWindows() { 8952 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 8953 } 8954 8955 /** 8956 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 8957 * treat them as such. 8958 * @hide 8959 */ 8960 public void getOutsets(Rect outOutsetRect) { 8961 if (mAttachInfo != null) { 8962 outOutsetRect.set(mAttachInfo.mOutsets); 8963 } else { 8964 outOutsetRect.setEmpty(); 8965 } 8966 } 8967 8968 /** 8969 * Returns the visibility status for this view. 8970 * 8971 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8972 * @attr ref android.R.styleable#View_visibility 8973 */ 8974 @ViewDebug.ExportedProperty(mapping = { 8975 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 8976 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 8977 @ViewDebug.IntToString(from = GONE, to = "GONE") 8978 }) 8979 @Visibility 8980 public int getVisibility() { 8981 return mViewFlags & VISIBILITY_MASK; 8982 } 8983 8984 /** 8985 * Set the visibility state of this view. 8986 * 8987 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8988 * @attr ref android.R.styleable#View_visibility 8989 */ 8990 @RemotableViewMethod 8991 public void setVisibility(@Visibility int visibility) { 8992 setFlags(visibility, VISIBILITY_MASK); 8993 } 8994 8995 /** 8996 * Returns the enabled status for this view. The interpretation of the 8997 * enabled state varies by subclass. 8998 * 8999 * @return True if this view is enabled, false otherwise. 9000 */ 9001 @ViewDebug.ExportedProperty 9002 public boolean isEnabled() { 9003 return (mViewFlags & ENABLED_MASK) == ENABLED; 9004 } 9005 9006 /** 9007 * Set the enabled state of this view. The interpretation of the enabled 9008 * state varies by subclass. 9009 * 9010 * @param enabled True if this view is enabled, false otherwise. 9011 */ 9012 @RemotableViewMethod 9013 public void setEnabled(boolean enabled) { 9014 if (enabled == isEnabled()) return; 9015 9016 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 9017 9018 /* 9019 * The View most likely has to change its appearance, so refresh 9020 * the drawable state. 9021 */ 9022 refreshDrawableState(); 9023 9024 // Invalidate too, since the default behavior for views is to be 9025 // be drawn at 50% alpha rather than to change the drawable. 9026 invalidate(true); 9027 9028 if (!enabled) { 9029 cancelPendingInputEvents(); 9030 } 9031 } 9032 9033 /** 9034 * Set whether this view can receive the focus. 9035 * <p> 9036 * Setting this to false will also ensure that this view is not focusable 9037 * in touch mode. 9038 * 9039 * @param focusable If true, this view can receive the focus. 9040 * 9041 * @see #setFocusableInTouchMode(boolean) 9042 * @see #setFocusable(int) 9043 * @attr ref android.R.styleable#View_focusable 9044 */ 9045 public void setFocusable(boolean focusable) { 9046 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 9047 } 9048 9049 /** 9050 * Sets whether this view can receive focus. 9051 * <p> 9052 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 9053 * automatically based on the view's interactivity. This is the default. 9054 * <p> 9055 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 9056 * in touch mode. 9057 * 9058 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 9059 * or {@link #FOCUSABLE_AUTO}. 9060 * @see #setFocusableInTouchMode(boolean) 9061 * @attr ref android.R.styleable#View_focusable 9062 */ 9063 public void setFocusable(@Focusable int focusable) { 9064 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 9065 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 9066 } 9067 setFlags(focusable, FOCUSABLE_MASK); 9068 } 9069 9070 /** 9071 * Set whether this view can receive focus while in touch mode. 9072 * 9073 * Setting this to true will also ensure that this view is focusable. 9074 * 9075 * @param focusableInTouchMode If true, this view can receive the focus while 9076 * in touch mode. 9077 * 9078 * @see #setFocusable(boolean) 9079 * @attr ref android.R.styleable#View_focusableInTouchMode 9080 */ 9081 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 9082 // Focusable in touch mode should always be set before the focusable flag 9083 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 9084 // which, in touch mode, will not successfully request focus on this view 9085 // because the focusable in touch mode flag is not set 9086 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 9087 9088 // Clear FOCUSABLE_AUTO if set. 9089 if (focusableInTouchMode) { 9090 // Clears FOCUSABLE_AUTO if set. 9091 setFlags(FOCUSABLE, FOCUSABLE_MASK); 9092 } 9093 } 9094 9095 /** 9096 * Set autofill mode for the view. 9097 * 9098 * @param autofillMode One of {@link #AUTOFILL_MODE_INHERIT}, {@link #AUTOFILL_MODE_AUTO}, 9099 * or {@link #AUTOFILL_MODE_MANUAL}. 9100 * @attr ref android.R.styleable#View_autofillMode 9101 */ 9102 public void setAutofillMode(@AutofillMode int autofillMode) { 9103 Preconditions.checkArgumentInRange(autofillMode, AUTOFILL_MODE_INHERIT, 9104 AUTOFILL_MODE_MANUAL, "autofillMode"); 9105 9106 mPrivateFlags3 &= ~PFLAG3_AUTOFILL_MODE_MASK; 9107 mPrivateFlags3 |= autofillMode << PFLAG3_AUTOFILL_MODE_SHIFT; 9108 } 9109 9110 /** 9111 * Sets the a hint that helps the autofill service to select the appropriate data to fill the 9112 * view. 9113 * 9114 * @param autofillHint The autofill hint to set. If the array is emtpy, {@code null} is set. 9115 * @attr ref android.R.styleable#View_autofillHint 9116 */ 9117 public void setAutofillHint(@Nullable String... autofillHint) { 9118 if (autofillHint == null || autofillHint.length == 0) { 9119 mAutofillHint = null; 9120 } else { 9121 mAutofillHint = autofillHint; 9122 } 9123 } 9124 9125 /** 9126 * Set whether this view should have sound effects enabled for events such as 9127 * clicking and touching. 9128 * 9129 * <p>You may wish to disable sound effects for a view if you already play sounds, 9130 * for instance, a dial key that plays dtmf tones. 9131 * 9132 * @param soundEffectsEnabled whether sound effects are enabled for this view. 9133 * @see #isSoundEffectsEnabled() 9134 * @see #playSoundEffect(int) 9135 * @attr ref android.R.styleable#View_soundEffectsEnabled 9136 */ 9137 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 9138 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 9139 } 9140 9141 /** 9142 * @return whether this view should have sound effects enabled for events such as 9143 * clicking and touching. 9144 * 9145 * @see #setSoundEffectsEnabled(boolean) 9146 * @see #playSoundEffect(int) 9147 * @attr ref android.R.styleable#View_soundEffectsEnabled 9148 */ 9149 @ViewDebug.ExportedProperty 9150 public boolean isSoundEffectsEnabled() { 9151 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 9152 } 9153 9154 /** 9155 * Set whether this view should have haptic feedback for events such as 9156 * long presses. 9157 * 9158 * <p>You may wish to disable haptic feedback if your view already controls 9159 * its own haptic feedback. 9160 * 9161 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 9162 * @see #isHapticFeedbackEnabled() 9163 * @see #performHapticFeedback(int) 9164 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9165 */ 9166 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 9167 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 9168 } 9169 9170 /** 9171 * @return whether this view should have haptic feedback enabled for events 9172 * long presses. 9173 * 9174 * @see #setHapticFeedbackEnabled(boolean) 9175 * @see #performHapticFeedback(int) 9176 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9177 */ 9178 @ViewDebug.ExportedProperty 9179 public boolean isHapticFeedbackEnabled() { 9180 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 9181 } 9182 9183 /** 9184 * Returns the layout direction for this view. 9185 * 9186 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 9187 * {@link #LAYOUT_DIRECTION_RTL}, 9188 * {@link #LAYOUT_DIRECTION_INHERIT} or 9189 * {@link #LAYOUT_DIRECTION_LOCALE}. 9190 * 9191 * @attr ref android.R.styleable#View_layoutDirection 9192 * 9193 * @hide 9194 */ 9195 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9196 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 9197 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 9198 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 9199 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 9200 }) 9201 @LayoutDir 9202 public int getRawLayoutDirection() { 9203 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 9204 } 9205 9206 /** 9207 * Set the layout direction for this view. This will propagate a reset of layout direction 9208 * resolution to the view's children and resolve layout direction for this view. 9209 * 9210 * @param layoutDirection the layout direction to set. Should be one of: 9211 * 9212 * {@link #LAYOUT_DIRECTION_LTR}, 9213 * {@link #LAYOUT_DIRECTION_RTL}, 9214 * {@link #LAYOUT_DIRECTION_INHERIT}, 9215 * {@link #LAYOUT_DIRECTION_LOCALE}. 9216 * 9217 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 9218 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 9219 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 9220 * 9221 * @attr ref android.R.styleable#View_layoutDirection 9222 */ 9223 @RemotableViewMethod 9224 public void setLayoutDirection(@LayoutDir int layoutDirection) { 9225 if (getRawLayoutDirection() != layoutDirection) { 9226 // Reset the current layout direction and the resolved one 9227 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 9228 resetRtlProperties(); 9229 // Set the new layout direction (filtered) 9230 mPrivateFlags2 |= 9231 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 9232 // We need to resolve all RTL properties as they all depend on layout direction 9233 resolveRtlPropertiesIfNeeded(); 9234 requestLayout(); 9235 invalidate(true); 9236 } 9237 } 9238 9239 /** 9240 * Returns the resolved layout direction for this view. 9241 * 9242 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 9243 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 9244 * 9245 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 9246 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 9247 * 9248 * @attr ref android.R.styleable#View_layoutDirection 9249 */ 9250 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9251 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 9252 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 9253 }) 9254 @ResolvedLayoutDir 9255 public int getLayoutDirection() { 9256 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 9257 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 9258 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 9259 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 9260 } 9261 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 9262 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 9263 } 9264 9265 /** 9266 * Indicates whether or not this view's layout is right-to-left. This is resolved from 9267 * layout attribute and/or the inherited value from the parent 9268 * 9269 * @return true if the layout is right-to-left. 9270 * 9271 * @hide 9272 */ 9273 @ViewDebug.ExportedProperty(category = "layout") 9274 public boolean isLayoutRtl() { 9275 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 9276 } 9277 9278 /** 9279 * Indicates whether the view is currently tracking transient state that the 9280 * app should not need to concern itself with saving and restoring, but that 9281 * the framework should take special note to preserve when possible. 9282 * 9283 * <p>A view with transient state cannot be trivially rebound from an external 9284 * data source, such as an adapter binding item views in a list. This may be 9285 * because the view is performing an animation, tracking user selection 9286 * of content, or similar.</p> 9287 * 9288 * @return true if the view has transient state 9289 */ 9290 @ViewDebug.ExportedProperty(category = "layout") 9291 public boolean hasTransientState() { 9292 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 9293 } 9294 9295 /** 9296 * Set whether this view is currently tracking transient state that the 9297 * framework should attempt to preserve when possible. This flag is reference counted, 9298 * so every call to setHasTransientState(true) should be paired with a later call 9299 * to setHasTransientState(false). 9300 * 9301 * <p>A view with transient state cannot be trivially rebound from an external 9302 * data source, such as an adapter binding item views in a list. This may be 9303 * because the view is performing an animation, tracking user selection 9304 * of content, or similar.</p> 9305 * 9306 * @param hasTransientState true if this view has transient state 9307 */ 9308 public void setHasTransientState(boolean hasTransientState) { 9309 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 9310 mTransientStateCount - 1; 9311 if (mTransientStateCount < 0) { 9312 mTransientStateCount = 0; 9313 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 9314 "unmatched pair of setHasTransientState calls"); 9315 } else if ((hasTransientState && mTransientStateCount == 1) || 9316 (!hasTransientState && mTransientStateCount == 0)) { 9317 // update flag if we've just incremented up from 0 or decremented down to 0 9318 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 9319 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 9320 if (mParent != null) { 9321 try { 9322 mParent.childHasTransientStateChanged(this, hasTransientState); 9323 } catch (AbstractMethodError e) { 9324 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 9325 " does not fully implement ViewParent", e); 9326 } 9327 } 9328 } 9329 } 9330 9331 /** 9332 * Returns true if this view is currently attached to a window. 9333 */ 9334 public boolean isAttachedToWindow() { 9335 return mAttachInfo != null; 9336 } 9337 9338 /** 9339 * Returns true if this view has been through at least one layout since it 9340 * was last attached to or detached from a window. 9341 */ 9342 public boolean isLaidOut() { 9343 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 9344 } 9345 9346 /** 9347 * If this view doesn't do any drawing on its own, set this flag to 9348 * allow further optimizations. By default, this flag is not set on 9349 * View, but could be set on some View subclasses such as ViewGroup. 9350 * 9351 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 9352 * you should clear this flag. 9353 * 9354 * @param willNotDraw whether or not this View draw on its own 9355 */ 9356 public void setWillNotDraw(boolean willNotDraw) { 9357 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 9358 } 9359 9360 /** 9361 * Returns whether or not this View draws on its own. 9362 * 9363 * @return true if this view has nothing to draw, false otherwise 9364 */ 9365 @ViewDebug.ExportedProperty(category = "drawing") 9366 public boolean willNotDraw() { 9367 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 9368 } 9369 9370 /** 9371 * When a View's drawing cache is enabled, drawing is redirected to an 9372 * offscreen bitmap. Some views, like an ImageView, must be able to 9373 * bypass this mechanism if they already draw a single bitmap, to avoid 9374 * unnecessary usage of the memory. 9375 * 9376 * @param willNotCacheDrawing true if this view does not cache its 9377 * drawing, false otherwise 9378 */ 9379 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 9380 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 9381 } 9382 9383 /** 9384 * Returns whether or not this View can cache its drawing or not. 9385 * 9386 * @return true if this view does not cache its drawing, false otherwise 9387 */ 9388 @ViewDebug.ExportedProperty(category = "drawing") 9389 public boolean willNotCacheDrawing() { 9390 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 9391 } 9392 9393 /** 9394 * Indicates whether this view reacts to click events or not. 9395 * 9396 * @return true if the view is clickable, false otherwise 9397 * 9398 * @see #setClickable(boolean) 9399 * @attr ref android.R.styleable#View_clickable 9400 */ 9401 @ViewDebug.ExportedProperty 9402 public boolean isClickable() { 9403 return (mViewFlags & CLICKABLE) == CLICKABLE; 9404 } 9405 9406 /** 9407 * Enables or disables click events for this view. When a view 9408 * is clickable it will change its state to "pressed" on every click. 9409 * Subclasses should set the view clickable to visually react to 9410 * user's clicks. 9411 * 9412 * @param clickable true to make the view clickable, false otherwise 9413 * 9414 * @see #isClickable() 9415 * @attr ref android.R.styleable#View_clickable 9416 */ 9417 public void setClickable(boolean clickable) { 9418 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 9419 } 9420 9421 /** 9422 * Indicates whether this view reacts to long click events or not. 9423 * 9424 * @return true if the view is long clickable, false otherwise 9425 * 9426 * @see #setLongClickable(boolean) 9427 * @attr ref android.R.styleable#View_longClickable 9428 */ 9429 public boolean isLongClickable() { 9430 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 9431 } 9432 9433 /** 9434 * Enables or disables long click events for this view. When a view is long 9435 * clickable it reacts to the user holding down the button for a longer 9436 * duration than a tap. This event can either launch the listener or a 9437 * context menu. 9438 * 9439 * @param longClickable true to make the view long clickable, false otherwise 9440 * @see #isLongClickable() 9441 * @attr ref android.R.styleable#View_longClickable 9442 */ 9443 public void setLongClickable(boolean longClickable) { 9444 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 9445 } 9446 9447 /** 9448 * Indicates whether this view reacts to context clicks or not. 9449 * 9450 * @return true if the view is context clickable, false otherwise 9451 * @see #setContextClickable(boolean) 9452 * @attr ref android.R.styleable#View_contextClickable 9453 */ 9454 public boolean isContextClickable() { 9455 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 9456 } 9457 9458 /** 9459 * Enables or disables context clicking for this view. This event can launch the listener. 9460 * 9461 * @param contextClickable true to make the view react to a context click, false otherwise 9462 * @see #isContextClickable() 9463 * @attr ref android.R.styleable#View_contextClickable 9464 */ 9465 public void setContextClickable(boolean contextClickable) { 9466 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 9467 } 9468 9469 /** 9470 * Sets the pressed state for this view and provides a touch coordinate for 9471 * animation hinting. 9472 * 9473 * @param pressed Pass true to set the View's internal state to "pressed", 9474 * or false to reverts the View's internal state from a 9475 * previously set "pressed" state. 9476 * @param x The x coordinate of the touch that caused the press 9477 * @param y The y coordinate of the touch that caused the press 9478 */ 9479 private void setPressed(boolean pressed, float x, float y) { 9480 if (pressed) { 9481 drawableHotspotChanged(x, y); 9482 } 9483 9484 setPressed(pressed); 9485 } 9486 9487 /** 9488 * Sets the pressed state for this view. 9489 * 9490 * @see #isClickable() 9491 * @see #setClickable(boolean) 9492 * 9493 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 9494 * the View's internal state from a previously set "pressed" state. 9495 */ 9496 public void setPressed(boolean pressed) { 9497 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 9498 9499 if (pressed) { 9500 mPrivateFlags |= PFLAG_PRESSED; 9501 } else { 9502 mPrivateFlags &= ~PFLAG_PRESSED; 9503 } 9504 9505 if (needsRefresh) { 9506 refreshDrawableState(); 9507 } 9508 dispatchSetPressed(pressed); 9509 } 9510 9511 /** 9512 * Dispatch setPressed to all of this View's children. 9513 * 9514 * @see #setPressed(boolean) 9515 * 9516 * @param pressed The new pressed state 9517 */ 9518 protected void dispatchSetPressed(boolean pressed) { 9519 } 9520 9521 /** 9522 * Indicates whether the view is currently in pressed state. Unless 9523 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 9524 * the pressed state. 9525 * 9526 * @see #setPressed(boolean) 9527 * @see #isClickable() 9528 * @see #setClickable(boolean) 9529 * 9530 * @return true if the view is currently pressed, false otherwise 9531 */ 9532 @ViewDebug.ExportedProperty 9533 public boolean isPressed() { 9534 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 9535 } 9536 9537 /** 9538 * @hide 9539 * Indicates whether this view will participate in data collection through 9540 * {@link ViewStructure}. If true, it will not provide any data 9541 * for itself or its children. If false, the normal data collection will be allowed. 9542 * 9543 * @return Returns false if assist data collection is not blocked, else true. 9544 * 9545 * @see #setAssistBlocked(boolean) 9546 * @attr ref android.R.styleable#View_assistBlocked 9547 */ 9548 public boolean isAssistBlocked() { 9549 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 9550 } 9551 9552 /** 9553 * @hide 9554 * Indicates whether this view will participate in data collection through 9555 * {@link ViewStructure} for autofill purposes. 9556 * 9557 * <p>If {@code true}, it will not provide any data for itself or its children. 9558 * <p>If {@code false}, the normal data collection will be allowed. 9559 * 9560 * @return Returns {@code false} if assist data collection for autofill is not blocked, 9561 * else {@code true}. 9562 * 9563 * TODO(b/33197203): update / remove javadoc tags below 9564 * @see #setAssistBlocked(boolean) 9565 * @attr ref android.R.styleable#View_assistBlocked 9566 */ 9567 public boolean isAutofillBlocked() { 9568 return false; // TODO(b/33197203): properly implement it 9569 } 9570 9571 /** 9572 * @hide 9573 * Controls whether assist data collection from this view and its children is enabled 9574 * (that is, whether {@link #onProvideStructure} and 9575 * {@link #onProvideVirtualStructure} will be called). The default value is false, 9576 * allowing normal assist collection. Setting this to false will disable assist collection. 9577 * 9578 * @param enabled Set to true to <em>disable</em> assist data collection, or false 9579 * (the default) to allow it. 9580 * 9581 * @see #isAssistBlocked() 9582 * @see #onProvideStructure 9583 * @see #onProvideVirtualStructure 9584 * @attr ref android.R.styleable#View_assistBlocked 9585 */ 9586 public void setAssistBlocked(boolean enabled) { 9587 if (enabled) { 9588 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 9589 } else { 9590 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 9591 } 9592 } 9593 9594 /** 9595 * Indicates whether this view will save its state (that is, 9596 * whether its {@link #onSaveInstanceState} method will be called). 9597 * 9598 * @return Returns true if the view state saving is enabled, else false. 9599 * 9600 * @see #setSaveEnabled(boolean) 9601 * @attr ref android.R.styleable#View_saveEnabled 9602 */ 9603 public boolean isSaveEnabled() { 9604 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 9605 } 9606 9607 /** 9608 * Controls whether the saving of this view's state is 9609 * enabled (that is, whether its {@link #onSaveInstanceState} method 9610 * will be called). Note that even if freezing is enabled, the 9611 * view still must have an id assigned to it (via {@link #setId(int)}) 9612 * for its state to be saved. This flag can only disable the 9613 * saving of this view; any child views may still have their state saved. 9614 * 9615 * @param enabled Set to false to <em>disable</em> state saving, or true 9616 * (the default) to allow it. 9617 * 9618 * @see #isSaveEnabled() 9619 * @see #setId(int) 9620 * @see #onSaveInstanceState() 9621 * @attr ref android.R.styleable#View_saveEnabled 9622 */ 9623 public void setSaveEnabled(boolean enabled) { 9624 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 9625 } 9626 9627 /** 9628 * Gets whether the framework should discard touches when the view's 9629 * window is obscured by another visible window. 9630 * Refer to the {@link View} security documentation for more details. 9631 * 9632 * @return True if touch filtering is enabled. 9633 * 9634 * @see #setFilterTouchesWhenObscured(boolean) 9635 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9636 */ 9637 @ViewDebug.ExportedProperty 9638 public boolean getFilterTouchesWhenObscured() { 9639 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 9640 } 9641 9642 /** 9643 * Sets whether the framework should discard touches when the view's 9644 * window is obscured by another visible window. 9645 * Refer to the {@link View} security documentation for more details. 9646 * 9647 * @param enabled True if touch filtering should be enabled. 9648 * 9649 * @see #getFilterTouchesWhenObscured 9650 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9651 */ 9652 public void setFilterTouchesWhenObscured(boolean enabled) { 9653 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 9654 FILTER_TOUCHES_WHEN_OBSCURED); 9655 } 9656 9657 /** 9658 * Indicates whether the entire hierarchy under this view will save its 9659 * state when a state saving traversal occurs from its parent. The default 9660 * is true; if false, these views will not be saved unless 9661 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9662 * 9663 * @return Returns true if the view state saving from parent is enabled, else false. 9664 * 9665 * @see #setSaveFromParentEnabled(boolean) 9666 */ 9667 public boolean isSaveFromParentEnabled() { 9668 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 9669 } 9670 9671 /** 9672 * Controls whether the entire hierarchy under this view will save its 9673 * state when a state saving traversal occurs from its parent. The default 9674 * is true; if false, these views will not be saved unless 9675 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9676 * 9677 * @param enabled Set to false to <em>disable</em> state saving, or true 9678 * (the default) to allow it. 9679 * 9680 * @see #isSaveFromParentEnabled() 9681 * @see #setId(int) 9682 * @see #onSaveInstanceState() 9683 */ 9684 public void setSaveFromParentEnabled(boolean enabled) { 9685 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 9686 } 9687 9688 9689 /** 9690 * Returns whether this View is currently able to take focus. 9691 * 9692 * @return True if this view can take focus, or false otherwise. 9693 */ 9694 @ViewDebug.ExportedProperty(category = "focus") 9695 public final boolean isFocusable() { 9696 return FOCUSABLE == (mViewFlags & FOCUSABLE); 9697 } 9698 9699 /** 9700 * Returns the focusable setting for this view. 9701 * 9702 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 9703 * @attr ref android.R.styleable#View_focusable 9704 */ 9705 @ViewDebug.ExportedProperty(mapping = { 9706 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 9707 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 9708 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 9709 }) 9710 @Focusable 9711 public int getFocusable() { 9712 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 9713 } 9714 9715 /** 9716 * When a view is focusable, it may not want to take focus when in touch mode. 9717 * For example, a button would like focus when the user is navigating via a D-pad 9718 * so that the user can click on it, but once the user starts touching the screen, 9719 * the button shouldn't take focus 9720 * @return Whether the view is focusable in touch mode. 9721 * @attr ref android.R.styleable#View_focusableInTouchMode 9722 */ 9723 @ViewDebug.ExportedProperty 9724 public final boolean isFocusableInTouchMode() { 9725 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 9726 } 9727 9728 /** 9729 * Returns the autofill mode for this view. 9730 * 9731 * @return One of {@link #AUTOFILL_MODE_INHERIT}, {@link #AUTOFILL_MODE_AUTO}, or 9732 * {@link #AUTOFILL_MODE_MANUAL}. 9733 * @attr ref android.R.styleable#View_autofillMode 9734 */ 9735 @ViewDebug.ExportedProperty(mapping = { 9736 @ViewDebug.IntToString(from = AUTOFILL_MODE_INHERIT, to = "AUTOFILL_MODE_INHERIT"), 9737 @ViewDebug.IntToString(from = AUTOFILL_MODE_AUTO, to = "AUTOFILL_MODE_AUTO"), 9738 @ViewDebug.IntToString(from = AUTOFILL_MODE_MANUAL, to = "AUTOFILL_MODE_MANUAL") 9739 }) 9740 @AutofillMode 9741 public int getAutofillMode() { 9742 return (mPrivateFlags3 & PFLAG3_AUTOFILL_MODE_MASK) >> PFLAG3_AUTOFILL_MODE_SHIFT; 9743 } 9744 9745 /** 9746 * Returns the resolved autofill mode for this view. 9747 * 9748 * This is the same as {@link #getAutofillMode()} but if the mode is 9749 * {@link #AUTOFILL_MODE_INHERIT} the parents autofill mode will be returned. 9750 * 9751 * @return One of {@link #AUTOFILL_MODE_AUTO}, or {@link #AUTOFILL_MODE_MANUAL}. If the auto- 9752 * fill mode can not be resolved e.g. {@link #getAutofillMode()} is 9753 * {@link #AUTOFILL_MODE_INHERIT} and the {@link View} is detached 9754 * {@link #AUTOFILL_MODE_AUTO} is returned. 9755 */ 9756 public @AutofillMode int getResolvedAutofillMode() { 9757 @AutofillMode int autofillMode = getAutofillMode(); 9758 9759 if (autofillMode == AUTOFILL_MODE_INHERIT) { 9760 if (mParent == null) { 9761 return AUTOFILL_MODE_AUTO; 9762 } else { 9763 return mParent.getResolvedAutofillMode(); 9764 } 9765 } else { 9766 return autofillMode; 9767 } 9768 } 9769 9770 /** 9771 * Find the nearest view in the specified direction that can take focus. 9772 * This does not actually give focus to that view. 9773 * 9774 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9775 * 9776 * @return The nearest focusable in the specified direction, or null if none 9777 * can be found. 9778 */ 9779 public View focusSearch(@FocusRealDirection int direction) { 9780 if (mParent != null) { 9781 return mParent.focusSearch(this, direction); 9782 } else { 9783 return null; 9784 } 9785 } 9786 9787 /** 9788 * Returns whether this View is a root of a keyboard navigation cluster. 9789 * 9790 * @return True if this view is a root of a cluster, or false otherwise. 9791 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9792 */ 9793 @ViewDebug.ExportedProperty(category = "keyboardNavigationCluster") 9794 public final boolean isKeyboardNavigationCluster() { 9795 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 9796 } 9797 9798 /** 9799 * Set whether this view is a root of a keyboard navigation cluster. 9800 * 9801 * @param isCluster If true, this view is a root of a cluster. 9802 * 9803 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9804 */ 9805 public void setKeyboardNavigationCluster(boolean isCluster) { 9806 if (isCluster) { 9807 mPrivateFlags3 |= PFLAG3_CLUSTER; 9808 } else { 9809 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 9810 } 9811 } 9812 9813 /** 9814 * Sets this View as the one which receives focus the next time cluster navigation jumps 9815 * to the cluster containing this View. This does NOT change focus even if the cluster 9816 * containing this view is current. 9817 * 9818 * @hide 9819 */ 9820 public void setFocusedInCluster() { 9821 if (mParent instanceof ViewGroup) { 9822 ((ViewGroup) mParent).setFocusInCluster(this); 9823 } 9824 } 9825 9826 /** 9827 * Returns whether this View should receive focus when the focus is restored for the view 9828 * hierarchy containing this view. 9829 * <p> 9830 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 9831 * window or serves as a target of cluster navigation. 9832 * 9833 * @see #restoreDefaultFocus(int) 9834 * 9835 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 9836 * @attr ref android.R.styleable#View_focusedByDefault 9837 */ 9838 @ViewDebug.ExportedProperty(category = "focusedByDefault") 9839 public final boolean isFocusedByDefault() { 9840 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 9841 } 9842 9843 /** 9844 * Sets whether this View should receive focus when the focus is restored for the view 9845 * hierarchy containing this view. 9846 * <p> 9847 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 9848 * window or serves as a target of cluster navigation. 9849 * 9850 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 9851 * {@code false} otherwise. 9852 * 9853 * @see #restoreDefaultFocus(int) 9854 * 9855 * @attr ref android.R.styleable#View_focusedByDefault 9856 */ 9857 public void setFocusedByDefault(boolean isFocusedByDefault) { 9858 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 9859 return; 9860 } 9861 9862 if (isFocusedByDefault) { 9863 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 9864 } else { 9865 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 9866 } 9867 9868 if (mParent instanceof ViewGroup) { 9869 if (isFocusedByDefault) { 9870 ((ViewGroup) mParent).setDefaultFocus(this); 9871 } else { 9872 ((ViewGroup) mParent).clearDefaultFocus(this); 9873 } 9874 } 9875 } 9876 9877 /** 9878 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 9879 * 9880 * @return {@code true} if this view has default focus, {@code false} otherwise 9881 */ 9882 boolean hasDefaultFocus() { 9883 return isFocusedByDefault(); 9884 } 9885 9886 /** 9887 * Find the nearest keyboard navigation cluster in the specified direction. 9888 * This does not actually give focus to that cluster. 9889 * 9890 * @param currentCluster The starting point of the search. Null means the current cluster is not 9891 * found yet 9892 * @param direction Direction to look 9893 * 9894 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 9895 * can be found 9896 */ 9897 public View keyboardNavigationClusterSearch(View currentCluster, 9898 @FocusDirection int direction) { 9899 if (isKeyboardNavigationCluster()) { 9900 currentCluster = this; 9901 } 9902 if (isRootNamespace()) { 9903 // Root namespace means we should consider ourselves the top of the 9904 // tree for group searching; otherwise we could be group searching 9905 // into other tabs. see LocalActivityManager and TabHost for more info. 9906 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 9907 this, currentCluster, direction); 9908 } else if (mParent != null) { 9909 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 9910 } 9911 return null; 9912 } 9913 9914 /** 9915 * This method is the last chance for the focused view and its ancestors to 9916 * respond to an arrow key. This is called when the focused view did not 9917 * consume the key internally, nor could the view system find a new view in 9918 * the requested direction to give focus to. 9919 * 9920 * @param focused The currently focused view. 9921 * @param direction The direction focus wants to move. One of FOCUS_UP, 9922 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 9923 * @return True if the this view consumed this unhandled move. 9924 */ 9925 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 9926 return false; 9927 } 9928 9929 /** 9930 * If a user manually specified the next view id for a particular direction, 9931 * use the root to look up the view. 9932 * @param root The root view of the hierarchy containing this view. 9933 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 9934 * or FOCUS_BACKWARD. 9935 * @return The user specified next view, or null if there is none. 9936 */ 9937 View findUserSetNextFocus(View root, @FocusDirection int direction) { 9938 switch (direction) { 9939 case FOCUS_LEFT: 9940 if (mNextFocusLeftId == View.NO_ID) return null; 9941 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 9942 case FOCUS_RIGHT: 9943 if (mNextFocusRightId == View.NO_ID) return null; 9944 return findViewInsideOutShouldExist(root, mNextFocusRightId); 9945 case FOCUS_UP: 9946 if (mNextFocusUpId == View.NO_ID) return null; 9947 return findViewInsideOutShouldExist(root, mNextFocusUpId); 9948 case FOCUS_DOWN: 9949 if (mNextFocusDownId == View.NO_ID) return null; 9950 return findViewInsideOutShouldExist(root, mNextFocusDownId); 9951 case FOCUS_FORWARD: 9952 if (mNextFocusForwardId == View.NO_ID) return null; 9953 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 9954 case FOCUS_BACKWARD: { 9955 if (mID == View.NO_ID) return null; 9956 final int id = mID; 9957 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 9958 @Override 9959 public boolean test(View t) { 9960 return t.mNextFocusForwardId == id; 9961 } 9962 }); 9963 } 9964 } 9965 return null; 9966 } 9967 9968 private View findViewInsideOutShouldExist(View root, int id) { 9969 if (mMatchIdPredicate == null) { 9970 mMatchIdPredicate = new MatchIdPredicate(); 9971 } 9972 mMatchIdPredicate.mId = id; 9973 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 9974 if (result == null) { 9975 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 9976 } 9977 return result; 9978 } 9979 9980 /** 9981 * Find and return all focusable views that are descendants of this view, 9982 * possibly including this view if it is focusable itself. 9983 * 9984 * @param direction The direction of the focus 9985 * @return A list of focusable views 9986 */ 9987 public ArrayList<View> getFocusables(@FocusDirection int direction) { 9988 ArrayList<View> result = new ArrayList<View>(24); 9989 addFocusables(result, direction); 9990 return result; 9991 } 9992 9993 /** 9994 * Add any focusable views that are descendants of this view (possibly 9995 * including this view if it is focusable itself) to views. If we are in touch mode, 9996 * only add views that are also focusable in touch mode. 9997 * 9998 * @param views Focusable views found so far 9999 * @param direction The direction of the focus 10000 */ 10001 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 10002 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 10003 } 10004 10005 /** 10006 * Adds any focusable views that are descendants of this view (possibly 10007 * including this view if it is focusable itself) to views. This method 10008 * adds all focusable views regardless if we are in touch mode or 10009 * only views focusable in touch mode if we are in touch mode or 10010 * only views that can take accessibility focus if accessibility is enabled 10011 * depending on the focusable mode parameter. 10012 * 10013 * @param views Focusable views found so far or null if all we are interested is 10014 * the number of focusables. 10015 * @param direction The direction of the focus. 10016 * @param focusableMode The type of focusables to be added. 10017 * 10018 * @see #FOCUSABLES_ALL 10019 * @see #FOCUSABLES_TOUCH_MODE 10020 */ 10021 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 10022 @FocusableMode int focusableMode) { 10023 if (views == null) { 10024 return; 10025 } 10026 if (!isFocusable()) { 10027 return; 10028 } 10029 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 10030 && !isFocusableInTouchMode()) { 10031 return; 10032 } 10033 views.add(this); 10034 } 10035 10036 /** 10037 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 10038 * including this view if it is a cluster root itself) to views. 10039 * 10040 * @param views Keyboard navigation cluster roots found so far 10041 * @param direction Direction to look 10042 */ 10043 public void addKeyboardNavigationClusters( 10044 @NonNull Collection<View> views, 10045 int direction) { 10046 if (!isKeyboardNavigationCluster()) { 10047 return; 10048 } 10049 if (!hasFocusable()) { 10050 return; 10051 } 10052 views.add(this); 10053 } 10054 10055 /** 10056 * Finds the Views that contain given text. The containment is case insensitive. 10057 * The search is performed by either the text that the View renders or the content 10058 * description that describes the view for accessibility purposes and the view does 10059 * not render or both. Clients can specify how the search is to be performed via 10060 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 10061 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 10062 * 10063 * @param outViews The output list of matching Views. 10064 * @param searched The text to match against. 10065 * 10066 * @see #FIND_VIEWS_WITH_TEXT 10067 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 10068 * @see #setContentDescription(CharSequence) 10069 */ 10070 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 10071 @FindViewFlags int flags) { 10072 if (getAccessibilityNodeProvider() != null) { 10073 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 10074 outViews.add(this); 10075 } 10076 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 10077 && (searched != null && searched.length() > 0) 10078 && (mContentDescription != null && mContentDescription.length() > 0)) { 10079 String searchedLowerCase = searched.toString().toLowerCase(); 10080 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 10081 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 10082 outViews.add(this); 10083 } 10084 } 10085 } 10086 10087 /** 10088 * Find and return all touchable views that are descendants of this view, 10089 * possibly including this view if it is touchable itself. 10090 * 10091 * @return A list of touchable views 10092 */ 10093 public ArrayList<View> getTouchables() { 10094 ArrayList<View> result = new ArrayList<View>(); 10095 addTouchables(result); 10096 return result; 10097 } 10098 10099 /** 10100 * Add any touchable views that are descendants of this view (possibly 10101 * including this view if it is touchable itself) to views. 10102 * 10103 * @param views Touchable views found so far 10104 */ 10105 public void addTouchables(ArrayList<View> views) { 10106 final int viewFlags = mViewFlags; 10107 10108 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 10109 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 10110 && (viewFlags & ENABLED_MASK) == ENABLED) { 10111 views.add(this); 10112 } 10113 } 10114 10115 /** 10116 * Returns whether this View is accessibility focused. 10117 * 10118 * @return True if this View is accessibility focused. 10119 */ 10120 public boolean isAccessibilityFocused() { 10121 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 10122 } 10123 10124 /** 10125 * Call this to try to give accessibility focus to this view. 10126 * 10127 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 10128 * returns false or the view is no visible or the view already has accessibility 10129 * focus. 10130 * 10131 * See also {@link #focusSearch(int)}, which is what you call to say that you 10132 * have focus, and you want your parent to look for the next one. 10133 * 10134 * @return Whether this view actually took accessibility focus. 10135 * 10136 * @hide 10137 */ 10138 public boolean requestAccessibilityFocus() { 10139 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 10140 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 10141 return false; 10142 } 10143 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10144 return false; 10145 } 10146 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 10147 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 10148 ViewRootImpl viewRootImpl = getViewRootImpl(); 10149 if (viewRootImpl != null) { 10150 viewRootImpl.setAccessibilityFocus(this, null); 10151 } 10152 invalidate(); 10153 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 10154 return true; 10155 } 10156 return false; 10157 } 10158 10159 /** 10160 * Call this to try to clear accessibility focus of this view. 10161 * 10162 * See also {@link #focusSearch(int)}, which is what you call to say that you 10163 * have focus, and you want your parent to look for the next one. 10164 * 10165 * @hide 10166 */ 10167 public void clearAccessibilityFocus() { 10168 clearAccessibilityFocusNoCallbacks(0); 10169 10170 // Clear the global reference of accessibility focus if this view or 10171 // any of its descendants had accessibility focus. This will NOT send 10172 // an event or update internal state if focus is cleared from a 10173 // descendant view, which may leave views in inconsistent states. 10174 final ViewRootImpl viewRootImpl = getViewRootImpl(); 10175 if (viewRootImpl != null) { 10176 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 10177 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 10178 viewRootImpl.setAccessibilityFocus(null, null); 10179 } 10180 } 10181 } 10182 10183 private void sendAccessibilityHoverEvent(int eventType) { 10184 // Since we are not delivering to a client accessibility events from not 10185 // important views (unless the clinet request that) we need to fire the 10186 // event from the deepest view exposed to the client. As a consequence if 10187 // the user crosses a not exposed view the client will see enter and exit 10188 // of the exposed predecessor followed by and enter and exit of that same 10189 // predecessor when entering and exiting the not exposed descendant. This 10190 // is fine since the client has a clear idea which view is hovered at the 10191 // price of a couple more events being sent. This is a simple and 10192 // working solution. 10193 View source = this; 10194 while (true) { 10195 if (source.includeForAccessibility()) { 10196 source.sendAccessibilityEvent(eventType); 10197 return; 10198 } 10199 ViewParent parent = source.getParent(); 10200 if (parent instanceof View) { 10201 source = (View) parent; 10202 } else { 10203 return; 10204 } 10205 } 10206 } 10207 10208 /** 10209 * Clears accessibility focus without calling any callback methods 10210 * normally invoked in {@link #clearAccessibilityFocus()}. This method 10211 * is used separately from that one for clearing accessibility focus when 10212 * giving this focus to another view. 10213 * 10214 * @param action The action, if any, that led to focus being cleared. Set to 10215 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 10216 * the window. 10217 */ 10218 void clearAccessibilityFocusNoCallbacks(int action) { 10219 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 10220 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 10221 invalidate(); 10222 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 10223 AccessibilityEvent event = AccessibilityEvent.obtain( 10224 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 10225 event.setAction(action); 10226 if (mAccessibilityDelegate != null) { 10227 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 10228 } else { 10229 sendAccessibilityEventUnchecked(event); 10230 } 10231 } 10232 } 10233 } 10234 10235 /** 10236 * Call this to try to give focus to a specific view or to one of its 10237 * descendants. 10238 * 10239 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10240 * false), or if it is focusable and it is not focusable in touch mode 10241 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10242 * 10243 * See also {@link #focusSearch(int)}, which is what you call to say that you 10244 * have focus, and you want your parent to look for the next one. 10245 * 10246 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 10247 * {@link #FOCUS_DOWN} and <code>null</code>. 10248 * 10249 * @return Whether this view or one of its descendants actually took focus. 10250 */ 10251 public final boolean requestFocus() { 10252 return requestFocus(View.FOCUS_DOWN); 10253 } 10254 10255 /** 10256 * This will request focus for whichever View was last focused within this 10257 * cluster before a focus-jump out of it. 10258 * 10259 * @hide 10260 */ 10261 @TestApi 10262 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 10263 // Prioritize focusableByDefault over algorithmic focus selection. 10264 if (restoreDefaultFocus()) { 10265 return true; 10266 } 10267 return requestFocus(direction); 10268 } 10269 10270 /** 10271 * This will request focus for whichever View not in a cluster was last focused before a 10272 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 10273 * the "first" focusable view it finds. 10274 * 10275 * @hide 10276 */ 10277 @TestApi 10278 public boolean restoreFocusNotInCluster() { 10279 return requestFocus(View.FOCUS_DOWN); 10280 } 10281 10282 /** 10283 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 10284 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 10285 * 10286 * @return Whether this view or one of its descendants actually took focus 10287 */ 10288 public boolean restoreDefaultFocus() { 10289 return requestFocus(View.FOCUS_DOWN); 10290 } 10291 10292 /** 10293 * Call this to try to give focus to a specific view or to one of its 10294 * descendants and give it a hint about what direction focus is heading. 10295 * 10296 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10297 * false), or if it is focusable and it is not focusable in touch mode 10298 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10299 * 10300 * See also {@link #focusSearch(int)}, which is what you call to say that you 10301 * have focus, and you want your parent to look for the next one. 10302 * 10303 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 10304 * <code>null</code> set for the previously focused rectangle. 10305 * 10306 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10307 * @return Whether this view or one of its descendants actually took focus. 10308 */ 10309 public final boolean requestFocus(int direction) { 10310 return requestFocus(direction, null); 10311 } 10312 10313 /** 10314 * Call this to try to give focus to a specific view or to one of its descendants 10315 * and give it hints about the direction and a specific rectangle that the focus 10316 * is coming from. The rectangle can help give larger views a finer grained hint 10317 * about where focus is coming from, and therefore, where to show selection, or 10318 * forward focus change internally. 10319 * 10320 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10321 * false), or if it is focusable and it is not focusable in touch mode 10322 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10323 * 10324 * A View will not take focus if it is not visible. 10325 * 10326 * A View will not take focus if one of its parents has 10327 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 10328 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 10329 * 10330 * See also {@link #focusSearch(int)}, which is what you call to say that you 10331 * have focus, and you want your parent to look for the next one. 10332 * 10333 * You may wish to override this method if your custom {@link View} has an internal 10334 * {@link View} that it wishes to forward the request to. 10335 * 10336 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10337 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 10338 * to give a finer grained hint about where focus is coming from. May be null 10339 * if there is no hint. 10340 * @return Whether this view or one of its descendants actually took focus. 10341 */ 10342 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 10343 return requestFocusNoSearch(direction, previouslyFocusedRect); 10344 } 10345 10346 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 10347 // need to be focusable 10348 if ((mViewFlags & FOCUSABLE) != FOCUSABLE 10349 || (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10350 return false; 10351 } 10352 10353 // need to be focusable in touch mode if in touch mode 10354 if (isInTouchMode() && 10355 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 10356 return false; 10357 } 10358 10359 // need to not have any parents blocking us 10360 if (hasAncestorThatBlocksDescendantFocus()) { 10361 return false; 10362 } 10363 10364 handleFocusGainInternal(direction, previouslyFocusedRect); 10365 return true; 10366 } 10367 10368 /** 10369 * Call this to try to give focus to a specific view or to one of its descendants. This is a 10370 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 10371 * touch mode to request focus when they are touched. 10372 * 10373 * @return Whether this view or one of its descendants actually took focus. 10374 * 10375 * @see #isInTouchMode() 10376 * 10377 */ 10378 public final boolean requestFocusFromTouch() { 10379 // Leave touch mode if we need to 10380 if (isInTouchMode()) { 10381 ViewRootImpl viewRoot = getViewRootImpl(); 10382 if (viewRoot != null) { 10383 viewRoot.ensureTouchMode(false); 10384 } 10385 } 10386 return requestFocus(View.FOCUS_DOWN); 10387 } 10388 10389 /** 10390 * @return Whether any ancestor of this view blocks descendant focus. 10391 */ 10392 private boolean hasAncestorThatBlocksDescendantFocus() { 10393 final boolean focusableInTouchMode = isFocusableInTouchMode(); 10394 ViewParent ancestor = mParent; 10395 while (ancestor instanceof ViewGroup) { 10396 final ViewGroup vgAncestor = (ViewGroup) ancestor; 10397 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 10398 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 10399 return true; 10400 } else { 10401 ancestor = vgAncestor.getParent(); 10402 } 10403 } 10404 return false; 10405 } 10406 10407 /** 10408 * Gets the mode for determining whether this View is important for accessibility. 10409 * A view is important for accessibility if it fires accessibility events and if it 10410 * is reported to accessibility services that query the screen. 10411 * 10412 * @return The mode for determining whether a view is important for accessibility, one 10413 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 10414 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 10415 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 10416 * 10417 * @attr ref android.R.styleable#View_importantForAccessibility 10418 * 10419 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10420 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10421 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10422 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10423 */ 10424 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 10425 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 10426 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 10427 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 10428 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 10429 to = "noHideDescendants") 10430 }) 10431 public int getImportantForAccessibility() { 10432 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 10433 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 10434 } 10435 10436 /** 10437 * Sets the live region mode for this view. This indicates to accessibility 10438 * services whether they should automatically notify the user about changes 10439 * to the view's content description or text, or to the content descriptions 10440 * or text of the view's children (where applicable). 10441 * <p> 10442 * For example, in a login screen with a TextView that displays an "incorrect 10443 * password" notification, that view should be marked as a live region with 10444 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10445 * <p> 10446 * To disable change notifications for this view, use 10447 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 10448 * mode for most views. 10449 * <p> 10450 * To indicate that the user should be notified of changes, use 10451 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10452 * <p> 10453 * If the view's changes should interrupt ongoing speech and notify the user 10454 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 10455 * 10456 * @param mode The live region mode for this view, one of: 10457 * <ul> 10458 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 10459 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 10460 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 10461 * </ul> 10462 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10463 */ 10464 public void setAccessibilityLiveRegion(int mode) { 10465 if (mode != getAccessibilityLiveRegion()) { 10466 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10467 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 10468 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10469 notifyViewAccessibilityStateChangedIfNeeded( 10470 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10471 } 10472 } 10473 10474 /** 10475 * Gets the live region mode for this View. 10476 * 10477 * @return The live region mode for the view. 10478 * 10479 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10480 * 10481 * @see #setAccessibilityLiveRegion(int) 10482 */ 10483 public int getAccessibilityLiveRegion() { 10484 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 10485 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 10486 } 10487 10488 /** 10489 * Sets how to determine whether this view is important for accessibility 10490 * which is if it fires accessibility events and if it is reported to 10491 * accessibility services that query the screen. 10492 * 10493 * @param mode How to determine whether this view is important for accessibility. 10494 * 10495 * @attr ref android.R.styleable#View_importantForAccessibility 10496 * 10497 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10498 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10499 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10500 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10501 */ 10502 public void setImportantForAccessibility(int mode) { 10503 final int oldMode = getImportantForAccessibility(); 10504 if (mode != oldMode) { 10505 final boolean hideDescendants = 10506 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 10507 10508 // If this node or its descendants are no longer important, try to 10509 // clear accessibility focus. 10510 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 10511 final View focusHost = findAccessibilityFocusHost(hideDescendants); 10512 if (focusHost != null) { 10513 focusHost.clearAccessibilityFocus(); 10514 } 10515 } 10516 10517 // If we're moving between AUTO and another state, we might not need 10518 // to send a subtree changed notification. We'll store the computed 10519 // importance, since we'll need to check it later to make sure. 10520 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 10521 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 10522 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 10523 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 10524 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 10525 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 10526 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 10527 notifySubtreeAccessibilityStateChangedIfNeeded(); 10528 } else { 10529 notifyViewAccessibilityStateChangedIfNeeded( 10530 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10531 } 10532 } 10533 } 10534 10535 /** 10536 * Returns the view within this view's hierarchy that is hosting 10537 * accessibility focus. 10538 * 10539 * @param searchDescendants whether to search for focus in descendant views 10540 * @return the view hosting accessibility focus, or {@code null} 10541 */ 10542 private View findAccessibilityFocusHost(boolean searchDescendants) { 10543 if (isAccessibilityFocusedViewOrHost()) { 10544 return this; 10545 } 10546 10547 if (searchDescendants) { 10548 final ViewRootImpl viewRoot = getViewRootImpl(); 10549 if (viewRoot != null) { 10550 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 10551 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 10552 return focusHost; 10553 } 10554 } 10555 } 10556 10557 return null; 10558 } 10559 10560 /** 10561 * Computes whether this view should be exposed for accessibility. In 10562 * general, views that are interactive or provide information are exposed 10563 * while views that serve only as containers are hidden. 10564 * <p> 10565 * If an ancestor of this view has importance 10566 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 10567 * returns <code>false</code>. 10568 * <p> 10569 * Otherwise, the value is computed according to the view's 10570 * {@link #getImportantForAccessibility()} value: 10571 * <ol> 10572 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 10573 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 10574 * </code> 10575 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 10576 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 10577 * view satisfies any of the following: 10578 * <ul> 10579 * <li>Is actionable, e.g. {@link #isClickable()}, 10580 * {@link #isLongClickable()}, or {@link #isFocusable()} 10581 * <li>Has an {@link AccessibilityDelegate} 10582 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 10583 * {@link OnKeyListener}, etc. 10584 * <li>Is an accessibility live region, e.g. 10585 * {@link #getAccessibilityLiveRegion()} is not 10586 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 10587 * </ul> 10588 * </ol> 10589 * 10590 * @return Whether the view is exposed for accessibility. 10591 * @see #setImportantForAccessibility(int) 10592 * @see #getImportantForAccessibility() 10593 */ 10594 public boolean isImportantForAccessibility() { 10595 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 10596 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 10597 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 10598 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 10599 return false; 10600 } 10601 10602 // Check parent mode to ensure we're not hidden. 10603 ViewParent parent = mParent; 10604 while (parent instanceof View) { 10605 if (((View) parent).getImportantForAccessibility() 10606 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 10607 return false; 10608 } 10609 parent = parent.getParent(); 10610 } 10611 10612 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 10613 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 10614 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 10615 } 10616 10617 /** 10618 * Gets the parent for accessibility purposes. Note that the parent for 10619 * accessibility is not necessary the immediate parent. It is the first 10620 * predecessor that is important for accessibility. 10621 * 10622 * @return The parent for accessibility purposes. 10623 */ 10624 public ViewParent getParentForAccessibility() { 10625 if (mParent instanceof View) { 10626 View parentView = (View) mParent; 10627 if (parentView.includeForAccessibility()) { 10628 return mParent; 10629 } else { 10630 return mParent.getParentForAccessibility(); 10631 } 10632 } 10633 return null; 10634 } 10635 10636 /** 10637 * Adds the children of this View relevant for accessibility to the given list 10638 * as output. Since some Views are not important for accessibility the added 10639 * child views are not necessarily direct children of this view, rather they are 10640 * the first level of descendants important for accessibility. 10641 * 10642 * @param outChildren The output list that will receive children for accessibility. 10643 */ 10644 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 10645 10646 } 10647 10648 /** 10649 * Whether to regard this view for accessibility. A view is regarded for 10650 * accessibility if it is important for accessibility or the querying 10651 * accessibility service has explicitly requested that view not 10652 * important for accessibility are regarded. 10653 * 10654 * @return Whether to regard the view for accessibility. 10655 * 10656 * @hide 10657 */ 10658 public boolean includeForAccessibility() { 10659 if (mAttachInfo != null) { 10660 return (mAttachInfo.mAccessibilityFetchFlags 10661 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 10662 || isImportantForAccessibility(); 10663 } 10664 return false; 10665 } 10666 10667 /** 10668 * Returns whether the View is considered actionable from 10669 * accessibility perspective. Such view are important for 10670 * accessibility. 10671 * 10672 * @return True if the view is actionable for accessibility. 10673 * 10674 * @hide 10675 */ 10676 public boolean isActionableForAccessibility() { 10677 return (isClickable() || isLongClickable() || isFocusable()); 10678 } 10679 10680 /** 10681 * Returns whether the View has registered callbacks which makes it 10682 * important for accessibility. 10683 * 10684 * @return True if the view is actionable for accessibility. 10685 */ 10686 private boolean hasListenersForAccessibility() { 10687 ListenerInfo info = getListenerInfo(); 10688 return mTouchDelegate != null || info.mOnKeyListener != null 10689 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 10690 || info.mOnHoverListener != null || info.mOnDragListener != null; 10691 } 10692 10693 /** 10694 * Notifies that the accessibility state of this view changed. The change 10695 * is local to this view and does not represent structural changes such 10696 * as children and parent. For example, the view became focusable. The 10697 * notification is at at most once every 10698 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 10699 * to avoid unnecessary load to the system. Also once a view has a pending 10700 * notification this method is a NOP until the notification has been sent. 10701 * 10702 * @hide 10703 */ 10704 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 10705 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 10706 return; 10707 } 10708 if (mSendViewStateChangedAccessibilityEvent == null) { 10709 mSendViewStateChangedAccessibilityEvent = 10710 new SendViewStateChangedAccessibilityEvent(); 10711 } 10712 mSendViewStateChangedAccessibilityEvent.runOrPost(changeType); 10713 } 10714 10715 /** 10716 * Notifies that the accessibility state of this view changed. The change 10717 * is *not* local to this view and does represent structural changes such 10718 * as children and parent. For example, the view size changed. The 10719 * notification is at at most once every 10720 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 10721 * to avoid unnecessary load to the system. Also once a view has a pending 10722 * notification this method is a NOP until the notification has been sent. 10723 * 10724 * @hide 10725 */ 10726 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 10727 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 10728 return; 10729 } 10730 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 10731 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 10732 if (mParent != null) { 10733 try { 10734 mParent.notifySubtreeAccessibilityStateChanged( 10735 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 10736 } catch (AbstractMethodError e) { 10737 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 10738 " does not fully implement ViewParent", e); 10739 } 10740 } 10741 } 10742 } 10743 10744 /** 10745 * Change the visibility of the View without triggering any other changes. This is 10746 * important for transitions, where visibility changes should not adjust focus or 10747 * trigger a new layout. This is only used when the visibility has already been changed 10748 * and we need a transient value during an animation. When the animation completes, 10749 * the original visibility value is always restored. 10750 * 10751 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 10752 * @hide 10753 */ 10754 public void setTransitionVisibility(@Visibility int visibility) { 10755 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 10756 } 10757 10758 /** 10759 * Reset the flag indicating the accessibility state of the subtree rooted 10760 * at this view changed. 10761 */ 10762 void resetSubtreeAccessibilityStateChanged() { 10763 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 10764 } 10765 10766 /** 10767 * Report an accessibility action to this view's parents for delegated processing. 10768 * 10769 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 10770 * call this method to delegate an accessibility action to a supporting parent. If the parent 10771 * returns true from its 10772 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 10773 * method this method will return true to signify that the action was consumed.</p> 10774 * 10775 * <p>This method is useful for implementing nested scrolling child views. If 10776 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 10777 * a custom view implementation may invoke this method to allow a parent to consume the 10778 * scroll first. If this method returns true the custom view should skip its own scrolling 10779 * behavior.</p> 10780 * 10781 * @param action Accessibility action to delegate 10782 * @param arguments Optional action arguments 10783 * @return true if the action was consumed by a parent 10784 */ 10785 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 10786 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 10787 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 10788 return true; 10789 } 10790 } 10791 return false; 10792 } 10793 10794 /** 10795 * Performs the specified accessibility action on the view. For 10796 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 10797 * <p> 10798 * If an {@link AccessibilityDelegate} has been specified via calling 10799 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10800 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 10801 * is responsible for handling this call. 10802 * </p> 10803 * 10804 * <p>The default implementation will delegate 10805 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 10806 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 10807 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 10808 * 10809 * @param action The action to perform. 10810 * @param arguments Optional action arguments. 10811 * @return Whether the action was performed. 10812 */ 10813 public boolean performAccessibilityAction(int action, Bundle arguments) { 10814 if (mAccessibilityDelegate != null) { 10815 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 10816 } else { 10817 return performAccessibilityActionInternal(action, arguments); 10818 } 10819 } 10820 10821 /** 10822 * @see #performAccessibilityAction(int, Bundle) 10823 * 10824 * Note: Called from the default {@link AccessibilityDelegate}. 10825 * 10826 * @hide 10827 */ 10828 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 10829 if (isNestedScrollingEnabled() 10830 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 10831 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 10832 || action == R.id.accessibilityActionScrollUp 10833 || action == R.id.accessibilityActionScrollLeft 10834 || action == R.id.accessibilityActionScrollDown 10835 || action == R.id.accessibilityActionScrollRight)) { 10836 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 10837 return true; 10838 } 10839 } 10840 10841 switch (action) { 10842 case AccessibilityNodeInfo.ACTION_CLICK: { 10843 if (isClickable()) { 10844 performClick(); 10845 return true; 10846 } 10847 } break; 10848 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 10849 if (isLongClickable()) { 10850 performLongClick(); 10851 return true; 10852 } 10853 } break; 10854 case AccessibilityNodeInfo.ACTION_FOCUS: { 10855 if (!hasFocus()) { 10856 // Get out of touch mode since accessibility 10857 // wants to move focus around. 10858 getViewRootImpl().ensureTouchMode(false); 10859 return requestFocus(); 10860 } 10861 } break; 10862 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 10863 if (hasFocus()) { 10864 clearFocus(); 10865 return !isFocused(); 10866 } 10867 } break; 10868 case AccessibilityNodeInfo.ACTION_SELECT: { 10869 if (!isSelected()) { 10870 setSelected(true); 10871 return isSelected(); 10872 } 10873 } break; 10874 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 10875 if (isSelected()) { 10876 setSelected(false); 10877 return !isSelected(); 10878 } 10879 } break; 10880 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 10881 if (!isAccessibilityFocused()) { 10882 return requestAccessibilityFocus(); 10883 } 10884 } break; 10885 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 10886 if (isAccessibilityFocused()) { 10887 clearAccessibilityFocus(); 10888 return true; 10889 } 10890 } break; 10891 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 10892 if (arguments != null) { 10893 final int granularity = arguments.getInt( 10894 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10895 final boolean extendSelection = arguments.getBoolean( 10896 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10897 return traverseAtGranularity(granularity, true, extendSelection); 10898 } 10899 } break; 10900 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 10901 if (arguments != null) { 10902 final int granularity = arguments.getInt( 10903 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10904 final boolean extendSelection = arguments.getBoolean( 10905 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10906 return traverseAtGranularity(granularity, false, extendSelection); 10907 } 10908 } break; 10909 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 10910 CharSequence text = getIterableTextForAccessibility(); 10911 if (text == null) { 10912 return false; 10913 } 10914 final int start = (arguments != null) ? arguments.getInt( 10915 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 10916 final int end = (arguments != null) ? arguments.getInt( 10917 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 10918 // Only cursor position can be specified (selection length == 0) 10919 if ((getAccessibilitySelectionStart() != start 10920 || getAccessibilitySelectionEnd() != end) 10921 && (start == end)) { 10922 setAccessibilitySelection(start, end); 10923 notifyViewAccessibilityStateChangedIfNeeded( 10924 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10925 return true; 10926 } 10927 } break; 10928 case R.id.accessibilityActionShowOnScreen: { 10929 if (mAttachInfo != null) { 10930 final Rect r = mAttachInfo.mTmpInvalRect; 10931 getDrawingRect(r); 10932 return requestRectangleOnScreen(r, true); 10933 } 10934 } break; 10935 case R.id.accessibilityActionContextClick: { 10936 if (isContextClickable()) { 10937 performContextClick(); 10938 return true; 10939 } 10940 } break; 10941 } 10942 return false; 10943 } 10944 10945 private boolean traverseAtGranularity(int granularity, boolean forward, 10946 boolean extendSelection) { 10947 CharSequence text = getIterableTextForAccessibility(); 10948 if (text == null || text.length() == 0) { 10949 return false; 10950 } 10951 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 10952 if (iterator == null) { 10953 return false; 10954 } 10955 int current = getAccessibilitySelectionEnd(); 10956 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10957 current = forward ? 0 : text.length(); 10958 } 10959 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 10960 if (range == null) { 10961 return false; 10962 } 10963 final int segmentStart = range[0]; 10964 final int segmentEnd = range[1]; 10965 int selectionStart; 10966 int selectionEnd; 10967 if (extendSelection && isAccessibilitySelectionExtendable()) { 10968 selectionStart = getAccessibilitySelectionStart(); 10969 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10970 selectionStart = forward ? segmentStart : segmentEnd; 10971 } 10972 selectionEnd = forward ? segmentEnd : segmentStart; 10973 } else { 10974 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 10975 } 10976 setAccessibilitySelection(selectionStart, selectionEnd); 10977 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 10978 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 10979 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 10980 return true; 10981 } 10982 10983 /** 10984 * Gets the text reported for accessibility purposes. 10985 * 10986 * @return The accessibility text. 10987 * 10988 * @hide 10989 */ 10990 public CharSequence getIterableTextForAccessibility() { 10991 return getContentDescription(); 10992 } 10993 10994 /** 10995 * Gets whether accessibility selection can be extended. 10996 * 10997 * @return If selection is extensible. 10998 * 10999 * @hide 11000 */ 11001 public boolean isAccessibilitySelectionExtendable() { 11002 return false; 11003 } 11004 11005 /** 11006 * @hide 11007 */ 11008 public int getAccessibilitySelectionStart() { 11009 return mAccessibilityCursorPosition; 11010 } 11011 11012 /** 11013 * @hide 11014 */ 11015 public int getAccessibilitySelectionEnd() { 11016 return getAccessibilitySelectionStart(); 11017 } 11018 11019 /** 11020 * @hide 11021 */ 11022 public void setAccessibilitySelection(int start, int end) { 11023 if (start == end && end == mAccessibilityCursorPosition) { 11024 return; 11025 } 11026 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 11027 mAccessibilityCursorPosition = start; 11028 } else { 11029 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 11030 } 11031 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 11032 } 11033 11034 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 11035 int fromIndex, int toIndex) { 11036 if (mParent == null) { 11037 return; 11038 } 11039 AccessibilityEvent event = AccessibilityEvent.obtain( 11040 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 11041 onInitializeAccessibilityEvent(event); 11042 onPopulateAccessibilityEvent(event); 11043 event.setFromIndex(fromIndex); 11044 event.setToIndex(toIndex); 11045 event.setAction(action); 11046 event.setMovementGranularity(granularity); 11047 mParent.requestSendAccessibilityEvent(this, event); 11048 } 11049 11050 /** 11051 * @hide 11052 */ 11053 public TextSegmentIterator getIteratorForGranularity(int granularity) { 11054 switch (granularity) { 11055 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 11056 CharSequence text = getIterableTextForAccessibility(); 11057 if (text != null && text.length() > 0) { 11058 CharacterTextSegmentIterator iterator = 11059 CharacterTextSegmentIterator.getInstance( 11060 mContext.getResources().getConfiguration().locale); 11061 iterator.initialize(text.toString()); 11062 return iterator; 11063 } 11064 } break; 11065 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 11066 CharSequence text = getIterableTextForAccessibility(); 11067 if (text != null && text.length() > 0) { 11068 WordTextSegmentIterator iterator = 11069 WordTextSegmentIterator.getInstance( 11070 mContext.getResources().getConfiguration().locale); 11071 iterator.initialize(text.toString()); 11072 return iterator; 11073 } 11074 } break; 11075 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 11076 CharSequence text = getIterableTextForAccessibility(); 11077 if (text != null && text.length() > 0) { 11078 ParagraphTextSegmentIterator iterator = 11079 ParagraphTextSegmentIterator.getInstance(); 11080 iterator.initialize(text.toString()); 11081 return iterator; 11082 } 11083 } break; 11084 } 11085 return null; 11086 } 11087 11088 /** 11089 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 11090 * and {@link #onFinishTemporaryDetach()}. 11091 * 11092 * <p>This method always returns {@code true} when called directly or indirectly from 11093 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 11094 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 11095 * <ul> 11096 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 11097 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 11098 * </ul> 11099 * </p> 11100 * 11101 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 11102 * and {@link #onFinishTemporaryDetach()}. 11103 */ 11104 public final boolean isTemporarilyDetached() { 11105 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 11106 } 11107 11108 /** 11109 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 11110 * a container View. 11111 */ 11112 @CallSuper 11113 public void dispatchStartTemporaryDetach() { 11114 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 11115 notifyEnterOrExitForAutoFillIfNeeded(false); 11116 onStartTemporaryDetach(); 11117 } 11118 11119 /** 11120 * This is called when a container is going to temporarily detach a child, with 11121 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 11122 * It will either be followed by {@link #onFinishTemporaryDetach()} or 11123 * {@link #onDetachedFromWindow()} when the container is done. 11124 */ 11125 public void onStartTemporaryDetach() { 11126 removeUnsetPressCallback(); 11127 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 11128 } 11129 11130 /** 11131 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 11132 * a container View. 11133 */ 11134 @CallSuper 11135 public void dispatchFinishTemporaryDetach() { 11136 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 11137 onFinishTemporaryDetach(); 11138 if (hasWindowFocus() && hasFocus()) { 11139 InputMethodManager.getInstance().focusIn(this); 11140 } 11141 notifyEnterOrExitForAutoFillIfNeeded(true); 11142 } 11143 11144 /** 11145 * Called after {@link #onStartTemporaryDetach} when the container is done 11146 * changing the view. 11147 */ 11148 public void onFinishTemporaryDetach() { 11149 } 11150 11151 /** 11152 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 11153 * for this view's window. Returns null if the view is not currently attached 11154 * to the window. Normally you will not need to use this directly, but 11155 * just use the standard high-level event callbacks like 11156 * {@link #onKeyDown(int, KeyEvent)}. 11157 */ 11158 public KeyEvent.DispatcherState getKeyDispatcherState() { 11159 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 11160 } 11161 11162 /** 11163 * Dispatch a key event before it is processed by any input method 11164 * associated with the view hierarchy. This can be used to intercept 11165 * key events in special situations before the IME consumes them; a 11166 * typical example would be handling the BACK key to update the application's 11167 * UI instead of allowing the IME to see it and close itself. 11168 * 11169 * @param event The key event to be dispatched. 11170 * @return True if the event was handled, false otherwise. 11171 */ 11172 public boolean dispatchKeyEventPreIme(KeyEvent event) { 11173 return onKeyPreIme(event.getKeyCode(), event); 11174 } 11175 11176 /** 11177 * Dispatch a key event to the next view on the focus path. This path runs 11178 * from the top of the view tree down to the currently focused view. If this 11179 * view has focus, it will dispatch to itself. Otherwise it will dispatch 11180 * the next node down the focus path. This method also fires any key 11181 * listeners. 11182 * 11183 * @param event The key event to be dispatched. 11184 * @return True if the event was handled, false otherwise. 11185 */ 11186 public boolean dispatchKeyEvent(KeyEvent event) { 11187 if (mInputEventConsistencyVerifier != null) { 11188 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 11189 } 11190 11191 // Give any attached key listener a first crack at the event. 11192 //noinspection SimplifiableIfStatement 11193 ListenerInfo li = mListenerInfo; 11194 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 11195 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 11196 return true; 11197 } 11198 11199 if (event.dispatch(this, mAttachInfo != null 11200 ? mAttachInfo.mKeyDispatchState : null, this)) { 11201 return true; 11202 } 11203 11204 if (mInputEventConsistencyVerifier != null) { 11205 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11206 } 11207 return false; 11208 } 11209 11210 /** 11211 * Dispatches a key shortcut event. 11212 * 11213 * @param event The key event to be dispatched. 11214 * @return True if the event was handled by the view, false otherwise. 11215 */ 11216 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 11217 return onKeyShortcut(event.getKeyCode(), event); 11218 } 11219 11220 /** 11221 * Pass the touch screen motion event down to the target view, or this 11222 * view if it is the target. 11223 * 11224 * @param event The motion event to be dispatched. 11225 * @return True if the event was handled by the view, false otherwise. 11226 */ 11227 public boolean dispatchTouchEvent(MotionEvent event) { 11228 // If the event should be handled by accessibility focus first. 11229 if (event.isTargetAccessibilityFocus()) { 11230 // We don't have focus or no virtual descendant has it, do not handle the event. 11231 if (!isAccessibilityFocusedViewOrHost()) { 11232 return false; 11233 } 11234 // We have focus and got the event, then use normal event dispatch. 11235 event.setTargetAccessibilityFocus(false); 11236 } 11237 11238 boolean result = false; 11239 11240 if (mInputEventConsistencyVerifier != null) { 11241 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 11242 } 11243 11244 final int actionMasked = event.getActionMasked(); 11245 if (actionMasked == MotionEvent.ACTION_DOWN) { 11246 // Defensive cleanup for new gesture 11247 stopNestedScroll(); 11248 } 11249 11250 if (onFilterTouchEventForSecurity(event)) { 11251 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 11252 result = true; 11253 } 11254 //noinspection SimplifiableIfStatement 11255 ListenerInfo li = mListenerInfo; 11256 if (li != null && li.mOnTouchListener != null 11257 && (mViewFlags & ENABLED_MASK) == ENABLED 11258 && li.mOnTouchListener.onTouch(this, event)) { 11259 result = true; 11260 } 11261 11262 if (!result && onTouchEvent(event)) { 11263 result = true; 11264 } 11265 } 11266 11267 if (!result && mInputEventConsistencyVerifier != null) { 11268 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11269 } 11270 11271 // Clean up after nested scrolls if this is the end of a gesture; 11272 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 11273 // of the gesture. 11274 if (actionMasked == MotionEvent.ACTION_UP || 11275 actionMasked == MotionEvent.ACTION_CANCEL || 11276 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 11277 stopNestedScroll(); 11278 } 11279 11280 return result; 11281 } 11282 11283 boolean isAccessibilityFocusedViewOrHost() { 11284 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 11285 .getAccessibilityFocusedHost() == this); 11286 } 11287 11288 /** 11289 * Filter the touch event to apply security policies. 11290 * 11291 * @param event The motion event to be filtered. 11292 * @return True if the event should be dispatched, false if the event should be dropped. 11293 * 11294 * @see #getFilterTouchesWhenObscured 11295 */ 11296 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 11297 //noinspection RedundantIfStatement 11298 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 11299 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 11300 // Window is obscured, drop this touch. 11301 return false; 11302 } 11303 return true; 11304 } 11305 11306 /** 11307 * Pass a trackball motion event down to the focused view. 11308 * 11309 * @param event The motion event to be dispatched. 11310 * @return True if the event was handled by the view, false otherwise. 11311 */ 11312 public boolean dispatchTrackballEvent(MotionEvent event) { 11313 if (mInputEventConsistencyVerifier != null) { 11314 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 11315 } 11316 11317 return onTrackballEvent(event); 11318 } 11319 11320 /** 11321 * Pass a captured pointer event down to the focused view. 11322 * 11323 * @param event The motion event to be dispatched. 11324 * @return True if the event was handled by the view, false otherwise. 11325 */ 11326 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 11327 if (!hasPointerCapture()) { 11328 return false; 11329 } 11330 //noinspection SimplifiableIfStatement 11331 ListenerInfo li = mListenerInfo; 11332 if (li != null && li.mOnCapturedPointerListener != null 11333 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 11334 return true; 11335 } 11336 return onCapturedPointerEvent(event); 11337 } 11338 11339 /** 11340 * Dispatch a generic motion event. 11341 * <p> 11342 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11343 * are delivered to the view under the pointer. All other generic motion events are 11344 * delivered to the focused view. Hover events are handled specially and are delivered 11345 * to {@link #onHoverEvent(MotionEvent)}. 11346 * </p> 11347 * 11348 * @param event The motion event to be dispatched. 11349 * @return True if the event was handled by the view, false otherwise. 11350 */ 11351 public boolean dispatchGenericMotionEvent(MotionEvent event) { 11352 if (mInputEventConsistencyVerifier != null) { 11353 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 11354 } 11355 11356 final int source = event.getSource(); 11357 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 11358 final int action = event.getAction(); 11359 if (action == MotionEvent.ACTION_HOVER_ENTER 11360 || action == MotionEvent.ACTION_HOVER_MOVE 11361 || action == MotionEvent.ACTION_HOVER_EXIT) { 11362 if (dispatchHoverEvent(event)) { 11363 return true; 11364 } 11365 } else if (dispatchGenericPointerEvent(event)) { 11366 return true; 11367 } 11368 } else if (dispatchGenericFocusedEvent(event)) { 11369 return true; 11370 } 11371 11372 if (dispatchGenericMotionEventInternal(event)) { 11373 return true; 11374 } 11375 11376 if (mInputEventConsistencyVerifier != null) { 11377 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11378 } 11379 return false; 11380 } 11381 11382 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 11383 //noinspection SimplifiableIfStatement 11384 ListenerInfo li = mListenerInfo; 11385 if (li != null && li.mOnGenericMotionListener != null 11386 && (mViewFlags & ENABLED_MASK) == ENABLED 11387 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 11388 return true; 11389 } 11390 11391 if (onGenericMotionEvent(event)) { 11392 return true; 11393 } 11394 11395 final int actionButton = event.getActionButton(); 11396 switch (event.getActionMasked()) { 11397 case MotionEvent.ACTION_BUTTON_PRESS: 11398 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 11399 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11400 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11401 if (performContextClick(event.getX(), event.getY())) { 11402 mInContextButtonPress = true; 11403 setPressed(true, event.getX(), event.getY()); 11404 removeTapCallback(); 11405 removeLongPressCallback(); 11406 return true; 11407 } 11408 } 11409 break; 11410 11411 case MotionEvent.ACTION_BUTTON_RELEASE: 11412 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11413 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11414 mInContextButtonPress = false; 11415 mIgnoreNextUpEvent = true; 11416 } 11417 break; 11418 } 11419 11420 if (mInputEventConsistencyVerifier != null) { 11421 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11422 } 11423 return false; 11424 } 11425 11426 /** 11427 * Dispatch a hover event. 11428 * <p> 11429 * Do not call this method directly. 11430 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11431 * </p> 11432 * 11433 * @param event The motion event to be dispatched. 11434 * @return True if the event was handled by the view, false otherwise. 11435 */ 11436 protected boolean dispatchHoverEvent(MotionEvent event) { 11437 ListenerInfo li = mListenerInfo; 11438 //noinspection SimplifiableIfStatement 11439 if (li != null && li.mOnHoverListener != null 11440 && (mViewFlags & ENABLED_MASK) == ENABLED 11441 && li.mOnHoverListener.onHover(this, event)) { 11442 return true; 11443 } 11444 11445 return onHoverEvent(event); 11446 } 11447 11448 /** 11449 * Returns true if the view has a child to which it has recently sent 11450 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 11451 * it does not have a hovered child, then it must be the innermost hovered view. 11452 * @hide 11453 */ 11454 protected boolean hasHoveredChild() { 11455 return false; 11456 } 11457 11458 /** 11459 * Dispatch a generic motion event to the view under the first pointer. 11460 * <p> 11461 * Do not call this method directly. 11462 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11463 * </p> 11464 * 11465 * @param event The motion event to be dispatched. 11466 * @return True if the event was handled by the view, false otherwise. 11467 */ 11468 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 11469 return false; 11470 } 11471 11472 /** 11473 * Dispatch a generic motion event to the currently focused view. 11474 * <p> 11475 * Do not call this method directly. 11476 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11477 * </p> 11478 * 11479 * @param event The motion event to be dispatched. 11480 * @return True if the event was handled by the view, false otherwise. 11481 */ 11482 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 11483 return false; 11484 } 11485 11486 /** 11487 * Dispatch a pointer event. 11488 * <p> 11489 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 11490 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 11491 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 11492 * and should not be expected to handle other pointing device features. 11493 * </p> 11494 * 11495 * @param event The motion event to be dispatched. 11496 * @return True if the event was handled by the view, false otherwise. 11497 * @hide 11498 */ 11499 public final boolean dispatchPointerEvent(MotionEvent event) { 11500 if (event.isTouchEvent()) { 11501 return dispatchTouchEvent(event); 11502 } else { 11503 return dispatchGenericMotionEvent(event); 11504 } 11505 } 11506 11507 /** 11508 * Called when the window containing this view gains or loses window focus. 11509 * ViewGroups should override to route to their children. 11510 * 11511 * @param hasFocus True if the window containing this view now has focus, 11512 * false otherwise. 11513 */ 11514 public void dispatchWindowFocusChanged(boolean hasFocus) { 11515 onWindowFocusChanged(hasFocus); 11516 } 11517 11518 /** 11519 * Called when the window containing this view gains or loses focus. Note 11520 * that this is separate from view focus: to receive key events, both 11521 * your view and its window must have focus. If a window is displayed 11522 * on top of yours that takes input focus, then your own window will lose 11523 * focus but the view focus will remain unchanged. 11524 * 11525 * @param hasWindowFocus True if the window containing this view now has 11526 * focus, false otherwise. 11527 */ 11528 public void onWindowFocusChanged(boolean hasWindowFocus) { 11529 InputMethodManager imm = InputMethodManager.peekInstance(); 11530 if (!hasWindowFocus) { 11531 if (isPressed()) { 11532 setPressed(false); 11533 } 11534 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11535 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 11536 imm.focusOut(this); 11537 } 11538 removeLongPressCallback(); 11539 removeTapCallback(); 11540 onFocusLost(); 11541 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 11542 imm.focusIn(this); 11543 } 11544 11545 notifyEnterOrExitForAutoFillIfNeeded(hasWindowFocus); 11546 11547 refreshDrawableState(); 11548 } 11549 11550 /** 11551 * Returns true if this view is in a window that currently has window focus. 11552 * Note that this is not the same as the view itself having focus. 11553 * 11554 * @return True if this view is in a window that currently has window focus. 11555 */ 11556 public boolean hasWindowFocus() { 11557 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 11558 } 11559 11560 /** 11561 * Dispatch a view visibility change down the view hierarchy. 11562 * ViewGroups should override to route to their children. 11563 * @param changedView The view whose visibility changed. Could be 'this' or 11564 * an ancestor view. 11565 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 11566 * {@link #INVISIBLE} or {@link #GONE}. 11567 */ 11568 protected void dispatchVisibilityChanged(@NonNull View changedView, 11569 @Visibility int visibility) { 11570 onVisibilityChanged(changedView, visibility); 11571 } 11572 11573 /** 11574 * Called when the visibility of the view or an ancestor of the view has 11575 * changed. 11576 * 11577 * @param changedView The view whose visibility changed. May be 11578 * {@code this} or an ancestor view. 11579 * @param visibility The new visibility, one of {@link #VISIBLE}, 11580 * {@link #INVISIBLE} or {@link #GONE}. 11581 */ 11582 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 11583 } 11584 11585 /** 11586 * Dispatch a hint about whether this view is displayed. For instance, when 11587 * a View moves out of the screen, it might receives a display hint indicating 11588 * the view is not displayed. Applications should not <em>rely</em> on this hint 11589 * as there is no guarantee that they will receive one. 11590 * 11591 * @param hint A hint about whether or not this view is displayed: 11592 * {@link #VISIBLE} or {@link #INVISIBLE}. 11593 */ 11594 public void dispatchDisplayHint(@Visibility int hint) { 11595 onDisplayHint(hint); 11596 } 11597 11598 /** 11599 * Gives this view a hint about whether is displayed or not. For instance, when 11600 * a View moves out of the screen, it might receives a display hint indicating 11601 * the view is not displayed. Applications should not <em>rely</em> on this hint 11602 * as there is no guarantee that they will receive one. 11603 * 11604 * @param hint A hint about whether or not this view is displayed: 11605 * {@link #VISIBLE} or {@link #INVISIBLE}. 11606 */ 11607 protected void onDisplayHint(@Visibility int hint) { 11608 } 11609 11610 /** 11611 * Dispatch a window visibility change down the view hierarchy. 11612 * ViewGroups should override to route to their children. 11613 * 11614 * @param visibility The new visibility of the window. 11615 * 11616 * @see #onWindowVisibilityChanged(int) 11617 */ 11618 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 11619 onWindowVisibilityChanged(visibility); 11620 } 11621 11622 /** 11623 * Called when the window containing has change its visibility 11624 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 11625 * that this tells you whether or not your window is being made visible 11626 * to the window manager; this does <em>not</em> tell you whether or not 11627 * your window is obscured by other windows on the screen, even if it 11628 * is itself visible. 11629 * 11630 * @param visibility The new visibility of the window. 11631 */ 11632 protected void onWindowVisibilityChanged(@Visibility int visibility) { 11633 if (visibility == VISIBLE) { 11634 initialAwakenScrollBars(); 11635 } 11636 } 11637 11638 /** 11639 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 11640 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 11641 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 11642 * 11643 * @param isVisible true if this view's visibility to the user is uninterrupted by its 11644 * ancestors or by window visibility 11645 * @return true if this view is visible to the user, not counting clipping or overlapping 11646 */ 11647 boolean dispatchVisibilityAggregated(boolean isVisible) { 11648 final boolean thisVisible = getVisibility() == VISIBLE; 11649 // If we're not visible but something is telling us we are, ignore it. 11650 if (thisVisible || !isVisible) { 11651 onVisibilityAggregated(isVisible); 11652 } 11653 return thisVisible && isVisible; 11654 } 11655 11656 /** 11657 * Called when the user-visibility of this View is potentially affected by a change 11658 * to this view itself, an ancestor view or the window this view is attached to. 11659 * 11660 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 11661 * and this view's window is also visible 11662 */ 11663 @CallSuper 11664 public void onVisibilityAggregated(boolean isVisible) { 11665 if (isVisible && mAttachInfo != null) { 11666 initialAwakenScrollBars(); 11667 } 11668 11669 final Drawable dr = mBackground; 11670 if (dr != null && isVisible != dr.isVisible()) { 11671 dr.setVisible(isVisible, false); 11672 } 11673 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 11674 if (fg != null && isVisible != fg.isVisible()) { 11675 fg.setVisible(isVisible, false); 11676 } 11677 } 11678 11679 /** 11680 * Returns the current visibility of the window this view is attached to 11681 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 11682 * 11683 * @return Returns the current visibility of the view's window. 11684 */ 11685 @Visibility 11686 public int getWindowVisibility() { 11687 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 11688 } 11689 11690 /** 11691 * Retrieve the overall visible display size in which the window this view is 11692 * attached to has been positioned in. This takes into account screen 11693 * decorations above the window, for both cases where the window itself 11694 * is being position inside of them or the window is being placed under 11695 * then and covered insets are used for the window to position its content 11696 * inside. In effect, this tells you the available area where content can 11697 * be placed and remain visible to users. 11698 * 11699 * <p>This function requires an IPC back to the window manager to retrieve 11700 * the requested information, so should not be used in performance critical 11701 * code like drawing. 11702 * 11703 * @param outRect Filled in with the visible display frame. If the view 11704 * is not attached to a window, this is simply the raw display size. 11705 */ 11706 public void getWindowVisibleDisplayFrame(Rect outRect) { 11707 if (mAttachInfo != null) { 11708 try { 11709 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 11710 } catch (RemoteException e) { 11711 return; 11712 } 11713 // XXX This is really broken, and probably all needs to be done 11714 // in the window manager, and we need to know more about whether 11715 // we want the area behind or in front of the IME. 11716 final Rect insets = mAttachInfo.mVisibleInsets; 11717 outRect.left += insets.left; 11718 outRect.top += insets.top; 11719 outRect.right -= insets.right; 11720 outRect.bottom -= insets.bottom; 11721 return; 11722 } 11723 // The view is not attached to a display so we don't have a context. 11724 // Make a best guess about the display size. 11725 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 11726 d.getRectSize(outRect); 11727 } 11728 11729 /** 11730 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 11731 * is currently in without any insets. 11732 * 11733 * @hide 11734 */ 11735 public void getWindowDisplayFrame(Rect outRect) { 11736 if (mAttachInfo != null) { 11737 try { 11738 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 11739 } catch (RemoteException e) { 11740 return; 11741 } 11742 return; 11743 } 11744 // The view is not attached to a display so we don't have a context. 11745 // Make a best guess about the display size. 11746 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 11747 d.getRectSize(outRect); 11748 } 11749 11750 /** 11751 * Dispatch a notification about a resource configuration change down 11752 * the view hierarchy. 11753 * ViewGroups should override to route to their children. 11754 * 11755 * @param newConfig The new resource configuration. 11756 * 11757 * @see #onConfigurationChanged(android.content.res.Configuration) 11758 */ 11759 public void dispatchConfigurationChanged(Configuration newConfig) { 11760 onConfigurationChanged(newConfig); 11761 } 11762 11763 /** 11764 * Called when the current configuration of the resources being used 11765 * by the application have changed. You can use this to decide when 11766 * to reload resources that can changed based on orientation and other 11767 * configuration characteristics. You only need to use this if you are 11768 * not relying on the normal {@link android.app.Activity} mechanism of 11769 * recreating the activity instance upon a configuration change. 11770 * 11771 * @param newConfig The new resource configuration. 11772 */ 11773 protected void onConfigurationChanged(Configuration newConfig) { 11774 } 11775 11776 /** 11777 * Private function to aggregate all per-view attributes in to the view 11778 * root. 11779 */ 11780 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 11781 performCollectViewAttributes(attachInfo, visibility); 11782 } 11783 11784 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 11785 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 11786 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 11787 attachInfo.mKeepScreenOn = true; 11788 } 11789 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 11790 ListenerInfo li = mListenerInfo; 11791 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 11792 attachInfo.mHasSystemUiListeners = true; 11793 } 11794 } 11795 } 11796 11797 void needGlobalAttributesUpdate(boolean force) { 11798 final AttachInfo ai = mAttachInfo; 11799 if (ai != null && !ai.mRecomputeGlobalAttributes) { 11800 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 11801 || ai.mHasSystemUiListeners) { 11802 ai.mRecomputeGlobalAttributes = true; 11803 } 11804 } 11805 } 11806 11807 /** 11808 * Returns whether the device is currently in touch mode. Touch mode is entered 11809 * once the user begins interacting with the device by touch, and affects various 11810 * things like whether focus is always visible to the user. 11811 * 11812 * @return Whether the device is in touch mode. 11813 */ 11814 @ViewDebug.ExportedProperty 11815 public boolean isInTouchMode() { 11816 if (mAttachInfo != null) { 11817 return mAttachInfo.mInTouchMode; 11818 } else { 11819 return ViewRootImpl.isInTouchMode(); 11820 } 11821 } 11822 11823 /** 11824 * Returns the context the view is running in, through which it can 11825 * access the current theme, resources, etc. 11826 * 11827 * @return The view's Context. 11828 */ 11829 @ViewDebug.CapturedViewProperty 11830 public final Context getContext() { 11831 return mContext; 11832 } 11833 11834 /** 11835 * Handle a key event before it is processed by any input method 11836 * associated with the view hierarchy. This can be used to intercept 11837 * key events in special situations before the IME consumes them; a 11838 * typical example would be handling the BACK key to update the application's 11839 * UI instead of allowing the IME to see it and close itself. 11840 * 11841 * @param keyCode The value in event.getKeyCode(). 11842 * @param event Description of the key event. 11843 * @return If you handled the event, return true. If you want to allow the 11844 * event to be handled by the next receiver, return false. 11845 */ 11846 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 11847 return false; 11848 } 11849 11850 /** 11851 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 11852 * KeyEvent.Callback.onKeyDown()}: perform press of the view 11853 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 11854 * is released, if the view is enabled and clickable. 11855 * <p> 11856 * Key presses in software keyboards will generally NOT trigger this 11857 * listener, although some may elect to do so in some situations. Do not 11858 * rely on this to catch software key presses. 11859 * 11860 * @param keyCode a key code that represents the button pressed, from 11861 * {@link android.view.KeyEvent} 11862 * @param event the KeyEvent object that defines the button action 11863 */ 11864 public boolean onKeyDown(int keyCode, KeyEvent event) { 11865 if (KeyEvent.isConfirmKey(keyCode)) { 11866 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11867 return true; 11868 } 11869 11870 if (event.getRepeatCount() == 0) { 11871 // Long clickable items don't necessarily have to be clickable. 11872 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 11873 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 11874 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 11875 // For the purposes of menu anchoring and drawable hotspots, 11876 // key events are considered to be at the center of the view. 11877 final float x = getWidth() / 2f; 11878 final float y = getHeight() / 2f; 11879 if (clickable) { 11880 setPressed(true, x, y); 11881 } 11882 checkForLongClick(0, x, y); 11883 return true; 11884 } 11885 } 11886 } 11887 11888 return false; 11889 } 11890 11891 /** 11892 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 11893 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 11894 * the event). 11895 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11896 * although some may elect to do so in some situations. Do not rely on this to 11897 * catch software key presses. 11898 */ 11899 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 11900 return false; 11901 } 11902 11903 /** 11904 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 11905 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 11906 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 11907 * or {@link KeyEvent#KEYCODE_SPACE} is released. 11908 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11909 * although some may elect to do so in some situations. Do not rely on this to 11910 * catch software key presses. 11911 * 11912 * @param keyCode A key code that represents the button pressed, from 11913 * {@link android.view.KeyEvent}. 11914 * @param event The KeyEvent object that defines the button action. 11915 */ 11916 public boolean onKeyUp(int keyCode, KeyEvent event) { 11917 if (KeyEvent.isConfirmKey(keyCode)) { 11918 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11919 return true; 11920 } 11921 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 11922 setPressed(false); 11923 11924 if (!mHasPerformedLongPress) { 11925 // This is a tap, so remove the longpress check 11926 removeLongPressCallback(); 11927 if (!event.isCanceled()) { 11928 return performClick(); 11929 } 11930 } 11931 } 11932 } 11933 return false; 11934 } 11935 11936 /** 11937 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 11938 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 11939 * the event). 11940 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11941 * although some may elect to do so in some situations. Do not rely on this to 11942 * catch software key presses. 11943 * 11944 * @param keyCode A key code that represents the button pressed, from 11945 * {@link android.view.KeyEvent}. 11946 * @param repeatCount The number of times the action was made. 11947 * @param event The KeyEvent object that defines the button action. 11948 */ 11949 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 11950 return false; 11951 } 11952 11953 /** 11954 * Called on the focused view when a key shortcut event is not handled. 11955 * Override this method to implement local key shortcuts for the View. 11956 * Key shortcuts can also be implemented by setting the 11957 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 11958 * 11959 * @param keyCode The value in event.getKeyCode(). 11960 * @param event Description of the key event. 11961 * @return If you handled the event, return true. If you want to allow the 11962 * event to be handled by the next receiver, return false. 11963 */ 11964 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 11965 return false; 11966 } 11967 11968 /** 11969 * Check whether the called view is a text editor, in which case it 11970 * would make sense to automatically display a soft input window for 11971 * it. Subclasses should override this if they implement 11972 * {@link #onCreateInputConnection(EditorInfo)} to return true if 11973 * a call on that method would return a non-null InputConnection, and 11974 * they are really a first-class editor that the user would normally 11975 * start typing on when the go into a window containing your view. 11976 * 11977 * <p>The default implementation always returns false. This does 11978 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 11979 * will not be called or the user can not otherwise perform edits on your 11980 * view; it is just a hint to the system that this is not the primary 11981 * purpose of this view. 11982 * 11983 * @return Returns true if this view is a text editor, else false. 11984 */ 11985 public boolean onCheckIsTextEditor() { 11986 return false; 11987 } 11988 11989 /** 11990 * Create a new InputConnection for an InputMethod to interact 11991 * with the view. The default implementation returns null, since it doesn't 11992 * support input methods. You can override this to implement such support. 11993 * This is only needed for views that take focus and text input. 11994 * 11995 * <p>When implementing this, you probably also want to implement 11996 * {@link #onCheckIsTextEditor()} to indicate you will return a 11997 * non-null InputConnection.</p> 11998 * 11999 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 12000 * object correctly and in its entirety, so that the connected IME can rely 12001 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 12002 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 12003 * must be filled in with the correct cursor position for IMEs to work correctly 12004 * with your application.</p> 12005 * 12006 * @param outAttrs Fill in with attribute information about the connection. 12007 */ 12008 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 12009 return null; 12010 } 12011 12012 /** 12013 * Called by the {@link android.view.inputmethod.InputMethodManager} 12014 * when a view who is not the current 12015 * input connection target is trying to make a call on the manager. The 12016 * default implementation returns false; you can override this to return 12017 * true for certain views if you are performing InputConnection proxying 12018 * to them. 12019 * @param view The View that is making the InputMethodManager call. 12020 * @return Return true to allow the call, false to reject. 12021 */ 12022 public boolean checkInputConnectionProxy(View view) { 12023 return false; 12024 } 12025 12026 /** 12027 * Show the context menu for this view. It is not safe to hold on to the 12028 * menu after returning from this method. 12029 * 12030 * You should normally not overload this method. Overload 12031 * {@link #onCreateContextMenu(ContextMenu)} or define an 12032 * {@link OnCreateContextMenuListener} to add items to the context menu. 12033 * 12034 * @param menu The context menu to populate 12035 */ 12036 public void createContextMenu(ContextMenu menu) { 12037 ContextMenuInfo menuInfo = getContextMenuInfo(); 12038 12039 // Sets the current menu info so all items added to menu will have 12040 // my extra info set. 12041 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 12042 12043 onCreateContextMenu(menu); 12044 ListenerInfo li = mListenerInfo; 12045 if (li != null && li.mOnCreateContextMenuListener != null) { 12046 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 12047 } 12048 12049 // Clear the extra information so subsequent items that aren't mine don't 12050 // have my extra info. 12051 ((MenuBuilder)menu).setCurrentMenuInfo(null); 12052 12053 if (mParent != null) { 12054 mParent.createContextMenu(menu); 12055 } 12056 } 12057 12058 /** 12059 * Views should implement this if they have extra information to associate 12060 * with the context menu. The return result is supplied as a parameter to 12061 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 12062 * callback. 12063 * 12064 * @return Extra information about the item for which the context menu 12065 * should be shown. This information will vary across different 12066 * subclasses of View. 12067 */ 12068 protected ContextMenuInfo getContextMenuInfo() { 12069 return null; 12070 } 12071 12072 /** 12073 * Views should implement this if the view itself is going to add items to 12074 * the context menu. 12075 * 12076 * @param menu the context menu to populate 12077 */ 12078 protected void onCreateContextMenu(ContextMenu menu) { 12079 } 12080 12081 /** 12082 * Implement this method to handle trackball motion events. The 12083 * <em>relative</em> movement of the trackball since the last event 12084 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 12085 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 12086 * that a movement of 1 corresponds to the user pressing one DPAD key (so 12087 * they will often be fractional values, representing the more fine-grained 12088 * movement information available from a trackball). 12089 * 12090 * @param event The motion event. 12091 * @return True if the event was handled, false otherwise. 12092 */ 12093 public boolean onTrackballEvent(MotionEvent event) { 12094 return false; 12095 } 12096 12097 /** 12098 * Implement this method to handle generic motion events. 12099 * <p> 12100 * Generic motion events describe joystick movements, mouse hovers, track pad 12101 * touches, scroll wheel movements and other input events. The 12102 * {@link MotionEvent#getSource() source} of the motion event specifies 12103 * the class of input that was received. Implementations of this method 12104 * must examine the bits in the source before processing the event. 12105 * The following code example shows how this is done. 12106 * </p><p> 12107 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 12108 * are delivered to the view under the pointer. All other generic motion events are 12109 * delivered to the focused view. 12110 * </p> 12111 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 12112 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 12113 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 12114 * // process the joystick movement... 12115 * return true; 12116 * } 12117 * } 12118 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 12119 * switch (event.getAction()) { 12120 * case MotionEvent.ACTION_HOVER_MOVE: 12121 * // process the mouse hover movement... 12122 * return true; 12123 * case MotionEvent.ACTION_SCROLL: 12124 * // process the scroll wheel movement... 12125 * return true; 12126 * } 12127 * } 12128 * return super.onGenericMotionEvent(event); 12129 * }</pre> 12130 * 12131 * @param event The generic motion event being processed. 12132 * @return True if the event was handled, false otherwise. 12133 */ 12134 public boolean onGenericMotionEvent(MotionEvent event) { 12135 return false; 12136 } 12137 12138 /** 12139 * Implement this method to handle hover events. 12140 * <p> 12141 * This method is called whenever a pointer is hovering into, over, or out of the 12142 * bounds of a view and the view is not currently being touched. 12143 * Hover events are represented as pointer events with action 12144 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 12145 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 12146 * </p> 12147 * <ul> 12148 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 12149 * when the pointer enters the bounds of the view.</li> 12150 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 12151 * when the pointer has already entered the bounds of the view and has moved.</li> 12152 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 12153 * when the pointer has exited the bounds of the view or when the pointer is 12154 * about to go down due to a button click, tap, or similar user action that 12155 * causes the view to be touched.</li> 12156 * </ul> 12157 * <p> 12158 * The view should implement this method to return true to indicate that it is 12159 * handling the hover event, such as by changing its drawable state. 12160 * </p><p> 12161 * The default implementation calls {@link #setHovered} to update the hovered state 12162 * of the view when a hover enter or hover exit event is received, if the view 12163 * is enabled and is clickable. The default implementation also sends hover 12164 * accessibility events. 12165 * </p> 12166 * 12167 * @param event The motion event that describes the hover. 12168 * @return True if the view handled the hover event. 12169 * 12170 * @see #isHovered 12171 * @see #setHovered 12172 * @see #onHoverChanged 12173 */ 12174 public boolean onHoverEvent(MotionEvent event) { 12175 // The root view may receive hover (or touch) events that are outside the bounds of 12176 // the window. This code ensures that we only send accessibility events for 12177 // hovers that are actually within the bounds of the root view. 12178 final int action = event.getActionMasked(); 12179 if (!mSendingHoverAccessibilityEvents) { 12180 if ((action == MotionEvent.ACTION_HOVER_ENTER 12181 || action == MotionEvent.ACTION_HOVER_MOVE) 12182 && !hasHoveredChild() 12183 && pointInView(event.getX(), event.getY())) { 12184 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 12185 mSendingHoverAccessibilityEvents = true; 12186 } 12187 } else { 12188 if (action == MotionEvent.ACTION_HOVER_EXIT 12189 || (action == MotionEvent.ACTION_MOVE 12190 && !pointInView(event.getX(), event.getY()))) { 12191 mSendingHoverAccessibilityEvents = false; 12192 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 12193 } 12194 } 12195 12196 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 12197 && event.isFromSource(InputDevice.SOURCE_MOUSE) 12198 && isOnScrollbar(event.getX(), event.getY())) { 12199 awakenScrollBars(); 12200 } 12201 12202 // If we consider ourself hoverable, or if we we're already hovered, 12203 // handle changing state in response to ENTER and EXIT events. 12204 if (isHoverable() || isHovered()) { 12205 switch (action) { 12206 case MotionEvent.ACTION_HOVER_ENTER: 12207 setHovered(true); 12208 break; 12209 case MotionEvent.ACTION_HOVER_EXIT: 12210 setHovered(false); 12211 break; 12212 } 12213 12214 // Dispatch the event to onGenericMotionEvent before returning true. 12215 // This is to provide compatibility with existing applications that 12216 // handled HOVER_MOVE events in onGenericMotionEvent and that would 12217 // break because of the new default handling for hoverable views 12218 // in onHoverEvent. 12219 // Note that onGenericMotionEvent will be called by default when 12220 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 12221 dispatchGenericMotionEventInternal(event); 12222 // The event was already handled by calling setHovered(), so always 12223 // return true. 12224 return true; 12225 } 12226 12227 return false; 12228 } 12229 12230 /** 12231 * Returns true if the view should handle {@link #onHoverEvent} 12232 * by calling {@link #setHovered} to change its hovered state. 12233 * 12234 * @return True if the view is hoverable. 12235 */ 12236 private boolean isHoverable() { 12237 final int viewFlags = mViewFlags; 12238 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12239 return false; 12240 } 12241 12242 return (viewFlags & CLICKABLE) == CLICKABLE 12243 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 12244 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12245 } 12246 12247 /** 12248 * Returns true if the view is currently hovered. 12249 * 12250 * @return True if the view is currently hovered. 12251 * 12252 * @see #setHovered 12253 * @see #onHoverChanged 12254 */ 12255 @ViewDebug.ExportedProperty 12256 public boolean isHovered() { 12257 return (mPrivateFlags & PFLAG_HOVERED) != 0; 12258 } 12259 12260 /** 12261 * Sets whether the view is currently hovered. 12262 * <p> 12263 * Calling this method also changes the drawable state of the view. This 12264 * enables the view to react to hover by using different drawable resources 12265 * to change its appearance. 12266 * </p><p> 12267 * The {@link #onHoverChanged} method is called when the hovered state changes. 12268 * </p> 12269 * 12270 * @param hovered True if the view is hovered. 12271 * 12272 * @see #isHovered 12273 * @see #onHoverChanged 12274 */ 12275 public void setHovered(boolean hovered) { 12276 if (hovered) { 12277 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 12278 mPrivateFlags |= PFLAG_HOVERED; 12279 refreshDrawableState(); 12280 onHoverChanged(true); 12281 } 12282 } else { 12283 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 12284 mPrivateFlags &= ~PFLAG_HOVERED; 12285 refreshDrawableState(); 12286 onHoverChanged(false); 12287 } 12288 } 12289 } 12290 12291 /** 12292 * Implement this method to handle hover state changes. 12293 * <p> 12294 * This method is called whenever the hover state changes as a result of a 12295 * call to {@link #setHovered}. 12296 * </p> 12297 * 12298 * @param hovered The current hover state, as returned by {@link #isHovered}. 12299 * 12300 * @see #isHovered 12301 * @see #setHovered 12302 */ 12303 public void onHoverChanged(boolean hovered) { 12304 } 12305 12306 /** 12307 * Handles scroll bar dragging by mouse input. 12308 * 12309 * @hide 12310 * @param event The motion event. 12311 * 12312 * @return true if the event was handled as a scroll bar dragging, false otherwise. 12313 */ 12314 protected boolean handleScrollBarDragging(MotionEvent event) { 12315 if (mScrollCache == null) { 12316 return false; 12317 } 12318 final float x = event.getX(); 12319 final float y = event.getY(); 12320 final int action = event.getAction(); 12321 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 12322 && action != MotionEvent.ACTION_DOWN) 12323 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 12324 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 12325 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12326 return false; 12327 } 12328 12329 switch (action) { 12330 case MotionEvent.ACTION_MOVE: 12331 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 12332 return false; 12333 } 12334 if (mScrollCache.mScrollBarDraggingState 12335 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 12336 final Rect bounds = mScrollCache.mScrollBarBounds; 12337 getVerticalScrollBarBounds(bounds, null); 12338 final int range = computeVerticalScrollRange(); 12339 final int offset = computeVerticalScrollOffset(); 12340 final int extent = computeVerticalScrollExtent(); 12341 12342 final int thumbLength = ScrollBarUtils.getThumbLength( 12343 bounds.height(), bounds.width(), extent, range); 12344 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12345 bounds.height(), thumbLength, extent, range, offset); 12346 12347 final float diff = y - mScrollCache.mScrollBarDraggingPos; 12348 final float maxThumbOffset = bounds.height() - thumbLength; 12349 final float newThumbOffset = 12350 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12351 final int height = getHeight(); 12352 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12353 && height > 0 && extent > 0) { 12354 final int newY = Math.round((range - extent) 12355 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 12356 if (newY != getScrollY()) { 12357 mScrollCache.mScrollBarDraggingPos = y; 12358 setScrollY(newY); 12359 } 12360 } 12361 return true; 12362 } 12363 if (mScrollCache.mScrollBarDraggingState 12364 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 12365 final Rect bounds = mScrollCache.mScrollBarBounds; 12366 getHorizontalScrollBarBounds(bounds, null); 12367 final int range = computeHorizontalScrollRange(); 12368 final int offset = computeHorizontalScrollOffset(); 12369 final int extent = computeHorizontalScrollExtent(); 12370 12371 final int thumbLength = ScrollBarUtils.getThumbLength( 12372 bounds.width(), bounds.height(), extent, range); 12373 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12374 bounds.width(), thumbLength, extent, range, offset); 12375 12376 final float diff = x - mScrollCache.mScrollBarDraggingPos; 12377 final float maxThumbOffset = bounds.width() - thumbLength; 12378 final float newThumbOffset = 12379 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12380 final int width = getWidth(); 12381 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12382 && width > 0 && extent > 0) { 12383 final int newX = Math.round((range - extent) 12384 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 12385 if (newX != getScrollX()) { 12386 mScrollCache.mScrollBarDraggingPos = x; 12387 setScrollX(newX); 12388 } 12389 } 12390 return true; 12391 } 12392 case MotionEvent.ACTION_DOWN: 12393 if (mScrollCache.state == ScrollabilityCache.OFF) { 12394 return false; 12395 } 12396 if (isOnVerticalScrollbarThumb(x, y)) { 12397 mScrollCache.mScrollBarDraggingState = 12398 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 12399 mScrollCache.mScrollBarDraggingPos = y; 12400 return true; 12401 } 12402 if (isOnHorizontalScrollbarThumb(x, y)) { 12403 mScrollCache.mScrollBarDraggingState = 12404 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 12405 mScrollCache.mScrollBarDraggingPos = x; 12406 return true; 12407 } 12408 } 12409 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12410 return false; 12411 } 12412 12413 /** 12414 * Implement this method to handle touch screen motion events. 12415 * <p> 12416 * If this method is used to detect click actions, it is recommended that 12417 * the actions be performed by implementing and calling 12418 * {@link #performClick()}. This will ensure consistent system behavior, 12419 * including: 12420 * <ul> 12421 * <li>obeying click sound preferences 12422 * <li>dispatching OnClickListener calls 12423 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 12424 * accessibility features are enabled 12425 * </ul> 12426 * 12427 * @param event The motion event. 12428 * @return True if the event was handled, false otherwise. 12429 */ 12430 public boolean onTouchEvent(MotionEvent event) { 12431 final float x = event.getX(); 12432 final float y = event.getY(); 12433 final int viewFlags = mViewFlags; 12434 final int action = event.getAction(); 12435 12436 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 12437 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 12438 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12439 12440 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12441 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 12442 setPressed(false); 12443 } 12444 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12445 // A disabled view that is clickable still consumes the touch 12446 // events, it just doesn't respond to them. 12447 return clickable; 12448 } 12449 if (mTouchDelegate != null) { 12450 if (mTouchDelegate.onTouchEvent(event)) { 12451 return true; 12452 } 12453 } 12454 12455 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 12456 switch (action) { 12457 case MotionEvent.ACTION_UP: 12458 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12459 if ((viewFlags & TOOLTIP) == TOOLTIP) { 12460 handleTooltipUp(); 12461 } 12462 if (!clickable) { 12463 removeTapCallback(); 12464 removeLongPressCallback(); 12465 mInContextButtonPress = false; 12466 mHasPerformedLongPress = false; 12467 mIgnoreNextUpEvent = false; 12468 break; 12469 } 12470 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 12471 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 12472 // take focus if we don't have it already and we should in 12473 // touch mode. 12474 boolean focusTaken = false; 12475 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 12476 focusTaken = requestFocus(); 12477 } 12478 12479 if (prepressed) { 12480 // The button is being released before we actually 12481 // showed it as pressed. Make it show the pressed 12482 // state now (before scheduling the click) to ensure 12483 // the user sees it. 12484 setPressed(true, x, y); 12485 } 12486 12487 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 12488 // This is a tap, so remove the longpress check 12489 removeLongPressCallback(); 12490 12491 // Only perform take click actions if we were in the pressed state 12492 if (!focusTaken) { 12493 // Use a Runnable and post this rather than calling 12494 // performClick directly. This lets other visual state 12495 // of the view update before click actions start. 12496 if (mPerformClick == null) { 12497 mPerformClick = new PerformClick(); 12498 } 12499 if (!post(mPerformClick)) { 12500 performClick(); 12501 } 12502 } 12503 } 12504 12505 if (mUnsetPressedState == null) { 12506 mUnsetPressedState = new UnsetPressedState(); 12507 } 12508 12509 if (prepressed) { 12510 postDelayed(mUnsetPressedState, 12511 ViewConfiguration.getPressedStateDuration()); 12512 } else if (!post(mUnsetPressedState)) { 12513 // If the post failed, unpress right now 12514 mUnsetPressedState.run(); 12515 } 12516 12517 removeTapCallback(); 12518 } 12519 mIgnoreNextUpEvent = false; 12520 break; 12521 12522 case MotionEvent.ACTION_DOWN: 12523 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 12524 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 12525 } 12526 mHasPerformedLongPress = false; 12527 12528 if (!clickable) { 12529 checkForLongClick(0, x, y); 12530 break; 12531 } 12532 12533 if (performButtonActionOnTouchDown(event)) { 12534 break; 12535 } 12536 12537 // Walk up the hierarchy to determine if we're inside a scrolling container. 12538 boolean isInScrollingContainer = isInScrollingContainer(); 12539 12540 // For views inside a scrolling container, delay the pressed feedback for 12541 // a short period in case this is a scroll. 12542 if (isInScrollingContainer) { 12543 mPrivateFlags |= PFLAG_PREPRESSED; 12544 if (mPendingCheckForTap == null) { 12545 mPendingCheckForTap = new CheckForTap(); 12546 } 12547 mPendingCheckForTap.x = event.getX(); 12548 mPendingCheckForTap.y = event.getY(); 12549 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 12550 } else { 12551 // Not inside a scrolling container, so show the feedback right away 12552 setPressed(true, x, y); 12553 checkForLongClick(0, x, y); 12554 } 12555 break; 12556 12557 case MotionEvent.ACTION_CANCEL: 12558 if (clickable) { 12559 setPressed(false); 12560 } 12561 removeTapCallback(); 12562 removeLongPressCallback(); 12563 mInContextButtonPress = false; 12564 mHasPerformedLongPress = false; 12565 mIgnoreNextUpEvent = false; 12566 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12567 break; 12568 12569 case MotionEvent.ACTION_MOVE: 12570 if (clickable) { 12571 drawableHotspotChanged(x, y); 12572 } 12573 12574 // Be lenient about moving outside of buttons 12575 if (!pointInView(x, y, mTouchSlop)) { 12576 // Outside button 12577 // Remove any future long press/tap checks 12578 removeTapCallback(); 12579 removeLongPressCallback(); 12580 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 12581 setPressed(false); 12582 } 12583 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12584 } 12585 break; 12586 } 12587 12588 return true; 12589 } 12590 12591 return false; 12592 } 12593 12594 /** 12595 * @hide 12596 */ 12597 public boolean isInScrollingContainer() { 12598 ViewParent p = getParent(); 12599 while (p != null && p instanceof ViewGroup) { 12600 if (((ViewGroup) p).shouldDelayChildPressedState()) { 12601 return true; 12602 } 12603 p = p.getParent(); 12604 } 12605 return false; 12606 } 12607 12608 /** 12609 * Remove the longpress detection timer. 12610 */ 12611 private void removeLongPressCallback() { 12612 if (mPendingCheckForLongPress != null) { 12613 removeCallbacks(mPendingCheckForLongPress); 12614 } 12615 } 12616 12617 /** 12618 * Remove the pending click action 12619 */ 12620 private void removePerformClickCallback() { 12621 if (mPerformClick != null) { 12622 removeCallbacks(mPerformClick); 12623 } 12624 } 12625 12626 /** 12627 * Remove the prepress detection timer. 12628 */ 12629 private void removeUnsetPressCallback() { 12630 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 12631 setPressed(false); 12632 removeCallbacks(mUnsetPressedState); 12633 } 12634 } 12635 12636 /** 12637 * Remove the tap detection timer. 12638 */ 12639 private void removeTapCallback() { 12640 if (mPendingCheckForTap != null) { 12641 mPrivateFlags &= ~PFLAG_PREPRESSED; 12642 removeCallbacks(mPendingCheckForTap); 12643 } 12644 } 12645 12646 /** 12647 * Cancels a pending long press. Your subclass can use this if you 12648 * want the context menu to come up if the user presses and holds 12649 * at the same place, but you don't want it to come up if they press 12650 * and then move around enough to cause scrolling. 12651 */ 12652 public void cancelLongPress() { 12653 removeLongPressCallback(); 12654 12655 /* 12656 * The prepressed state handled by the tap callback is a display 12657 * construct, but the tap callback will post a long press callback 12658 * less its own timeout. Remove it here. 12659 */ 12660 removeTapCallback(); 12661 } 12662 12663 /** 12664 * Remove the pending callback for sending a 12665 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 12666 */ 12667 private void removeSendViewScrolledAccessibilityEventCallback() { 12668 if (mSendViewScrolledAccessibilityEvent != null) { 12669 removeCallbacks(mSendViewScrolledAccessibilityEvent); 12670 mSendViewScrolledAccessibilityEvent.mIsPending = false; 12671 } 12672 } 12673 12674 /** 12675 * Sets the TouchDelegate for this View. 12676 */ 12677 public void setTouchDelegate(TouchDelegate delegate) { 12678 mTouchDelegate = delegate; 12679 } 12680 12681 /** 12682 * Gets the TouchDelegate for this View. 12683 */ 12684 public TouchDelegate getTouchDelegate() { 12685 return mTouchDelegate; 12686 } 12687 12688 /** 12689 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 12690 * 12691 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 12692 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 12693 * available. This method should only be called for touch events. 12694 * 12695 * <p class="note">This api is not intended for most applications. Buffered dispatch 12696 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 12697 * streams will not improve your input latency. Side effects include: increased latency, 12698 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 12699 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 12700 * you.</p> 12701 */ 12702 public final void requestUnbufferedDispatch(MotionEvent event) { 12703 final int action = event.getAction(); 12704 if (mAttachInfo == null 12705 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 12706 || !event.isTouchEvent()) { 12707 return; 12708 } 12709 mAttachInfo.mUnbufferedDispatchRequested = true; 12710 } 12711 12712 /** 12713 * Set flags controlling behavior of this view. 12714 * 12715 * @param flags Constant indicating the value which should be set 12716 * @param mask Constant indicating the bit range that should be changed 12717 */ 12718 void setFlags(int flags, int mask) { 12719 final boolean accessibilityEnabled = 12720 AccessibilityManager.getInstance(mContext).isEnabled(); 12721 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 12722 12723 int old = mViewFlags; 12724 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 12725 12726 int changed = mViewFlags ^ old; 12727 if (changed == 0) { 12728 return; 12729 } 12730 int privateFlags = mPrivateFlags; 12731 12732 // If focusable is auto, update the FOCUSABLE bit. 12733 int focusableChangedByAuto = 0; 12734 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 12735 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 12736 // Heuristic only takes into account whether view is clickable. 12737 final int newFocus; 12738 if ((mViewFlags & CLICKABLE) != 0) { 12739 newFocus = FOCUSABLE; 12740 } else { 12741 newFocus = NOT_FOCUSABLE; 12742 } 12743 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 12744 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 12745 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 12746 } 12747 12748 /* Check if the FOCUSABLE bit has changed */ 12749 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 12750 if (((old & FOCUSABLE) == FOCUSABLE) 12751 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 12752 /* Give up focus if we are no longer focusable */ 12753 clearFocus(); 12754 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 12755 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 12756 /* 12757 * Tell the view system that we are now available to take focus 12758 * if no one else already has it. 12759 */ 12760 if (mParent != null) { 12761 ViewRootImpl viewRootImpl = getViewRootImpl(); 12762 if (!sAutoFocusableOffUIThreadWontNotifyParents 12763 || focusableChangedByAuto == 0 12764 || viewRootImpl == null 12765 || viewRootImpl.mThread == Thread.currentThread()) { 12766 mParent.focusableViewAvailable(this); 12767 } 12768 } 12769 } 12770 } 12771 12772 final int newVisibility = flags & VISIBILITY_MASK; 12773 if (newVisibility == VISIBLE) { 12774 if ((changed & VISIBILITY_MASK) != 0) { 12775 /* 12776 * If this view is becoming visible, invalidate it in case it changed while 12777 * it was not visible. Marking it drawn ensures that the invalidation will 12778 * go through. 12779 */ 12780 mPrivateFlags |= PFLAG_DRAWN; 12781 invalidate(true); 12782 12783 needGlobalAttributesUpdate(true); 12784 12785 // a view becoming visible is worth notifying the parent 12786 // about in case nothing has focus. even if this specific view 12787 // isn't focusable, it may contain something that is, so let 12788 // the root view try to give this focus if nothing else does. 12789 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 12790 mParent.focusableViewAvailable(this); 12791 } 12792 } 12793 } 12794 12795 /* Check if the GONE bit has changed */ 12796 if ((changed & GONE) != 0) { 12797 needGlobalAttributesUpdate(false); 12798 requestLayout(); 12799 12800 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 12801 if (hasFocus()) clearFocus(); 12802 clearAccessibilityFocus(); 12803 destroyDrawingCache(); 12804 if (mParent instanceof View) { 12805 // GONE views noop invalidation, so invalidate the parent 12806 ((View) mParent).invalidate(true); 12807 } 12808 // Mark the view drawn to ensure that it gets invalidated properly the next 12809 // time it is visible and gets invalidated 12810 mPrivateFlags |= PFLAG_DRAWN; 12811 } 12812 if (mAttachInfo != null) { 12813 mAttachInfo.mViewVisibilityChanged = true; 12814 } 12815 } 12816 12817 /* Check if the VISIBLE bit has changed */ 12818 if ((changed & INVISIBLE) != 0) { 12819 needGlobalAttributesUpdate(false); 12820 /* 12821 * If this view is becoming invisible, set the DRAWN flag so that 12822 * the next invalidate() will not be skipped. 12823 */ 12824 mPrivateFlags |= PFLAG_DRAWN; 12825 12826 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 12827 // root view becoming invisible shouldn't clear focus and accessibility focus 12828 if (getRootView() != this) { 12829 if (hasFocus()) clearFocus(); 12830 clearAccessibilityFocus(); 12831 } 12832 } 12833 if (mAttachInfo != null) { 12834 mAttachInfo.mViewVisibilityChanged = true; 12835 } 12836 } 12837 12838 if ((changed & VISIBILITY_MASK) != 0) { 12839 // If the view is invisible, cleanup its display list to free up resources 12840 if (newVisibility != VISIBLE && mAttachInfo != null) { 12841 cleanupDraw(); 12842 } 12843 12844 if (mParent instanceof ViewGroup) { 12845 ((ViewGroup) mParent).onChildVisibilityChanged(this, 12846 (changed & VISIBILITY_MASK), newVisibility); 12847 ((View) mParent).invalidate(true); 12848 } else if (mParent != null) { 12849 mParent.invalidateChild(this, null); 12850 } 12851 12852 if (mAttachInfo != null) { 12853 dispatchVisibilityChanged(this, newVisibility); 12854 12855 // Aggregated visibility changes are dispatched to attached views 12856 // in visible windows where the parent is currently shown/drawn 12857 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 12858 // discounting clipping or overlapping. This makes it a good place 12859 // to change animation states. 12860 if (mParent != null && getWindowVisibility() == VISIBLE && 12861 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 12862 dispatchVisibilityAggregated(newVisibility == VISIBLE); 12863 } 12864 notifySubtreeAccessibilityStateChangedIfNeeded(); 12865 } 12866 } 12867 12868 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 12869 destroyDrawingCache(); 12870 } 12871 12872 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 12873 destroyDrawingCache(); 12874 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12875 invalidateParentCaches(); 12876 } 12877 12878 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 12879 destroyDrawingCache(); 12880 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12881 } 12882 12883 if ((changed & DRAW_MASK) != 0) { 12884 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 12885 if (mBackground != null 12886 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 12887 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12888 } else { 12889 mPrivateFlags |= PFLAG_SKIP_DRAW; 12890 } 12891 } else { 12892 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12893 } 12894 requestLayout(); 12895 invalidate(true); 12896 } 12897 12898 if ((changed & KEEP_SCREEN_ON) != 0) { 12899 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 12900 mParent.recomputeViewAttributes(this); 12901 } 12902 } 12903 12904 if (accessibilityEnabled) { 12905 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 12906 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 12907 || (changed & CONTEXT_CLICKABLE) != 0) { 12908 if (oldIncludeForAccessibility != includeForAccessibility()) { 12909 notifySubtreeAccessibilityStateChangedIfNeeded(); 12910 } else { 12911 notifyViewAccessibilityStateChangedIfNeeded( 12912 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12913 } 12914 } else if ((changed & ENABLED_MASK) != 0) { 12915 notifyViewAccessibilityStateChangedIfNeeded( 12916 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12917 } 12918 } 12919 } 12920 12921 /** 12922 * Change the view's z order in the tree, so it's on top of other sibling 12923 * views. This ordering change may affect layout, if the parent container 12924 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 12925 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 12926 * method should be followed by calls to {@link #requestLayout()} and 12927 * {@link View#invalidate()} on the view's parent to force the parent to redraw 12928 * with the new child ordering. 12929 * 12930 * @see ViewGroup#bringChildToFront(View) 12931 */ 12932 public void bringToFront() { 12933 if (mParent != null) { 12934 mParent.bringChildToFront(this); 12935 } 12936 } 12937 12938 /** 12939 * This is called in response to an internal scroll in this view (i.e., the 12940 * view scrolled its own contents). This is typically as a result of 12941 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 12942 * called. 12943 * 12944 * @param l Current horizontal scroll origin. 12945 * @param t Current vertical scroll origin. 12946 * @param oldl Previous horizontal scroll origin. 12947 * @param oldt Previous vertical scroll origin. 12948 */ 12949 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 12950 notifySubtreeAccessibilityStateChangedIfNeeded(); 12951 12952 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 12953 postSendViewScrolledAccessibilityEventCallback(); 12954 } 12955 12956 mBackgroundSizeChanged = true; 12957 if (mForegroundInfo != null) { 12958 mForegroundInfo.mBoundsChanged = true; 12959 } 12960 12961 final AttachInfo ai = mAttachInfo; 12962 if (ai != null) { 12963 ai.mViewScrollChanged = true; 12964 } 12965 12966 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 12967 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 12968 } 12969 } 12970 12971 /** 12972 * Interface definition for a callback to be invoked when the scroll 12973 * X or Y positions of a view change. 12974 * <p> 12975 * <b>Note:</b> Some views handle scrolling independently from View and may 12976 * have their own separate listeners for scroll-type events. For example, 12977 * {@link android.widget.ListView ListView} allows clients to register an 12978 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 12979 * to listen for changes in list scroll position. 12980 * 12981 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 12982 */ 12983 public interface OnScrollChangeListener { 12984 /** 12985 * Called when the scroll position of a view changes. 12986 * 12987 * @param v The view whose scroll position has changed. 12988 * @param scrollX Current horizontal scroll origin. 12989 * @param scrollY Current vertical scroll origin. 12990 * @param oldScrollX Previous horizontal scroll origin. 12991 * @param oldScrollY Previous vertical scroll origin. 12992 */ 12993 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 12994 } 12995 12996 /** 12997 * Interface definition for a callback to be invoked when the layout bounds of a view 12998 * changes due to layout processing. 12999 */ 13000 public interface OnLayoutChangeListener { 13001 /** 13002 * Called when the layout bounds of a view changes due to layout processing. 13003 * 13004 * @param v The view whose bounds have changed. 13005 * @param left The new value of the view's left property. 13006 * @param top The new value of the view's top property. 13007 * @param right The new value of the view's right property. 13008 * @param bottom The new value of the view's bottom property. 13009 * @param oldLeft The previous value of the view's left property. 13010 * @param oldTop The previous value of the view's top property. 13011 * @param oldRight The previous value of the view's right property. 13012 * @param oldBottom The previous value of the view's bottom property. 13013 */ 13014 void onLayoutChange(View v, int left, int top, int right, int bottom, 13015 int oldLeft, int oldTop, int oldRight, int oldBottom); 13016 } 13017 13018 /** 13019 * This is called during layout when the size of this view has changed. If 13020 * you were just added to the view hierarchy, you're called with the old 13021 * values of 0. 13022 * 13023 * @param w Current width of this view. 13024 * @param h Current height of this view. 13025 * @param oldw Old width of this view. 13026 * @param oldh Old height of this view. 13027 */ 13028 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 13029 } 13030 13031 /** 13032 * Called by draw to draw the child views. This may be overridden 13033 * by derived classes to gain control just before its children are drawn 13034 * (but after its own view has been drawn). 13035 * @param canvas the canvas on which to draw the view 13036 */ 13037 protected void dispatchDraw(Canvas canvas) { 13038 13039 } 13040 13041 /** 13042 * Gets the parent of this view. Note that the parent is a 13043 * ViewParent and not necessarily a View. 13044 * 13045 * @return Parent of this view. 13046 */ 13047 public final ViewParent getParent() { 13048 return mParent; 13049 } 13050 13051 /** 13052 * Set the horizontal scrolled position of your view. This will cause a call to 13053 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13054 * invalidated. 13055 * @param value the x position to scroll to 13056 */ 13057 public void setScrollX(int value) { 13058 scrollTo(value, mScrollY); 13059 } 13060 13061 /** 13062 * Set the vertical scrolled position of your view. This will cause a call to 13063 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13064 * invalidated. 13065 * @param value the y position to scroll to 13066 */ 13067 public void setScrollY(int value) { 13068 scrollTo(mScrollX, value); 13069 } 13070 13071 /** 13072 * Return the scrolled left position of this view. This is the left edge of 13073 * the displayed part of your view. You do not need to draw any pixels 13074 * farther left, since those are outside of the frame of your view on 13075 * screen. 13076 * 13077 * @return The left edge of the displayed part of your view, in pixels. 13078 */ 13079 public final int getScrollX() { 13080 return mScrollX; 13081 } 13082 13083 /** 13084 * Return the scrolled top position of this view. This is the top edge of 13085 * the displayed part of your view. You do not need to draw any pixels above 13086 * it, since those are outside of the frame of your view on screen. 13087 * 13088 * @return The top edge of the displayed part of your view, in pixels. 13089 */ 13090 public final int getScrollY() { 13091 return mScrollY; 13092 } 13093 13094 /** 13095 * Return the width of the your view. 13096 * 13097 * @return The width of your view, in pixels. 13098 */ 13099 @ViewDebug.ExportedProperty(category = "layout") 13100 public final int getWidth() { 13101 return mRight - mLeft; 13102 } 13103 13104 /** 13105 * Return the height of your view. 13106 * 13107 * @return The height of your view, in pixels. 13108 */ 13109 @ViewDebug.ExportedProperty(category = "layout") 13110 public final int getHeight() { 13111 return mBottom - mTop; 13112 } 13113 13114 /** 13115 * Return the visible drawing bounds of your view. Fills in the output 13116 * rectangle with the values from getScrollX(), getScrollY(), 13117 * getWidth(), and getHeight(). These bounds do not account for any 13118 * transformation properties currently set on the view, such as 13119 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 13120 * 13121 * @param outRect The (scrolled) drawing bounds of the view. 13122 */ 13123 public void getDrawingRect(Rect outRect) { 13124 outRect.left = mScrollX; 13125 outRect.top = mScrollY; 13126 outRect.right = mScrollX + (mRight - mLeft); 13127 outRect.bottom = mScrollY + (mBottom - mTop); 13128 } 13129 13130 /** 13131 * Like {@link #getMeasuredWidthAndState()}, but only returns the 13132 * raw width component (that is the result is masked by 13133 * {@link #MEASURED_SIZE_MASK}). 13134 * 13135 * @return The raw measured width of this view. 13136 */ 13137 public final int getMeasuredWidth() { 13138 return mMeasuredWidth & MEASURED_SIZE_MASK; 13139 } 13140 13141 /** 13142 * Return the full width measurement information for this view as computed 13143 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13144 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13145 * This should be used during measurement and layout calculations only. Use 13146 * {@link #getWidth()} to see how wide a view is after layout. 13147 * 13148 * @return The measured width of this view as a bit mask. 13149 */ 13150 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13151 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13152 name = "MEASURED_STATE_TOO_SMALL"), 13153 }) 13154 public final int getMeasuredWidthAndState() { 13155 return mMeasuredWidth; 13156 } 13157 13158 /** 13159 * Like {@link #getMeasuredHeightAndState()}, but only returns the 13160 * raw height component (that is the result is masked by 13161 * {@link #MEASURED_SIZE_MASK}). 13162 * 13163 * @return The raw measured height of this view. 13164 */ 13165 public final int getMeasuredHeight() { 13166 return mMeasuredHeight & MEASURED_SIZE_MASK; 13167 } 13168 13169 /** 13170 * Return the full height measurement information for this view as computed 13171 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13172 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13173 * This should be used during measurement and layout calculations only. Use 13174 * {@link #getHeight()} to see how wide a view is after layout. 13175 * 13176 * @return The measured height of this view as a bit mask. 13177 */ 13178 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13179 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13180 name = "MEASURED_STATE_TOO_SMALL"), 13181 }) 13182 public final int getMeasuredHeightAndState() { 13183 return mMeasuredHeight; 13184 } 13185 13186 /** 13187 * Return only the state bits of {@link #getMeasuredWidthAndState()} 13188 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 13189 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 13190 * and the height component is at the shifted bits 13191 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 13192 */ 13193 public final int getMeasuredState() { 13194 return (mMeasuredWidth&MEASURED_STATE_MASK) 13195 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 13196 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 13197 } 13198 13199 /** 13200 * The transform matrix of this view, which is calculated based on the current 13201 * rotation, scale, and pivot properties. 13202 * 13203 * @see #getRotation() 13204 * @see #getScaleX() 13205 * @see #getScaleY() 13206 * @see #getPivotX() 13207 * @see #getPivotY() 13208 * @return The current transform matrix for the view 13209 */ 13210 public Matrix getMatrix() { 13211 ensureTransformationInfo(); 13212 final Matrix matrix = mTransformationInfo.mMatrix; 13213 mRenderNode.getMatrix(matrix); 13214 return matrix; 13215 } 13216 13217 /** 13218 * Returns true if the transform matrix is the identity matrix. 13219 * Recomputes the matrix if necessary. 13220 * 13221 * @return True if the transform matrix is the identity matrix, false otherwise. 13222 */ 13223 final boolean hasIdentityMatrix() { 13224 return mRenderNode.hasIdentityMatrix(); 13225 } 13226 13227 void ensureTransformationInfo() { 13228 if (mTransformationInfo == null) { 13229 mTransformationInfo = new TransformationInfo(); 13230 } 13231 } 13232 13233 /** 13234 * Utility method to retrieve the inverse of the current mMatrix property. 13235 * We cache the matrix to avoid recalculating it when transform properties 13236 * have not changed. 13237 * 13238 * @return The inverse of the current matrix of this view. 13239 * @hide 13240 */ 13241 public final Matrix getInverseMatrix() { 13242 ensureTransformationInfo(); 13243 if (mTransformationInfo.mInverseMatrix == null) { 13244 mTransformationInfo.mInverseMatrix = new Matrix(); 13245 } 13246 final Matrix matrix = mTransformationInfo.mInverseMatrix; 13247 mRenderNode.getInverseMatrix(matrix); 13248 return matrix; 13249 } 13250 13251 /** 13252 * Gets the distance along the Z axis from the camera to this view. 13253 * 13254 * @see #setCameraDistance(float) 13255 * 13256 * @return The distance along the Z axis. 13257 */ 13258 public float getCameraDistance() { 13259 final float dpi = mResources.getDisplayMetrics().densityDpi; 13260 return -(mRenderNode.getCameraDistance() * dpi); 13261 } 13262 13263 /** 13264 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 13265 * views are drawn) from the camera to this view. The camera's distance 13266 * affects 3D transformations, for instance rotations around the X and Y 13267 * axis. If the rotationX or rotationY properties are changed and this view is 13268 * large (more than half the size of the screen), it is recommended to always 13269 * use a camera distance that's greater than the height (X axis rotation) or 13270 * the width (Y axis rotation) of this view.</p> 13271 * 13272 * <p>The distance of the camera from the view plane can have an affect on the 13273 * perspective distortion of the view when it is rotated around the x or y axis. 13274 * For example, a large distance will result in a large viewing angle, and there 13275 * will not be much perspective distortion of the view as it rotates. A short 13276 * distance may cause much more perspective distortion upon rotation, and can 13277 * also result in some drawing artifacts if the rotated view ends up partially 13278 * behind the camera (which is why the recommendation is to use a distance at 13279 * least as far as the size of the view, if the view is to be rotated.)</p> 13280 * 13281 * <p>The distance is expressed in "depth pixels." The default distance depends 13282 * on the screen density. For instance, on a medium density display, the 13283 * default distance is 1280. On a high density display, the default distance 13284 * is 1920.</p> 13285 * 13286 * <p>If you want to specify a distance that leads to visually consistent 13287 * results across various densities, use the following formula:</p> 13288 * <pre> 13289 * float scale = context.getResources().getDisplayMetrics().density; 13290 * view.setCameraDistance(distance * scale); 13291 * </pre> 13292 * 13293 * <p>The density scale factor of a high density display is 1.5, 13294 * and 1920 = 1280 * 1.5.</p> 13295 * 13296 * @param distance The distance in "depth pixels", if negative the opposite 13297 * value is used 13298 * 13299 * @see #setRotationX(float) 13300 * @see #setRotationY(float) 13301 */ 13302 public void setCameraDistance(float distance) { 13303 final float dpi = mResources.getDisplayMetrics().densityDpi; 13304 13305 invalidateViewProperty(true, false); 13306 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 13307 invalidateViewProperty(false, false); 13308 13309 invalidateParentIfNeededAndWasQuickRejected(); 13310 } 13311 13312 /** 13313 * The degrees that the view is rotated around the pivot point. 13314 * 13315 * @see #setRotation(float) 13316 * @see #getPivotX() 13317 * @see #getPivotY() 13318 * 13319 * @return The degrees of rotation. 13320 */ 13321 @ViewDebug.ExportedProperty(category = "drawing") 13322 public float getRotation() { 13323 return mRenderNode.getRotation(); 13324 } 13325 13326 /** 13327 * Sets the degrees that the view is rotated around the pivot point. Increasing values 13328 * result in clockwise rotation. 13329 * 13330 * @param rotation The degrees of rotation. 13331 * 13332 * @see #getRotation() 13333 * @see #getPivotX() 13334 * @see #getPivotY() 13335 * @see #setRotationX(float) 13336 * @see #setRotationY(float) 13337 * 13338 * @attr ref android.R.styleable#View_rotation 13339 */ 13340 public void setRotation(float rotation) { 13341 if (rotation != getRotation()) { 13342 // Double-invalidation is necessary to capture view's old and new areas 13343 invalidateViewProperty(true, false); 13344 mRenderNode.setRotation(rotation); 13345 invalidateViewProperty(false, true); 13346 13347 invalidateParentIfNeededAndWasQuickRejected(); 13348 notifySubtreeAccessibilityStateChangedIfNeeded(); 13349 } 13350 } 13351 13352 /** 13353 * The degrees that the view is rotated around the vertical axis through the pivot point. 13354 * 13355 * @see #getPivotX() 13356 * @see #getPivotY() 13357 * @see #setRotationY(float) 13358 * 13359 * @return The degrees of Y rotation. 13360 */ 13361 @ViewDebug.ExportedProperty(category = "drawing") 13362 public float getRotationY() { 13363 return mRenderNode.getRotationY(); 13364 } 13365 13366 /** 13367 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 13368 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 13369 * down the y axis. 13370 * 13371 * When rotating large views, it is recommended to adjust the camera distance 13372 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13373 * 13374 * @param rotationY The degrees of Y rotation. 13375 * 13376 * @see #getRotationY() 13377 * @see #getPivotX() 13378 * @see #getPivotY() 13379 * @see #setRotation(float) 13380 * @see #setRotationX(float) 13381 * @see #setCameraDistance(float) 13382 * 13383 * @attr ref android.R.styleable#View_rotationY 13384 */ 13385 public void setRotationY(float rotationY) { 13386 if (rotationY != getRotationY()) { 13387 invalidateViewProperty(true, false); 13388 mRenderNode.setRotationY(rotationY); 13389 invalidateViewProperty(false, true); 13390 13391 invalidateParentIfNeededAndWasQuickRejected(); 13392 notifySubtreeAccessibilityStateChangedIfNeeded(); 13393 } 13394 } 13395 13396 /** 13397 * The degrees that the view is rotated around the horizontal axis through the pivot point. 13398 * 13399 * @see #getPivotX() 13400 * @see #getPivotY() 13401 * @see #setRotationX(float) 13402 * 13403 * @return The degrees of X rotation. 13404 */ 13405 @ViewDebug.ExportedProperty(category = "drawing") 13406 public float getRotationX() { 13407 return mRenderNode.getRotationX(); 13408 } 13409 13410 /** 13411 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 13412 * Increasing values result in clockwise rotation from the viewpoint of looking down the 13413 * x axis. 13414 * 13415 * When rotating large views, it is recommended to adjust the camera distance 13416 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13417 * 13418 * @param rotationX The degrees of X rotation. 13419 * 13420 * @see #getRotationX() 13421 * @see #getPivotX() 13422 * @see #getPivotY() 13423 * @see #setRotation(float) 13424 * @see #setRotationY(float) 13425 * @see #setCameraDistance(float) 13426 * 13427 * @attr ref android.R.styleable#View_rotationX 13428 */ 13429 public void setRotationX(float rotationX) { 13430 if (rotationX != getRotationX()) { 13431 invalidateViewProperty(true, false); 13432 mRenderNode.setRotationX(rotationX); 13433 invalidateViewProperty(false, true); 13434 13435 invalidateParentIfNeededAndWasQuickRejected(); 13436 notifySubtreeAccessibilityStateChangedIfNeeded(); 13437 } 13438 } 13439 13440 /** 13441 * The amount that the view is scaled in x around the pivot point, as a proportion of 13442 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 13443 * 13444 * <p>By default, this is 1.0f. 13445 * 13446 * @see #getPivotX() 13447 * @see #getPivotY() 13448 * @return The scaling factor. 13449 */ 13450 @ViewDebug.ExportedProperty(category = "drawing") 13451 public float getScaleX() { 13452 return mRenderNode.getScaleX(); 13453 } 13454 13455 /** 13456 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 13457 * the view's unscaled width. A value of 1 means that no scaling is applied. 13458 * 13459 * @param scaleX The scaling factor. 13460 * @see #getPivotX() 13461 * @see #getPivotY() 13462 * 13463 * @attr ref android.R.styleable#View_scaleX 13464 */ 13465 public void setScaleX(float scaleX) { 13466 if (scaleX != getScaleX()) { 13467 invalidateViewProperty(true, false); 13468 mRenderNode.setScaleX(scaleX); 13469 invalidateViewProperty(false, true); 13470 13471 invalidateParentIfNeededAndWasQuickRejected(); 13472 notifySubtreeAccessibilityStateChangedIfNeeded(); 13473 } 13474 } 13475 13476 /** 13477 * The amount that the view is scaled in y around the pivot point, as a proportion of 13478 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 13479 * 13480 * <p>By default, this is 1.0f. 13481 * 13482 * @see #getPivotX() 13483 * @see #getPivotY() 13484 * @return The scaling factor. 13485 */ 13486 @ViewDebug.ExportedProperty(category = "drawing") 13487 public float getScaleY() { 13488 return mRenderNode.getScaleY(); 13489 } 13490 13491 /** 13492 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 13493 * the view's unscaled width. A value of 1 means that no scaling is applied. 13494 * 13495 * @param scaleY The scaling factor. 13496 * @see #getPivotX() 13497 * @see #getPivotY() 13498 * 13499 * @attr ref android.R.styleable#View_scaleY 13500 */ 13501 public void setScaleY(float scaleY) { 13502 if (scaleY != getScaleY()) { 13503 invalidateViewProperty(true, false); 13504 mRenderNode.setScaleY(scaleY); 13505 invalidateViewProperty(false, true); 13506 13507 invalidateParentIfNeededAndWasQuickRejected(); 13508 notifySubtreeAccessibilityStateChangedIfNeeded(); 13509 } 13510 } 13511 13512 /** 13513 * The x location of the point around which the view is {@link #setRotation(float) rotated} 13514 * and {@link #setScaleX(float) scaled}. 13515 * 13516 * @see #getRotation() 13517 * @see #getScaleX() 13518 * @see #getScaleY() 13519 * @see #getPivotY() 13520 * @return The x location of the pivot point. 13521 * 13522 * @attr ref android.R.styleable#View_transformPivotX 13523 */ 13524 @ViewDebug.ExportedProperty(category = "drawing") 13525 public float getPivotX() { 13526 return mRenderNode.getPivotX(); 13527 } 13528 13529 /** 13530 * Sets the x location of the point around which the view is 13531 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 13532 * By default, the pivot point is centered on the object. 13533 * Setting this property disables this behavior and causes the view to use only the 13534 * explicitly set pivotX and pivotY values. 13535 * 13536 * @param pivotX The x location of the pivot point. 13537 * @see #getRotation() 13538 * @see #getScaleX() 13539 * @see #getScaleY() 13540 * @see #getPivotY() 13541 * 13542 * @attr ref android.R.styleable#View_transformPivotX 13543 */ 13544 public void setPivotX(float pivotX) { 13545 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 13546 invalidateViewProperty(true, false); 13547 mRenderNode.setPivotX(pivotX); 13548 invalidateViewProperty(false, true); 13549 13550 invalidateParentIfNeededAndWasQuickRejected(); 13551 } 13552 } 13553 13554 /** 13555 * The y location of the point around which the view is {@link #setRotation(float) rotated} 13556 * and {@link #setScaleY(float) scaled}. 13557 * 13558 * @see #getRotation() 13559 * @see #getScaleX() 13560 * @see #getScaleY() 13561 * @see #getPivotY() 13562 * @return The y location of the pivot point. 13563 * 13564 * @attr ref android.R.styleable#View_transformPivotY 13565 */ 13566 @ViewDebug.ExportedProperty(category = "drawing") 13567 public float getPivotY() { 13568 return mRenderNode.getPivotY(); 13569 } 13570 13571 /** 13572 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 13573 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 13574 * Setting this property disables this behavior and causes the view to use only the 13575 * explicitly set pivotX and pivotY values. 13576 * 13577 * @param pivotY The y location of the pivot point. 13578 * @see #getRotation() 13579 * @see #getScaleX() 13580 * @see #getScaleY() 13581 * @see #getPivotY() 13582 * 13583 * @attr ref android.R.styleable#View_transformPivotY 13584 */ 13585 public void setPivotY(float pivotY) { 13586 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 13587 invalidateViewProperty(true, false); 13588 mRenderNode.setPivotY(pivotY); 13589 invalidateViewProperty(false, true); 13590 13591 invalidateParentIfNeededAndWasQuickRejected(); 13592 } 13593 } 13594 13595 /** 13596 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 13597 * completely transparent and 1 means the view is completely opaque. 13598 * 13599 * <p>By default this is 1.0f. 13600 * @return The opacity of the view. 13601 */ 13602 @ViewDebug.ExportedProperty(category = "drawing") 13603 public float getAlpha() { 13604 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 13605 } 13606 13607 /** 13608 * Sets the behavior for overlapping rendering for this view (see {@link 13609 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 13610 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 13611 * providing the value which is then used internally. That is, when {@link 13612 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 13613 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 13614 * instead. 13615 * 13616 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 13617 * instead of that returned by {@link #hasOverlappingRendering()}. 13618 * 13619 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 13620 */ 13621 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 13622 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 13623 if (hasOverlappingRendering) { 13624 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 13625 } else { 13626 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 13627 } 13628 } 13629 13630 /** 13631 * Returns the value for overlapping rendering that is used internally. This is either 13632 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 13633 * the return value of {@link #hasOverlappingRendering()}, otherwise. 13634 * 13635 * @return The value for overlapping rendering being used internally. 13636 */ 13637 public final boolean getHasOverlappingRendering() { 13638 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 13639 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 13640 hasOverlappingRendering(); 13641 } 13642 13643 /** 13644 * Returns whether this View has content which overlaps. 13645 * 13646 * <p>This function, intended to be overridden by specific View types, is an optimization when 13647 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 13648 * an offscreen buffer and then composited into place, which can be expensive. If the view has 13649 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 13650 * directly. An example of overlapping rendering is a TextView with a background image, such as 13651 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 13652 * ImageView with only the foreground image. The default implementation returns true; subclasses 13653 * should override if they have cases which can be optimized.</p> 13654 * 13655 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 13656 * necessitates that a View return true if it uses the methods internally without passing the 13657 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 13658 * 13659 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 13660 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 13661 * 13662 * @return true if the content in this view might overlap, false otherwise. 13663 */ 13664 @ViewDebug.ExportedProperty(category = "drawing") 13665 public boolean hasOverlappingRendering() { 13666 return true; 13667 } 13668 13669 /** 13670 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 13671 * completely transparent and 1 means the view is completely opaque. 13672 * 13673 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 13674 * can have significant performance implications, especially for large views. It is best to use 13675 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 13676 * 13677 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 13678 * strongly recommended for performance reasons to either override 13679 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 13680 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 13681 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 13682 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 13683 * of rendering cost, even for simple or small views. Starting with 13684 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 13685 * applied to the view at the rendering level.</p> 13686 * 13687 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 13688 * responsible for applying the opacity itself.</p> 13689 * 13690 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 13691 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 13692 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 13693 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 13694 * 13695 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 13696 * value will clip a View to its bounds, unless the View returns <code>false</code> from 13697 * {@link #hasOverlappingRendering}.</p> 13698 * 13699 * @param alpha The opacity of the view. 13700 * 13701 * @see #hasOverlappingRendering() 13702 * @see #setLayerType(int, android.graphics.Paint) 13703 * 13704 * @attr ref android.R.styleable#View_alpha 13705 */ 13706 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 13707 ensureTransformationInfo(); 13708 if (mTransformationInfo.mAlpha != alpha) { 13709 // Report visibility changes, which can affect children, to accessibility 13710 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 13711 notifySubtreeAccessibilityStateChangedIfNeeded(); 13712 } 13713 mTransformationInfo.mAlpha = alpha; 13714 if (onSetAlpha((int) (alpha * 255))) { 13715 mPrivateFlags |= PFLAG_ALPHA_SET; 13716 // subclass is handling alpha - don't optimize rendering cache invalidation 13717 invalidateParentCaches(); 13718 invalidate(true); 13719 } else { 13720 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13721 invalidateViewProperty(true, false); 13722 mRenderNode.setAlpha(getFinalAlpha()); 13723 } 13724 } 13725 } 13726 13727 /** 13728 * Faster version of setAlpha() which performs the same steps except there are 13729 * no calls to invalidate(). The caller of this function should perform proper invalidation 13730 * on the parent and this object. The return value indicates whether the subclass handles 13731 * alpha (the return value for onSetAlpha()). 13732 * 13733 * @param alpha The new value for the alpha property 13734 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 13735 * the new value for the alpha property is different from the old value 13736 */ 13737 boolean setAlphaNoInvalidation(float alpha) { 13738 ensureTransformationInfo(); 13739 if (mTransformationInfo.mAlpha != alpha) { 13740 mTransformationInfo.mAlpha = alpha; 13741 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 13742 if (subclassHandlesAlpha) { 13743 mPrivateFlags |= PFLAG_ALPHA_SET; 13744 return true; 13745 } else { 13746 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13747 mRenderNode.setAlpha(getFinalAlpha()); 13748 } 13749 } 13750 return false; 13751 } 13752 13753 /** 13754 * This property is hidden and intended only for use by the Fade transition, which 13755 * animates it to produce a visual translucency that does not side-effect (or get 13756 * affected by) the real alpha property. This value is composited with the other 13757 * alpha value (and the AlphaAnimation value, when that is present) to produce 13758 * a final visual translucency result, which is what is passed into the DisplayList. 13759 * 13760 * @hide 13761 */ 13762 public void setTransitionAlpha(float alpha) { 13763 ensureTransformationInfo(); 13764 if (mTransformationInfo.mTransitionAlpha != alpha) { 13765 mTransformationInfo.mTransitionAlpha = alpha; 13766 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13767 invalidateViewProperty(true, false); 13768 mRenderNode.setAlpha(getFinalAlpha()); 13769 } 13770 } 13771 13772 /** 13773 * Calculates the visual alpha of this view, which is a combination of the actual 13774 * alpha value and the transitionAlpha value (if set). 13775 */ 13776 private float getFinalAlpha() { 13777 if (mTransformationInfo != null) { 13778 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 13779 } 13780 return 1; 13781 } 13782 13783 /** 13784 * This property is hidden and intended only for use by the Fade transition, which 13785 * animates it to produce a visual translucency that does not side-effect (or get 13786 * affected by) the real alpha property. This value is composited with the other 13787 * alpha value (and the AlphaAnimation value, when that is present) to produce 13788 * a final visual translucency result, which is what is passed into the DisplayList. 13789 * 13790 * @hide 13791 */ 13792 @ViewDebug.ExportedProperty(category = "drawing") 13793 public float getTransitionAlpha() { 13794 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 13795 } 13796 13797 /** 13798 * Top position of this view relative to its parent. 13799 * 13800 * @return The top of this view, in pixels. 13801 */ 13802 @ViewDebug.CapturedViewProperty 13803 public final int getTop() { 13804 return mTop; 13805 } 13806 13807 /** 13808 * Sets the top position of this view relative to its parent. This method is meant to be called 13809 * by the layout system and should not generally be called otherwise, because the property 13810 * may be changed at any time by the layout. 13811 * 13812 * @param top The top of this view, in pixels. 13813 */ 13814 public final void setTop(int top) { 13815 if (top != mTop) { 13816 final boolean matrixIsIdentity = hasIdentityMatrix(); 13817 if (matrixIsIdentity) { 13818 if (mAttachInfo != null) { 13819 int minTop; 13820 int yLoc; 13821 if (top < mTop) { 13822 minTop = top; 13823 yLoc = top - mTop; 13824 } else { 13825 minTop = mTop; 13826 yLoc = 0; 13827 } 13828 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 13829 } 13830 } else { 13831 // Double-invalidation is necessary to capture view's old and new areas 13832 invalidate(true); 13833 } 13834 13835 int width = mRight - mLeft; 13836 int oldHeight = mBottom - mTop; 13837 13838 mTop = top; 13839 mRenderNode.setTop(mTop); 13840 13841 sizeChange(width, mBottom - mTop, width, oldHeight); 13842 13843 if (!matrixIsIdentity) { 13844 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13845 invalidate(true); 13846 } 13847 mBackgroundSizeChanged = true; 13848 if (mForegroundInfo != null) { 13849 mForegroundInfo.mBoundsChanged = true; 13850 } 13851 invalidateParentIfNeeded(); 13852 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13853 // View was rejected last time it was drawn by its parent; this may have changed 13854 invalidateParentIfNeeded(); 13855 } 13856 } 13857 } 13858 13859 /** 13860 * Bottom position of this view relative to its parent. 13861 * 13862 * @return The bottom of this view, in pixels. 13863 */ 13864 @ViewDebug.CapturedViewProperty 13865 public final int getBottom() { 13866 return mBottom; 13867 } 13868 13869 /** 13870 * True if this view has changed since the last time being drawn. 13871 * 13872 * @return The dirty state of this view. 13873 */ 13874 public boolean isDirty() { 13875 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 13876 } 13877 13878 /** 13879 * Sets the bottom position of this view relative to its parent. This method is meant to be 13880 * called by the layout system and should not generally be called otherwise, because the 13881 * property may be changed at any time by the layout. 13882 * 13883 * @param bottom The bottom of this view, in pixels. 13884 */ 13885 public final void setBottom(int bottom) { 13886 if (bottom != mBottom) { 13887 final boolean matrixIsIdentity = hasIdentityMatrix(); 13888 if (matrixIsIdentity) { 13889 if (mAttachInfo != null) { 13890 int maxBottom; 13891 if (bottom < mBottom) { 13892 maxBottom = mBottom; 13893 } else { 13894 maxBottom = bottom; 13895 } 13896 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 13897 } 13898 } else { 13899 // Double-invalidation is necessary to capture view's old and new areas 13900 invalidate(true); 13901 } 13902 13903 int width = mRight - mLeft; 13904 int oldHeight = mBottom - mTop; 13905 13906 mBottom = bottom; 13907 mRenderNode.setBottom(mBottom); 13908 13909 sizeChange(width, mBottom - mTop, width, oldHeight); 13910 13911 if (!matrixIsIdentity) { 13912 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13913 invalidate(true); 13914 } 13915 mBackgroundSizeChanged = true; 13916 if (mForegroundInfo != null) { 13917 mForegroundInfo.mBoundsChanged = true; 13918 } 13919 invalidateParentIfNeeded(); 13920 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13921 // View was rejected last time it was drawn by its parent; this may have changed 13922 invalidateParentIfNeeded(); 13923 } 13924 } 13925 } 13926 13927 /** 13928 * Left position of this view relative to its parent. 13929 * 13930 * @return The left edge of this view, in pixels. 13931 */ 13932 @ViewDebug.CapturedViewProperty 13933 public final int getLeft() { 13934 return mLeft; 13935 } 13936 13937 /** 13938 * Sets the left position of this view relative to its parent. This method is meant to be called 13939 * by the layout system and should not generally be called otherwise, because the property 13940 * may be changed at any time by the layout. 13941 * 13942 * @param left The left of this view, in pixels. 13943 */ 13944 public final void setLeft(int left) { 13945 if (left != mLeft) { 13946 final boolean matrixIsIdentity = hasIdentityMatrix(); 13947 if (matrixIsIdentity) { 13948 if (mAttachInfo != null) { 13949 int minLeft; 13950 int xLoc; 13951 if (left < mLeft) { 13952 minLeft = left; 13953 xLoc = left - mLeft; 13954 } else { 13955 minLeft = mLeft; 13956 xLoc = 0; 13957 } 13958 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 13959 } 13960 } else { 13961 // Double-invalidation is necessary to capture view's old and new areas 13962 invalidate(true); 13963 } 13964 13965 int oldWidth = mRight - mLeft; 13966 int height = mBottom - mTop; 13967 13968 mLeft = left; 13969 mRenderNode.setLeft(left); 13970 13971 sizeChange(mRight - mLeft, height, oldWidth, height); 13972 13973 if (!matrixIsIdentity) { 13974 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13975 invalidate(true); 13976 } 13977 mBackgroundSizeChanged = true; 13978 if (mForegroundInfo != null) { 13979 mForegroundInfo.mBoundsChanged = true; 13980 } 13981 invalidateParentIfNeeded(); 13982 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13983 // View was rejected last time it was drawn by its parent; this may have changed 13984 invalidateParentIfNeeded(); 13985 } 13986 } 13987 } 13988 13989 /** 13990 * Right position of this view relative to its parent. 13991 * 13992 * @return The right edge of this view, in pixels. 13993 */ 13994 @ViewDebug.CapturedViewProperty 13995 public final int getRight() { 13996 return mRight; 13997 } 13998 13999 /** 14000 * Sets the right position of this view relative to its parent. This method is meant to be called 14001 * by the layout system and should not generally be called otherwise, because the property 14002 * may be changed at any time by the layout. 14003 * 14004 * @param right The right of this view, in pixels. 14005 */ 14006 public final void setRight(int right) { 14007 if (right != mRight) { 14008 final boolean matrixIsIdentity = hasIdentityMatrix(); 14009 if (matrixIsIdentity) { 14010 if (mAttachInfo != null) { 14011 int maxRight; 14012 if (right < mRight) { 14013 maxRight = mRight; 14014 } else { 14015 maxRight = right; 14016 } 14017 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 14018 } 14019 } else { 14020 // Double-invalidation is necessary to capture view's old and new areas 14021 invalidate(true); 14022 } 14023 14024 int oldWidth = mRight - mLeft; 14025 int height = mBottom - mTop; 14026 14027 mRight = right; 14028 mRenderNode.setRight(mRight); 14029 14030 sizeChange(mRight - mLeft, height, oldWidth, height); 14031 14032 if (!matrixIsIdentity) { 14033 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14034 invalidate(true); 14035 } 14036 mBackgroundSizeChanged = true; 14037 if (mForegroundInfo != null) { 14038 mForegroundInfo.mBoundsChanged = true; 14039 } 14040 invalidateParentIfNeeded(); 14041 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14042 // View was rejected last time it was drawn by its parent; this may have changed 14043 invalidateParentIfNeeded(); 14044 } 14045 } 14046 } 14047 14048 /** 14049 * The visual x position of this view, in pixels. This is equivalent to the 14050 * {@link #setTranslationX(float) translationX} property plus the current 14051 * {@link #getLeft() left} property. 14052 * 14053 * @return The visual x position of this view, in pixels. 14054 */ 14055 @ViewDebug.ExportedProperty(category = "drawing") 14056 public float getX() { 14057 return mLeft + getTranslationX(); 14058 } 14059 14060 /** 14061 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 14062 * {@link #setTranslationX(float) translationX} property to be the difference between 14063 * the x value passed in and the current {@link #getLeft() left} property. 14064 * 14065 * @param x The visual x position of this view, in pixels. 14066 */ 14067 public void setX(float x) { 14068 setTranslationX(x - mLeft); 14069 } 14070 14071 /** 14072 * The visual y position of this view, in pixels. This is equivalent to the 14073 * {@link #setTranslationY(float) translationY} property plus the current 14074 * {@link #getTop() top} property. 14075 * 14076 * @return The visual y position of this view, in pixels. 14077 */ 14078 @ViewDebug.ExportedProperty(category = "drawing") 14079 public float getY() { 14080 return mTop + getTranslationY(); 14081 } 14082 14083 /** 14084 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 14085 * {@link #setTranslationY(float) translationY} property to be the difference between 14086 * the y value passed in and the current {@link #getTop() top} property. 14087 * 14088 * @param y The visual y position of this view, in pixels. 14089 */ 14090 public void setY(float y) { 14091 setTranslationY(y - mTop); 14092 } 14093 14094 /** 14095 * The visual z position of this view, in pixels. This is equivalent to the 14096 * {@link #setTranslationZ(float) translationZ} property plus the current 14097 * {@link #getElevation() elevation} property. 14098 * 14099 * @return The visual z position of this view, in pixels. 14100 */ 14101 @ViewDebug.ExportedProperty(category = "drawing") 14102 public float getZ() { 14103 return getElevation() + getTranslationZ(); 14104 } 14105 14106 /** 14107 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 14108 * {@link #setTranslationZ(float) translationZ} property to be the difference between 14109 * the x value passed in and the current {@link #getElevation() elevation} property. 14110 * 14111 * @param z The visual z position of this view, in pixels. 14112 */ 14113 public void setZ(float z) { 14114 setTranslationZ(z - getElevation()); 14115 } 14116 14117 /** 14118 * The base elevation of this view relative to its parent, in pixels. 14119 * 14120 * @return The base depth position of the view, in pixels. 14121 */ 14122 @ViewDebug.ExportedProperty(category = "drawing") 14123 public float getElevation() { 14124 return mRenderNode.getElevation(); 14125 } 14126 14127 /** 14128 * Sets the base elevation of this view, in pixels. 14129 * 14130 * @attr ref android.R.styleable#View_elevation 14131 */ 14132 public void setElevation(float elevation) { 14133 if (elevation != getElevation()) { 14134 invalidateViewProperty(true, false); 14135 mRenderNode.setElevation(elevation); 14136 invalidateViewProperty(false, true); 14137 14138 invalidateParentIfNeededAndWasQuickRejected(); 14139 } 14140 } 14141 14142 /** 14143 * The horizontal location of this view relative to its {@link #getLeft() left} position. 14144 * This position is post-layout, in addition to wherever the object's 14145 * layout placed it. 14146 * 14147 * @return The horizontal position of this view relative to its left position, in pixels. 14148 */ 14149 @ViewDebug.ExportedProperty(category = "drawing") 14150 public float getTranslationX() { 14151 return mRenderNode.getTranslationX(); 14152 } 14153 14154 /** 14155 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 14156 * This effectively positions the object post-layout, in addition to wherever the object's 14157 * layout placed it. 14158 * 14159 * @param translationX The horizontal position of this view relative to its left position, 14160 * in pixels. 14161 * 14162 * @attr ref android.R.styleable#View_translationX 14163 */ 14164 public void setTranslationX(float translationX) { 14165 if (translationX != getTranslationX()) { 14166 invalidateViewProperty(true, false); 14167 mRenderNode.setTranslationX(translationX); 14168 invalidateViewProperty(false, true); 14169 14170 invalidateParentIfNeededAndWasQuickRejected(); 14171 notifySubtreeAccessibilityStateChangedIfNeeded(); 14172 } 14173 } 14174 14175 /** 14176 * The vertical location of this view relative to its {@link #getTop() top} position. 14177 * This position is post-layout, in addition to wherever the object's 14178 * layout placed it. 14179 * 14180 * @return The vertical position of this view relative to its top position, 14181 * in pixels. 14182 */ 14183 @ViewDebug.ExportedProperty(category = "drawing") 14184 public float getTranslationY() { 14185 return mRenderNode.getTranslationY(); 14186 } 14187 14188 /** 14189 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 14190 * This effectively positions the object post-layout, in addition to wherever the object's 14191 * layout placed it. 14192 * 14193 * @param translationY The vertical position of this view relative to its top position, 14194 * in pixels. 14195 * 14196 * @attr ref android.R.styleable#View_translationY 14197 */ 14198 public void setTranslationY(float translationY) { 14199 if (translationY != getTranslationY()) { 14200 invalidateViewProperty(true, false); 14201 mRenderNode.setTranslationY(translationY); 14202 invalidateViewProperty(false, true); 14203 14204 invalidateParentIfNeededAndWasQuickRejected(); 14205 notifySubtreeAccessibilityStateChangedIfNeeded(); 14206 } 14207 } 14208 14209 /** 14210 * The depth location of this view relative to its {@link #getElevation() elevation}. 14211 * 14212 * @return The depth of this view relative to its elevation. 14213 */ 14214 @ViewDebug.ExportedProperty(category = "drawing") 14215 public float getTranslationZ() { 14216 return mRenderNode.getTranslationZ(); 14217 } 14218 14219 /** 14220 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 14221 * 14222 * @attr ref android.R.styleable#View_translationZ 14223 */ 14224 public void setTranslationZ(float translationZ) { 14225 if (translationZ != getTranslationZ()) { 14226 invalidateViewProperty(true, false); 14227 mRenderNode.setTranslationZ(translationZ); 14228 invalidateViewProperty(false, true); 14229 14230 invalidateParentIfNeededAndWasQuickRejected(); 14231 } 14232 } 14233 14234 /** @hide */ 14235 public void setAnimationMatrix(Matrix matrix) { 14236 invalidateViewProperty(true, false); 14237 mRenderNode.setAnimationMatrix(matrix); 14238 invalidateViewProperty(false, true); 14239 14240 invalidateParentIfNeededAndWasQuickRejected(); 14241 } 14242 14243 /** 14244 * Returns the current StateListAnimator if exists. 14245 * 14246 * @return StateListAnimator or null if it does not exists 14247 * @see #setStateListAnimator(android.animation.StateListAnimator) 14248 */ 14249 public StateListAnimator getStateListAnimator() { 14250 return mStateListAnimator; 14251 } 14252 14253 /** 14254 * Attaches the provided StateListAnimator to this View. 14255 * <p> 14256 * Any previously attached StateListAnimator will be detached. 14257 * 14258 * @param stateListAnimator The StateListAnimator to update the view 14259 * @see android.animation.StateListAnimator 14260 */ 14261 public void setStateListAnimator(StateListAnimator stateListAnimator) { 14262 if (mStateListAnimator == stateListAnimator) { 14263 return; 14264 } 14265 if (mStateListAnimator != null) { 14266 mStateListAnimator.setTarget(null); 14267 } 14268 mStateListAnimator = stateListAnimator; 14269 if (stateListAnimator != null) { 14270 stateListAnimator.setTarget(this); 14271 if (isAttachedToWindow()) { 14272 stateListAnimator.setState(getDrawableState()); 14273 } 14274 } 14275 } 14276 14277 /** 14278 * Returns whether the Outline should be used to clip the contents of the View. 14279 * <p> 14280 * Note that this flag will only be respected if the View's Outline returns true from 14281 * {@link Outline#canClip()}. 14282 * 14283 * @see #setOutlineProvider(ViewOutlineProvider) 14284 * @see #setClipToOutline(boolean) 14285 */ 14286 public final boolean getClipToOutline() { 14287 return mRenderNode.getClipToOutline(); 14288 } 14289 14290 /** 14291 * Sets whether the View's Outline should be used to clip the contents of the View. 14292 * <p> 14293 * Only a single non-rectangular clip can be applied on a View at any time. 14294 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 14295 * circular reveal} animation take priority over Outline clipping, and 14296 * child Outline clipping takes priority over Outline clipping done by a 14297 * parent. 14298 * <p> 14299 * Note that this flag will only be respected if the View's Outline returns true from 14300 * {@link Outline#canClip()}. 14301 * 14302 * @see #setOutlineProvider(ViewOutlineProvider) 14303 * @see #getClipToOutline() 14304 */ 14305 public void setClipToOutline(boolean clipToOutline) { 14306 damageInParent(); 14307 if (getClipToOutline() != clipToOutline) { 14308 mRenderNode.setClipToOutline(clipToOutline); 14309 } 14310 } 14311 14312 // correspond to the enum values of View_outlineProvider 14313 private static final int PROVIDER_BACKGROUND = 0; 14314 private static final int PROVIDER_NONE = 1; 14315 private static final int PROVIDER_BOUNDS = 2; 14316 private static final int PROVIDER_PADDED_BOUNDS = 3; 14317 private void setOutlineProviderFromAttribute(int providerInt) { 14318 switch (providerInt) { 14319 case PROVIDER_BACKGROUND: 14320 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 14321 break; 14322 case PROVIDER_NONE: 14323 setOutlineProvider(null); 14324 break; 14325 case PROVIDER_BOUNDS: 14326 setOutlineProvider(ViewOutlineProvider.BOUNDS); 14327 break; 14328 case PROVIDER_PADDED_BOUNDS: 14329 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 14330 break; 14331 } 14332 } 14333 14334 /** 14335 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 14336 * the shape of the shadow it casts, and enables outline clipping. 14337 * <p> 14338 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 14339 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 14340 * outline provider with this method allows this behavior to be overridden. 14341 * <p> 14342 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 14343 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 14344 * <p> 14345 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 14346 * 14347 * @see #setClipToOutline(boolean) 14348 * @see #getClipToOutline() 14349 * @see #getOutlineProvider() 14350 */ 14351 public void setOutlineProvider(ViewOutlineProvider provider) { 14352 mOutlineProvider = provider; 14353 invalidateOutline(); 14354 } 14355 14356 /** 14357 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 14358 * that defines the shape of the shadow it casts, and enables outline clipping. 14359 * 14360 * @see #setOutlineProvider(ViewOutlineProvider) 14361 */ 14362 public ViewOutlineProvider getOutlineProvider() { 14363 return mOutlineProvider; 14364 } 14365 14366 /** 14367 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 14368 * 14369 * @see #setOutlineProvider(ViewOutlineProvider) 14370 */ 14371 public void invalidateOutline() { 14372 rebuildOutline(); 14373 14374 notifySubtreeAccessibilityStateChangedIfNeeded(); 14375 invalidateViewProperty(false, false); 14376 } 14377 14378 /** 14379 * Internal version of {@link #invalidateOutline()} which invalidates the 14380 * outline without invalidating the view itself. This is intended to be called from 14381 * within methods in the View class itself which are the result of the view being 14382 * invalidated already. For example, when we are drawing the background of a View, 14383 * we invalidate the outline in case it changed in the meantime, but we do not 14384 * need to invalidate the view because we're already drawing the background as part 14385 * of drawing the view in response to an earlier invalidation of the view. 14386 */ 14387 private void rebuildOutline() { 14388 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 14389 if (mAttachInfo == null) return; 14390 14391 if (mOutlineProvider == null) { 14392 // no provider, remove outline 14393 mRenderNode.setOutline(null); 14394 } else { 14395 final Outline outline = mAttachInfo.mTmpOutline; 14396 outline.setEmpty(); 14397 outline.setAlpha(1.0f); 14398 14399 mOutlineProvider.getOutline(this, outline); 14400 mRenderNode.setOutline(outline); 14401 } 14402 } 14403 14404 /** 14405 * HierarchyViewer only 14406 * 14407 * @hide 14408 */ 14409 @ViewDebug.ExportedProperty(category = "drawing") 14410 public boolean hasShadow() { 14411 return mRenderNode.hasShadow(); 14412 } 14413 14414 14415 /** @hide */ 14416 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 14417 mRenderNode.setRevealClip(shouldClip, x, y, radius); 14418 invalidateViewProperty(false, false); 14419 } 14420 14421 /** 14422 * Hit rectangle in parent's coordinates 14423 * 14424 * @param outRect The hit rectangle of the view. 14425 */ 14426 public void getHitRect(Rect outRect) { 14427 if (hasIdentityMatrix() || mAttachInfo == null) { 14428 outRect.set(mLeft, mTop, mRight, mBottom); 14429 } else { 14430 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 14431 tmpRect.set(0, 0, getWidth(), getHeight()); 14432 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 14433 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 14434 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 14435 } 14436 } 14437 14438 /** 14439 * Determines whether the given point, in local coordinates is inside the view. 14440 */ 14441 /*package*/ final boolean pointInView(float localX, float localY) { 14442 return pointInView(localX, localY, 0); 14443 } 14444 14445 /** 14446 * Utility method to determine whether the given point, in local coordinates, 14447 * is inside the view, where the area of the view is expanded by the slop factor. 14448 * This method is called while processing touch-move events to determine if the event 14449 * is still within the view. 14450 * 14451 * @hide 14452 */ 14453 public boolean pointInView(float localX, float localY, float slop) { 14454 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 14455 localY < ((mBottom - mTop) + slop); 14456 } 14457 14458 /** 14459 * When a view has focus and the user navigates away from it, the next view is searched for 14460 * starting from the rectangle filled in by this method. 14461 * 14462 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 14463 * of the view. However, if your view maintains some idea of internal selection, 14464 * such as a cursor, or a selected row or column, you should override this method and 14465 * fill in a more specific rectangle. 14466 * 14467 * @param r The rectangle to fill in, in this view's coordinates. 14468 */ 14469 public void getFocusedRect(Rect r) { 14470 getDrawingRect(r); 14471 } 14472 14473 /** 14474 * If some part of this view is not clipped by any of its parents, then 14475 * return that area in r in global (root) coordinates. To convert r to local 14476 * coordinates (without taking possible View rotations into account), offset 14477 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 14478 * If the view is completely clipped or translated out, return false. 14479 * 14480 * @param r If true is returned, r holds the global coordinates of the 14481 * visible portion of this view. 14482 * @param globalOffset If true is returned, globalOffset holds the dx,dy 14483 * between this view and its root. globalOffet may be null. 14484 * @return true if r is non-empty (i.e. part of the view is visible at the 14485 * root level. 14486 */ 14487 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 14488 int width = mRight - mLeft; 14489 int height = mBottom - mTop; 14490 if (width > 0 && height > 0) { 14491 r.set(0, 0, width, height); 14492 if (globalOffset != null) { 14493 globalOffset.set(-mScrollX, -mScrollY); 14494 } 14495 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 14496 } 14497 return false; 14498 } 14499 14500 public final boolean getGlobalVisibleRect(Rect r) { 14501 return getGlobalVisibleRect(r, null); 14502 } 14503 14504 public final boolean getLocalVisibleRect(Rect r) { 14505 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 14506 if (getGlobalVisibleRect(r, offset)) { 14507 r.offset(-offset.x, -offset.y); // make r local 14508 return true; 14509 } 14510 return false; 14511 } 14512 14513 /** 14514 * Offset this view's vertical location by the specified number of pixels. 14515 * 14516 * @param offset the number of pixels to offset the view by 14517 */ 14518 public void offsetTopAndBottom(int offset) { 14519 if (offset != 0) { 14520 final boolean matrixIsIdentity = hasIdentityMatrix(); 14521 if (matrixIsIdentity) { 14522 if (isHardwareAccelerated()) { 14523 invalidateViewProperty(false, false); 14524 } else { 14525 final ViewParent p = mParent; 14526 if (p != null && mAttachInfo != null) { 14527 final Rect r = mAttachInfo.mTmpInvalRect; 14528 int minTop; 14529 int maxBottom; 14530 int yLoc; 14531 if (offset < 0) { 14532 minTop = mTop + offset; 14533 maxBottom = mBottom; 14534 yLoc = offset; 14535 } else { 14536 minTop = mTop; 14537 maxBottom = mBottom + offset; 14538 yLoc = 0; 14539 } 14540 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 14541 p.invalidateChild(this, r); 14542 } 14543 } 14544 } else { 14545 invalidateViewProperty(false, false); 14546 } 14547 14548 mTop += offset; 14549 mBottom += offset; 14550 mRenderNode.offsetTopAndBottom(offset); 14551 if (isHardwareAccelerated()) { 14552 invalidateViewProperty(false, false); 14553 invalidateParentIfNeededAndWasQuickRejected(); 14554 } else { 14555 if (!matrixIsIdentity) { 14556 invalidateViewProperty(false, true); 14557 } 14558 invalidateParentIfNeeded(); 14559 } 14560 notifySubtreeAccessibilityStateChangedIfNeeded(); 14561 } 14562 } 14563 14564 /** 14565 * Offset this view's horizontal location by the specified amount of pixels. 14566 * 14567 * @param offset the number of pixels to offset the view by 14568 */ 14569 public void offsetLeftAndRight(int offset) { 14570 if (offset != 0) { 14571 final boolean matrixIsIdentity = hasIdentityMatrix(); 14572 if (matrixIsIdentity) { 14573 if (isHardwareAccelerated()) { 14574 invalidateViewProperty(false, false); 14575 } else { 14576 final ViewParent p = mParent; 14577 if (p != null && mAttachInfo != null) { 14578 final Rect r = mAttachInfo.mTmpInvalRect; 14579 int minLeft; 14580 int maxRight; 14581 if (offset < 0) { 14582 minLeft = mLeft + offset; 14583 maxRight = mRight; 14584 } else { 14585 minLeft = mLeft; 14586 maxRight = mRight + offset; 14587 } 14588 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 14589 p.invalidateChild(this, r); 14590 } 14591 } 14592 } else { 14593 invalidateViewProperty(false, false); 14594 } 14595 14596 mLeft += offset; 14597 mRight += offset; 14598 mRenderNode.offsetLeftAndRight(offset); 14599 if (isHardwareAccelerated()) { 14600 invalidateViewProperty(false, false); 14601 invalidateParentIfNeededAndWasQuickRejected(); 14602 } else { 14603 if (!matrixIsIdentity) { 14604 invalidateViewProperty(false, true); 14605 } 14606 invalidateParentIfNeeded(); 14607 } 14608 notifySubtreeAccessibilityStateChangedIfNeeded(); 14609 } 14610 } 14611 14612 /** 14613 * Get the LayoutParams associated with this view. All views should have 14614 * layout parameters. These supply parameters to the <i>parent</i> of this 14615 * view specifying how it should be arranged. There are many subclasses of 14616 * ViewGroup.LayoutParams, and these correspond to the different subclasses 14617 * of ViewGroup that are responsible for arranging their children. 14618 * 14619 * This method may return null if this View is not attached to a parent 14620 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 14621 * was not invoked successfully. When a View is attached to a parent 14622 * ViewGroup, this method must not return null. 14623 * 14624 * @return The LayoutParams associated with this view, or null if no 14625 * parameters have been set yet 14626 */ 14627 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 14628 public ViewGroup.LayoutParams getLayoutParams() { 14629 return mLayoutParams; 14630 } 14631 14632 /** 14633 * Set the layout parameters associated with this view. These supply 14634 * parameters to the <i>parent</i> of this view specifying how it should be 14635 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 14636 * correspond to the different subclasses of ViewGroup that are responsible 14637 * for arranging their children. 14638 * 14639 * @param params The layout parameters for this view, cannot be null 14640 */ 14641 public void setLayoutParams(ViewGroup.LayoutParams params) { 14642 if (params == null) { 14643 throw new NullPointerException("Layout parameters cannot be null"); 14644 } 14645 mLayoutParams = params; 14646 resolveLayoutParams(); 14647 if (mParent instanceof ViewGroup) { 14648 ((ViewGroup) mParent).onSetLayoutParams(this, params); 14649 } 14650 requestLayout(); 14651 } 14652 14653 /** 14654 * Resolve the layout parameters depending on the resolved layout direction 14655 * 14656 * @hide 14657 */ 14658 public void resolveLayoutParams() { 14659 if (mLayoutParams != null) { 14660 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 14661 } 14662 } 14663 14664 /** 14665 * Set the scrolled position of your view. This will cause a call to 14666 * {@link #onScrollChanged(int, int, int, int)} and the view will be 14667 * invalidated. 14668 * @param x the x position to scroll to 14669 * @param y the y position to scroll to 14670 */ 14671 public void scrollTo(int x, int y) { 14672 if (mScrollX != x || mScrollY != y) { 14673 int oldX = mScrollX; 14674 int oldY = mScrollY; 14675 mScrollX = x; 14676 mScrollY = y; 14677 invalidateParentCaches(); 14678 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 14679 if (!awakenScrollBars()) { 14680 postInvalidateOnAnimation(); 14681 } 14682 } 14683 } 14684 14685 /** 14686 * Move the scrolled position of your view. This will cause a call to 14687 * {@link #onScrollChanged(int, int, int, int)} and the view will be 14688 * invalidated. 14689 * @param x the amount of pixels to scroll by horizontally 14690 * @param y the amount of pixels to scroll by vertically 14691 */ 14692 public void scrollBy(int x, int y) { 14693 scrollTo(mScrollX + x, mScrollY + y); 14694 } 14695 14696 /** 14697 * <p>Trigger the scrollbars to draw. When invoked this method starts an 14698 * animation to fade the scrollbars out after a default delay. If a subclass 14699 * provides animated scrolling, the start delay should equal the duration 14700 * of the scrolling animation.</p> 14701 * 14702 * <p>The animation starts only if at least one of the scrollbars is 14703 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 14704 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14705 * this method returns true, and false otherwise. If the animation is 14706 * started, this method calls {@link #invalidate()}; in that case the 14707 * caller should not call {@link #invalidate()}.</p> 14708 * 14709 * <p>This method should be invoked every time a subclass directly updates 14710 * the scroll parameters.</p> 14711 * 14712 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 14713 * and {@link #scrollTo(int, int)}.</p> 14714 * 14715 * @return true if the animation is played, false otherwise 14716 * 14717 * @see #awakenScrollBars(int) 14718 * @see #scrollBy(int, int) 14719 * @see #scrollTo(int, int) 14720 * @see #isHorizontalScrollBarEnabled() 14721 * @see #isVerticalScrollBarEnabled() 14722 * @see #setHorizontalScrollBarEnabled(boolean) 14723 * @see #setVerticalScrollBarEnabled(boolean) 14724 */ 14725 protected boolean awakenScrollBars() { 14726 return mScrollCache != null && 14727 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 14728 } 14729 14730 /** 14731 * Trigger the scrollbars to draw. 14732 * This method differs from awakenScrollBars() only in its default duration. 14733 * initialAwakenScrollBars() will show the scroll bars for longer than 14734 * usual to give the user more of a chance to notice them. 14735 * 14736 * @return true if the animation is played, false otherwise. 14737 */ 14738 private boolean initialAwakenScrollBars() { 14739 return mScrollCache != null && 14740 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 14741 } 14742 14743 /** 14744 * <p> 14745 * Trigger the scrollbars to draw. When invoked this method starts an 14746 * animation to fade the scrollbars out after a fixed delay. If a subclass 14747 * provides animated scrolling, the start delay should equal the duration of 14748 * the scrolling animation. 14749 * </p> 14750 * 14751 * <p> 14752 * The animation starts only if at least one of the scrollbars is enabled, 14753 * as specified by {@link #isHorizontalScrollBarEnabled()} and 14754 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14755 * this method returns true, and false otherwise. If the animation is 14756 * started, this method calls {@link #invalidate()}; in that case the caller 14757 * should not call {@link #invalidate()}. 14758 * </p> 14759 * 14760 * <p> 14761 * This method should be invoked every time a subclass directly updates the 14762 * scroll parameters. 14763 * </p> 14764 * 14765 * @param startDelay the delay, in milliseconds, after which the animation 14766 * should start; when the delay is 0, the animation starts 14767 * immediately 14768 * @return true if the animation is played, false otherwise 14769 * 14770 * @see #scrollBy(int, int) 14771 * @see #scrollTo(int, int) 14772 * @see #isHorizontalScrollBarEnabled() 14773 * @see #isVerticalScrollBarEnabled() 14774 * @see #setHorizontalScrollBarEnabled(boolean) 14775 * @see #setVerticalScrollBarEnabled(boolean) 14776 */ 14777 protected boolean awakenScrollBars(int startDelay) { 14778 return awakenScrollBars(startDelay, true); 14779 } 14780 14781 /** 14782 * <p> 14783 * Trigger the scrollbars to draw. When invoked this method starts an 14784 * animation to fade the scrollbars out after a fixed delay. If a subclass 14785 * provides animated scrolling, the start delay should equal the duration of 14786 * the scrolling animation. 14787 * </p> 14788 * 14789 * <p> 14790 * The animation starts only if at least one of the scrollbars is enabled, 14791 * as specified by {@link #isHorizontalScrollBarEnabled()} and 14792 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14793 * this method returns true, and false otherwise. If the animation is 14794 * started, this method calls {@link #invalidate()} if the invalidate parameter 14795 * is set to true; in that case the caller 14796 * should not call {@link #invalidate()}. 14797 * </p> 14798 * 14799 * <p> 14800 * This method should be invoked every time a subclass directly updates the 14801 * scroll parameters. 14802 * </p> 14803 * 14804 * @param startDelay the delay, in milliseconds, after which the animation 14805 * should start; when the delay is 0, the animation starts 14806 * immediately 14807 * 14808 * @param invalidate Whether this method should call invalidate 14809 * 14810 * @return true if the animation is played, false otherwise 14811 * 14812 * @see #scrollBy(int, int) 14813 * @see #scrollTo(int, int) 14814 * @see #isHorizontalScrollBarEnabled() 14815 * @see #isVerticalScrollBarEnabled() 14816 * @see #setHorizontalScrollBarEnabled(boolean) 14817 * @see #setVerticalScrollBarEnabled(boolean) 14818 */ 14819 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 14820 final ScrollabilityCache scrollCache = mScrollCache; 14821 14822 if (scrollCache == null || !scrollCache.fadeScrollBars) { 14823 return false; 14824 } 14825 14826 if (scrollCache.scrollBar == null) { 14827 scrollCache.scrollBar = new ScrollBarDrawable(); 14828 scrollCache.scrollBar.setState(getDrawableState()); 14829 scrollCache.scrollBar.setCallback(this); 14830 } 14831 14832 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 14833 14834 if (invalidate) { 14835 // Invalidate to show the scrollbars 14836 postInvalidateOnAnimation(); 14837 } 14838 14839 if (scrollCache.state == ScrollabilityCache.OFF) { 14840 // FIXME: this is copied from WindowManagerService. 14841 // We should get this value from the system when it 14842 // is possible to do so. 14843 final int KEY_REPEAT_FIRST_DELAY = 750; 14844 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 14845 } 14846 14847 // Tell mScrollCache when we should start fading. This may 14848 // extend the fade start time if one was already scheduled 14849 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 14850 scrollCache.fadeStartTime = fadeStartTime; 14851 scrollCache.state = ScrollabilityCache.ON; 14852 14853 // Schedule our fader to run, unscheduling any old ones first 14854 if (mAttachInfo != null) { 14855 mAttachInfo.mHandler.removeCallbacks(scrollCache); 14856 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 14857 } 14858 14859 return true; 14860 } 14861 14862 return false; 14863 } 14864 14865 /** 14866 * Do not invalidate views which are not visible and which are not running an animation. They 14867 * will not get drawn and they should not set dirty flags as if they will be drawn 14868 */ 14869 private boolean skipInvalidate() { 14870 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 14871 (!(mParent instanceof ViewGroup) || 14872 !((ViewGroup) mParent).isViewTransitioning(this)); 14873 } 14874 14875 /** 14876 * Mark the area defined by dirty as needing to be drawn. If the view is 14877 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14878 * point in the future. 14879 * <p> 14880 * This must be called from a UI thread. To call from a non-UI thread, call 14881 * {@link #postInvalidate()}. 14882 * <p> 14883 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 14884 * {@code dirty}. 14885 * 14886 * @param dirty the rectangle representing the bounds of the dirty region 14887 */ 14888 public void invalidate(Rect dirty) { 14889 final int scrollX = mScrollX; 14890 final int scrollY = mScrollY; 14891 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 14892 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 14893 } 14894 14895 /** 14896 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 14897 * coordinates of the dirty rect are relative to the view. If the view is 14898 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14899 * point in the future. 14900 * <p> 14901 * This must be called from a UI thread. To call from a non-UI thread, call 14902 * {@link #postInvalidate()}. 14903 * 14904 * @param l the left position of the dirty region 14905 * @param t the top position of the dirty region 14906 * @param r the right position of the dirty region 14907 * @param b the bottom position of the dirty region 14908 */ 14909 public void invalidate(int l, int t, int r, int b) { 14910 final int scrollX = mScrollX; 14911 final int scrollY = mScrollY; 14912 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 14913 } 14914 14915 /** 14916 * Invalidate the whole view. If the view is visible, 14917 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 14918 * the future. 14919 * <p> 14920 * This must be called from a UI thread. To call from a non-UI thread, call 14921 * {@link #postInvalidate()}. 14922 */ 14923 public void invalidate() { 14924 invalidate(true); 14925 } 14926 14927 /** 14928 * This is where the invalidate() work actually happens. A full invalidate() 14929 * causes the drawing cache to be invalidated, but this function can be 14930 * called with invalidateCache set to false to skip that invalidation step 14931 * for cases that do not need it (for example, a component that remains at 14932 * the same dimensions with the same content). 14933 * 14934 * @param invalidateCache Whether the drawing cache for this view should be 14935 * invalidated as well. This is usually true for a full 14936 * invalidate, but may be set to false if the View's contents or 14937 * dimensions have not changed. 14938 * @hide 14939 */ 14940 public void invalidate(boolean invalidateCache) { 14941 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 14942 } 14943 14944 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 14945 boolean fullInvalidate) { 14946 if (mGhostView != null) { 14947 mGhostView.invalidate(true); 14948 return; 14949 } 14950 14951 if (skipInvalidate()) { 14952 return; 14953 } 14954 14955 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 14956 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 14957 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 14958 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 14959 if (fullInvalidate) { 14960 mLastIsOpaque = isOpaque(); 14961 mPrivateFlags &= ~PFLAG_DRAWN; 14962 } 14963 14964 mPrivateFlags |= PFLAG_DIRTY; 14965 14966 if (invalidateCache) { 14967 mPrivateFlags |= PFLAG_INVALIDATED; 14968 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 14969 } 14970 14971 // Propagate the damage rectangle to the parent view. 14972 final AttachInfo ai = mAttachInfo; 14973 final ViewParent p = mParent; 14974 if (p != null && ai != null && l < r && t < b) { 14975 final Rect damage = ai.mTmpInvalRect; 14976 damage.set(l, t, r, b); 14977 p.invalidateChild(this, damage); 14978 } 14979 14980 // Damage the entire projection receiver, if necessary. 14981 if (mBackground != null && mBackground.isProjected()) { 14982 final View receiver = getProjectionReceiver(); 14983 if (receiver != null) { 14984 receiver.damageInParent(); 14985 } 14986 } 14987 } 14988 } 14989 14990 /** 14991 * @return this view's projection receiver, or {@code null} if none exists 14992 */ 14993 private View getProjectionReceiver() { 14994 ViewParent p = getParent(); 14995 while (p != null && p instanceof View) { 14996 final View v = (View) p; 14997 if (v.isProjectionReceiver()) { 14998 return v; 14999 } 15000 p = p.getParent(); 15001 } 15002 15003 return null; 15004 } 15005 15006 /** 15007 * @return whether the view is a projection receiver 15008 */ 15009 private boolean isProjectionReceiver() { 15010 return mBackground != null; 15011 } 15012 15013 /** 15014 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 15015 * set any flags or handle all of the cases handled by the default invalidation methods. 15016 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 15017 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 15018 * walk up the hierarchy, transforming the dirty rect as necessary. 15019 * 15020 * The method also handles normal invalidation logic if display list properties are not 15021 * being used in this view. The invalidateParent and forceRedraw flags are used by that 15022 * backup approach, to handle these cases used in the various property-setting methods. 15023 * 15024 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 15025 * are not being used in this view 15026 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 15027 * list properties are not being used in this view 15028 */ 15029 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 15030 if (!isHardwareAccelerated() 15031 || !mRenderNode.isValid() 15032 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 15033 if (invalidateParent) { 15034 invalidateParentCaches(); 15035 } 15036 if (forceRedraw) { 15037 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 15038 } 15039 invalidate(false); 15040 } else { 15041 damageInParent(); 15042 } 15043 } 15044 15045 /** 15046 * Tells the parent view to damage this view's bounds. 15047 * 15048 * @hide 15049 */ 15050 protected void damageInParent() { 15051 if (mParent != null && mAttachInfo != null) { 15052 mParent.onDescendantInvalidated(this, this); 15053 } 15054 } 15055 15056 /** 15057 * Utility method to transform a given Rect by the current matrix of this view. 15058 */ 15059 void transformRect(final Rect rect) { 15060 if (!getMatrix().isIdentity()) { 15061 RectF boundingRect = mAttachInfo.mTmpTransformRect; 15062 boundingRect.set(rect); 15063 getMatrix().mapRect(boundingRect); 15064 rect.set((int) Math.floor(boundingRect.left), 15065 (int) Math.floor(boundingRect.top), 15066 (int) Math.ceil(boundingRect.right), 15067 (int) Math.ceil(boundingRect.bottom)); 15068 } 15069 } 15070 15071 /** 15072 * Used to indicate that the parent of this view should clear its caches. This functionality 15073 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15074 * which is necessary when various parent-managed properties of the view change, such as 15075 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 15076 * clears the parent caches and does not causes an invalidate event. 15077 * 15078 * @hide 15079 */ 15080 protected void invalidateParentCaches() { 15081 if (mParent instanceof View) { 15082 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 15083 } 15084 } 15085 15086 /** 15087 * Used to indicate that the parent of this view should be invalidated. This functionality 15088 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15089 * which is necessary when various parent-managed properties of the view change, such as 15090 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 15091 * an invalidation event to the parent. 15092 * 15093 * @hide 15094 */ 15095 protected void invalidateParentIfNeeded() { 15096 if (isHardwareAccelerated() && mParent instanceof View) { 15097 ((View) mParent).invalidate(true); 15098 } 15099 } 15100 15101 /** 15102 * @hide 15103 */ 15104 protected void invalidateParentIfNeededAndWasQuickRejected() { 15105 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 15106 // View was rejected last time it was drawn by its parent; this may have changed 15107 invalidateParentIfNeeded(); 15108 } 15109 } 15110 15111 /** 15112 * Indicates whether this View is opaque. An opaque View guarantees that it will 15113 * draw all the pixels overlapping its bounds using a fully opaque color. 15114 * 15115 * Subclasses of View should override this method whenever possible to indicate 15116 * whether an instance is opaque. Opaque Views are treated in a special way by 15117 * the View hierarchy, possibly allowing it to perform optimizations during 15118 * invalidate/draw passes. 15119 * 15120 * @return True if this View is guaranteed to be fully opaque, false otherwise. 15121 */ 15122 @ViewDebug.ExportedProperty(category = "drawing") 15123 public boolean isOpaque() { 15124 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 15125 getFinalAlpha() >= 1.0f; 15126 } 15127 15128 /** 15129 * @hide 15130 */ 15131 protected void computeOpaqueFlags() { 15132 // Opaque if: 15133 // - Has a background 15134 // - Background is opaque 15135 // - Doesn't have scrollbars or scrollbars overlay 15136 15137 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 15138 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 15139 } else { 15140 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 15141 } 15142 15143 final int flags = mViewFlags; 15144 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 15145 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 15146 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 15147 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 15148 } else { 15149 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 15150 } 15151 } 15152 15153 /** 15154 * @hide 15155 */ 15156 protected boolean hasOpaqueScrollbars() { 15157 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 15158 } 15159 15160 /** 15161 * @return A handler associated with the thread running the View. This 15162 * handler can be used to pump events in the UI events queue. 15163 */ 15164 public Handler getHandler() { 15165 final AttachInfo attachInfo = mAttachInfo; 15166 if (attachInfo != null) { 15167 return attachInfo.mHandler; 15168 } 15169 return null; 15170 } 15171 15172 /** 15173 * Returns the queue of runnable for this view. 15174 * 15175 * @return the queue of runnables for this view 15176 */ 15177 private HandlerActionQueue getRunQueue() { 15178 if (mRunQueue == null) { 15179 mRunQueue = new HandlerActionQueue(); 15180 } 15181 return mRunQueue; 15182 } 15183 15184 /** 15185 * Gets the view root associated with the View. 15186 * @return The view root, or null if none. 15187 * @hide 15188 */ 15189 public ViewRootImpl getViewRootImpl() { 15190 if (mAttachInfo != null) { 15191 return mAttachInfo.mViewRootImpl; 15192 } 15193 return null; 15194 } 15195 15196 /** 15197 * @hide 15198 */ 15199 public ThreadedRenderer getThreadedRenderer() { 15200 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 15201 } 15202 15203 /** 15204 * <p>Causes the Runnable to be added to the message queue. 15205 * The runnable will be run on the user interface thread.</p> 15206 * 15207 * @param action The Runnable that will be executed. 15208 * 15209 * @return Returns true if the Runnable was successfully placed in to the 15210 * message queue. Returns false on failure, usually because the 15211 * looper processing the message queue is exiting. 15212 * 15213 * @see #postDelayed 15214 * @see #removeCallbacks 15215 */ 15216 public boolean post(Runnable action) { 15217 final AttachInfo attachInfo = mAttachInfo; 15218 if (attachInfo != null) { 15219 return attachInfo.mHandler.post(action); 15220 } 15221 15222 // Postpone the runnable until we know on which thread it needs to run. 15223 // Assume that the runnable will be successfully placed after attach. 15224 getRunQueue().post(action); 15225 return true; 15226 } 15227 15228 /** 15229 * <p>Causes the Runnable to be added to the message queue, to be run 15230 * after the specified amount of time elapses. 15231 * The runnable will be run on the user interface thread.</p> 15232 * 15233 * @param action The Runnable that will be executed. 15234 * @param delayMillis The delay (in milliseconds) until the Runnable 15235 * will be executed. 15236 * 15237 * @return true if the Runnable was successfully placed in to the 15238 * message queue. Returns false on failure, usually because the 15239 * looper processing the message queue is exiting. Note that a 15240 * result of true does not mean the Runnable will be processed -- 15241 * if the looper is quit before the delivery time of the message 15242 * occurs then the message will be dropped. 15243 * 15244 * @see #post 15245 * @see #removeCallbacks 15246 */ 15247 public boolean postDelayed(Runnable action, long delayMillis) { 15248 final AttachInfo attachInfo = mAttachInfo; 15249 if (attachInfo != null) { 15250 return attachInfo.mHandler.postDelayed(action, delayMillis); 15251 } 15252 15253 // Postpone the runnable until we know on which thread it needs to run. 15254 // Assume that the runnable will be successfully placed after attach. 15255 getRunQueue().postDelayed(action, delayMillis); 15256 return true; 15257 } 15258 15259 /** 15260 * <p>Causes the Runnable to execute on the next animation time step. 15261 * The runnable will be run on the user interface thread.</p> 15262 * 15263 * @param action The Runnable that will be executed. 15264 * 15265 * @see #postOnAnimationDelayed 15266 * @see #removeCallbacks 15267 */ 15268 public void postOnAnimation(Runnable action) { 15269 final AttachInfo attachInfo = mAttachInfo; 15270 if (attachInfo != null) { 15271 attachInfo.mViewRootImpl.mChoreographer.postCallback( 15272 Choreographer.CALLBACK_ANIMATION, action, null); 15273 } else { 15274 // Postpone the runnable until we know 15275 // on which thread it needs to run. 15276 getRunQueue().post(action); 15277 } 15278 } 15279 15280 /** 15281 * <p>Causes the Runnable to execute on the next animation time step, 15282 * after the specified amount of time elapses. 15283 * The runnable will be run on the user interface thread.</p> 15284 * 15285 * @param action The Runnable that will be executed. 15286 * @param delayMillis The delay (in milliseconds) until the Runnable 15287 * will be executed. 15288 * 15289 * @see #postOnAnimation 15290 * @see #removeCallbacks 15291 */ 15292 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 15293 final AttachInfo attachInfo = mAttachInfo; 15294 if (attachInfo != null) { 15295 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 15296 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 15297 } else { 15298 // Postpone the runnable until we know 15299 // on which thread it needs to run. 15300 getRunQueue().postDelayed(action, delayMillis); 15301 } 15302 } 15303 15304 /** 15305 * <p>Removes the specified Runnable from the message queue.</p> 15306 * 15307 * @param action The Runnable to remove from the message handling queue 15308 * 15309 * @return true if this view could ask the Handler to remove the Runnable, 15310 * false otherwise. When the returned value is true, the Runnable 15311 * may or may not have been actually removed from the message queue 15312 * (for instance, if the Runnable was not in the queue already.) 15313 * 15314 * @see #post 15315 * @see #postDelayed 15316 * @see #postOnAnimation 15317 * @see #postOnAnimationDelayed 15318 */ 15319 public boolean removeCallbacks(Runnable action) { 15320 if (action != null) { 15321 final AttachInfo attachInfo = mAttachInfo; 15322 if (attachInfo != null) { 15323 attachInfo.mHandler.removeCallbacks(action); 15324 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 15325 Choreographer.CALLBACK_ANIMATION, action, null); 15326 } 15327 getRunQueue().removeCallbacks(action); 15328 } 15329 return true; 15330 } 15331 15332 /** 15333 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 15334 * Use this to invalidate the View from a non-UI thread.</p> 15335 * 15336 * <p>This method can be invoked from outside of the UI thread 15337 * only when this View is attached to a window.</p> 15338 * 15339 * @see #invalidate() 15340 * @see #postInvalidateDelayed(long) 15341 */ 15342 public void postInvalidate() { 15343 postInvalidateDelayed(0); 15344 } 15345 15346 /** 15347 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15348 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 15349 * 15350 * <p>This method can be invoked from outside of the UI thread 15351 * only when this View is attached to a window.</p> 15352 * 15353 * @param left The left coordinate of the rectangle to invalidate. 15354 * @param top The top coordinate of the rectangle to invalidate. 15355 * @param right The right coordinate of the rectangle to invalidate. 15356 * @param bottom The bottom coordinate of the rectangle to invalidate. 15357 * 15358 * @see #invalidate(int, int, int, int) 15359 * @see #invalidate(Rect) 15360 * @see #postInvalidateDelayed(long, int, int, int, int) 15361 */ 15362 public void postInvalidate(int left, int top, int right, int bottom) { 15363 postInvalidateDelayed(0, left, top, right, bottom); 15364 } 15365 15366 /** 15367 * <p>Cause an invalidate to happen on a subsequent cycle through the event 15368 * loop. Waits for the specified amount of time.</p> 15369 * 15370 * <p>This method can be invoked from outside of the UI thread 15371 * only when this View is attached to a window.</p> 15372 * 15373 * @param delayMilliseconds the duration in milliseconds to delay the 15374 * invalidation by 15375 * 15376 * @see #invalidate() 15377 * @see #postInvalidate() 15378 */ 15379 public void postInvalidateDelayed(long delayMilliseconds) { 15380 // We try only with the AttachInfo because there's no point in invalidating 15381 // if we are not attached to our window 15382 final AttachInfo attachInfo = mAttachInfo; 15383 if (attachInfo != null) { 15384 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 15385 } 15386 } 15387 15388 /** 15389 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15390 * through the event loop. Waits for the specified amount of time.</p> 15391 * 15392 * <p>This method can be invoked from outside of the UI thread 15393 * only when this View is attached to a window.</p> 15394 * 15395 * @param delayMilliseconds the duration in milliseconds to delay the 15396 * invalidation by 15397 * @param left The left coordinate of the rectangle to invalidate. 15398 * @param top The top coordinate of the rectangle to invalidate. 15399 * @param right The right coordinate of the rectangle to invalidate. 15400 * @param bottom The bottom coordinate of the rectangle to invalidate. 15401 * 15402 * @see #invalidate(int, int, int, int) 15403 * @see #invalidate(Rect) 15404 * @see #postInvalidate(int, int, int, int) 15405 */ 15406 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 15407 int right, int bottom) { 15408 15409 // We try only with the AttachInfo because there's no point in invalidating 15410 // if we are not attached to our window 15411 final AttachInfo attachInfo = mAttachInfo; 15412 if (attachInfo != null) { 15413 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15414 info.target = this; 15415 info.left = left; 15416 info.top = top; 15417 info.right = right; 15418 info.bottom = bottom; 15419 15420 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 15421 } 15422 } 15423 15424 /** 15425 * <p>Cause an invalidate to happen on the next animation time step, typically the 15426 * next display frame.</p> 15427 * 15428 * <p>This method can be invoked from outside of the UI thread 15429 * only when this View is attached to a window.</p> 15430 * 15431 * @see #invalidate() 15432 */ 15433 public void postInvalidateOnAnimation() { 15434 // We try only with the AttachInfo because there's no point in invalidating 15435 // if we are not attached to our window 15436 final AttachInfo attachInfo = mAttachInfo; 15437 if (attachInfo != null) { 15438 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 15439 } 15440 } 15441 15442 /** 15443 * <p>Cause an invalidate of the specified area to happen on the next animation 15444 * time step, typically the next display frame.</p> 15445 * 15446 * <p>This method can be invoked from outside of the UI thread 15447 * only when this View is attached to a window.</p> 15448 * 15449 * @param left The left coordinate of the rectangle to invalidate. 15450 * @param top The top coordinate of the rectangle to invalidate. 15451 * @param right The right coordinate of the rectangle to invalidate. 15452 * @param bottom The bottom coordinate of the rectangle to invalidate. 15453 * 15454 * @see #invalidate(int, int, int, int) 15455 * @see #invalidate(Rect) 15456 */ 15457 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 15458 // We try only with the AttachInfo because there's no point in invalidating 15459 // if we are not attached to our window 15460 final AttachInfo attachInfo = mAttachInfo; 15461 if (attachInfo != null) { 15462 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15463 info.target = this; 15464 info.left = left; 15465 info.top = top; 15466 info.right = right; 15467 info.bottom = bottom; 15468 15469 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 15470 } 15471 } 15472 15473 /** 15474 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 15475 * This event is sent at most once every 15476 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 15477 */ 15478 private void postSendViewScrolledAccessibilityEventCallback() { 15479 if (mSendViewScrolledAccessibilityEvent == null) { 15480 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 15481 } 15482 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 15483 mSendViewScrolledAccessibilityEvent.mIsPending = true; 15484 postDelayed(mSendViewScrolledAccessibilityEvent, 15485 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 15486 } 15487 } 15488 15489 /** 15490 * Called by a parent to request that a child update its values for mScrollX 15491 * and mScrollY if necessary. This will typically be done if the child is 15492 * animating a scroll using a {@link android.widget.Scroller Scroller} 15493 * object. 15494 */ 15495 public void computeScroll() { 15496 } 15497 15498 /** 15499 * <p>Indicate whether the horizontal edges are faded when the view is 15500 * scrolled horizontally.</p> 15501 * 15502 * @return true if the horizontal edges should are faded on scroll, false 15503 * otherwise 15504 * 15505 * @see #setHorizontalFadingEdgeEnabled(boolean) 15506 * 15507 * @attr ref android.R.styleable#View_requiresFadingEdge 15508 */ 15509 public boolean isHorizontalFadingEdgeEnabled() { 15510 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 15511 } 15512 15513 /** 15514 * <p>Define whether the horizontal edges should be faded when this view 15515 * is scrolled horizontally.</p> 15516 * 15517 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 15518 * be faded when the view is scrolled 15519 * horizontally 15520 * 15521 * @see #isHorizontalFadingEdgeEnabled() 15522 * 15523 * @attr ref android.R.styleable#View_requiresFadingEdge 15524 */ 15525 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 15526 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 15527 if (horizontalFadingEdgeEnabled) { 15528 initScrollCache(); 15529 } 15530 15531 mViewFlags ^= FADING_EDGE_HORIZONTAL; 15532 } 15533 } 15534 15535 /** 15536 * <p>Indicate whether the vertical edges are faded when the view is 15537 * scrolled horizontally.</p> 15538 * 15539 * @return true if the vertical edges should are faded on scroll, false 15540 * otherwise 15541 * 15542 * @see #setVerticalFadingEdgeEnabled(boolean) 15543 * 15544 * @attr ref android.R.styleable#View_requiresFadingEdge 15545 */ 15546 public boolean isVerticalFadingEdgeEnabled() { 15547 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 15548 } 15549 15550 /** 15551 * <p>Define whether the vertical edges should be faded when this view 15552 * is scrolled vertically.</p> 15553 * 15554 * @param verticalFadingEdgeEnabled true if the vertical edges should 15555 * be faded when the view is scrolled 15556 * vertically 15557 * 15558 * @see #isVerticalFadingEdgeEnabled() 15559 * 15560 * @attr ref android.R.styleable#View_requiresFadingEdge 15561 */ 15562 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 15563 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 15564 if (verticalFadingEdgeEnabled) { 15565 initScrollCache(); 15566 } 15567 15568 mViewFlags ^= FADING_EDGE_VERTICAL; 15569 } 15570 } 15571 15572 /** 15573 * Returns the strength, or intensity, of the top faded edge. The strength is 15574 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15575 * returns 0.0 or 1.0 but no value in between. 15576 * 15577 * Subclasses should override this method to provide a smoother fade transition 15578 * when scrolling occurs. 15579 * 15580 * @return the intensity of the top fade as a float between 0.0f and 1.0f 15581 */ 15582 protected float getTopFadingEdgeStrength() { 15583 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 15584 } 15585 15586 /** 15587 * Returns the strength, or intensity, of the bottom faded edge. The strength is 15588 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15589 * returns 0.0 or 1.0 but no value in between. 15590 * 15591 * Subclasses should override this method to provide a smoother fade transition 15592 * when scrolling occurs. 15593 * 15594 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 15595 */ 15596 protected float getBottomFadingEdgeStrength() { 15597 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 15598 computeVerticalScrollRange() ? 1.0f : 0.0f; 15599 } 15600 15601 /** 15602 * Returns the strength, or intensity, of the left faded edge. The strength is 15603 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15604 * returns 0.0 or 1.0 but no value in between. 15605 * 15606 * Subclasses should override this method to provide a smoother fade transition 15607 * when scrolling occurs. 15608 * 15609 * @return the intensity of the left fade as a float between 0.0f and 1.0f 15610 */ 15611 protected float getLeftFadingEdgeStrength() { 15612 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 15613 } 15614 15615 /** 15616 * Returns the strength, or intensity, of the right faded edge. The strength is 15617 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15618 * returns 0.0 or 1.0 but no value in between. 15619 * 15620 * Subclasses should override this method to provide a smoother fade transition 15621 * when scrolling occurs. 15622 * 15623 * @return the intensity of the right fade as a float between 0.0f and 1.0f 15624 */ 15625 protected float getRightFadingEdgeStrength() { 15626 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 15627 computeHorizontalScrollRange() ? 1.0f : 0.0f; 15628 } 15629 15630 /** 15631 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 15632 * scrollbar is not drawn by default.</p> 15633 * 15634 * @return true if the horizontal scrollbar should be painted, false 15635 * otherwise 15636 * 15637 * @see #setHorizontalScrollBarEnabled(boolean) 15638 */ 15639 public boolean isHorizontalScrollBarEnabled() { 15640 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 15641 } 15642 15643 /** 15644 * <p>Define whether the horizontal scrollbar should be drawn or not. The 15645 * scrollbar is not drawn by default.</p> 15646 * 15647 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 15648 * be painted 15649 * 15650 * @see #isHorizontalScrollBarEnabled() 15651 */ 15652 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 15653 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 15654 mViewFlags ^= SCROLLBARS_HORIZONTAL; 15655 computeOpaqueFlags(); 15656 resolvePadding(); 15657 } 15658 } 15659 15660 /** 15661 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 15662 * scrollbar is not drawn by default.</p> 15663 * 15664 * @return true if the vertical scrollbar should be painted, false 15665 * otherwise 15666 * 15667 * @see #setVerticalScrollBarEnabled(boolean) 15668 */ 15669 public boolean isVerticalScrollBarEnabled() { 15670 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 15671 } 15672 15673 /** 15674 * <p>Define whether the vertical scrollbar should be drawn or not. The 15675 * scrollbar is not drawn by default.</p> 15676 * 15677 * @param verticalScrollBarEnabled true if the vertical scrollbar should 15678 * be painted 15679 * 15680 * @see #isVerticalScrollBarEnabled() 15681 */ 15682 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 15683 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 15684 mViewFlags ^= SCROLLBARS_VERTICAL; 15685 computeOpaqueFlags(); 15686 resolvePadding(); 15687 } 15688 } 15689 15690 /** 15691 * @hide 15692 */ 15693 protected void recomputePadding() { 15694 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 15695 } 15696 15697 /** 15698 * Define whether scrollbars will fade when the view is not scrolling. 15699 * 15700 * @param fadeScrollbars whether to enable fading 15701 * 15702 * @attr ref android.R.styleable#View_fadeScrollbars 15703 */ 15704 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 15705 initScrollCache(); 15706 final ScrollabilityCache scrollabilityCache = mScrollCache; 15707 scrollabilityCache.fadeScrollBars = fadeScrollbars; 15708 if (fadeScrollbars) { 15709 scrollabilityCache.state = ScrollabilityCache.OFF; 15710 } else { 15711 scrollabilityCache.state = ScrollabilityCache.ON; 15712 } 15713 } 15714 15715 /** 15716 * 15717 * Returns true if scrollbars will fade when this view is not scrolling 15718 * 15719 * @return true if scrollbar fading is enabled 15720 * 15721 * @attr ref android.R.styleable#View_fadeScrollbars 15722 */ 15723 public boolean isScrollbarFadingEnabled() { 15724 return mScrollCache != null && mScrollCache.fadeScrollBars; 15725 } 15726 15727 /** 15728 * 15729 * Returns the delay before scrollbars fade. 15730 * 15731 * @return the delay before scrollbars fade 15732 * 15733 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 15734 */ 15735 public int getScrollBarDefaultDelayBeforeFade() { 15736 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 15737 mScrollCache.scrollBarDefaultDelayBeforeFade; 15738 } 15739 15740 /** 15741 * Define the delay before scrollbars fade. 15742 * 15743 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 15744 * 15745 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 15746 */ 15747 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 15748 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 15749 } 15750 15751 /** 15752 * 15753 * Returns the scrollbar fade duration. 15754 * 15755 * @return the scrollbar fade duration, in milliseconds 15756 * 15757 * @attr ref android.R.styleable#View_scrollbarFadeDuration 15758 */ 15759 public int getScrollBarFadeDuration() { 15760 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 15761 mScrollCache.scrollBarFadeDuration; 15762 } 15763 15764 /** 15765 * Define the scrollbar fade duration. 15766 * 15767 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 15768 * 15769 * @attr ref android.R.styleable#View_scrollbarFadeDuration 15770 */ 15771 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 15772 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 15773 } 15774 15775 /** 15776 * 15777 * Returns the scrollbar size. 15778 * 15779 * @return the scrollbar size 15780 * 15781 * @attr ref android.R.styleable#View_scrollbarSize 15782 */ 15783 public int getScrollBarSize() { 15784 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 15785 mScrollCache.scrollBarSize; 15786 } 15787 15788 /** 15789 * Define the scrollbar size. 15790 * 15791 * @param scrollBarSize - the scrollbar size 15792 * 15793 * @attr ref android.R.styleable#View_scrollbarSize 15794 */ 15795 public void setScrollBarSize(int scrollBarSize) { 15796 getScrollCache().scrollBarSize = scrollBarSize; 15797 } 15798 15799 /** 15800 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 15801 * inset. When inset, they add to the padding of the view. And the scrollbars 15802 * can be drawn inside the padding area or on the edge of the view. For example, 15803 * if a view has a background drawable and you want to draw the scrollbars 15804 * inside the padding specified by the drawable, you can use 15805 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 15806 * appear at the edge of the view, ignoring the padding, then you can use 15807 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 15808 * @param style the style of the scrollbars. Should be one of 15809 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 15810 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 15811 * @see #SCROLLBARS_INSIDE_OVERLAY 15812 * @see #SCROLLBARS_INSIDE_INSET 15813 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15814 * @see #SCROLLBARS_OUTSIDE_INSET 15815 * 15816 * @attr ref android.R.styleable#View_scrollbarStyle 15817 */ 15818 public void setScrollBarStyle(@ScrollBarStyle int style) { 15819 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 15820 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 15821 computeOpaqueFlags(); 15822 resolvePadding(); 15823 } 15824 } 15825 15826 /** 15827 * <p>Returns the current scrollbar style.</p> 15828 * @return the current scrollbar style 15829 * @see #SCROLLBARS_INSIDE_OVERLAY 15830 * @see #SCROLLBARS_INSIDE_INSET 15831 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15832 * @see #SCROLLBARS_OUTSIDE_INSET 15833 * 15834 * @attr ref android.R.styleable#View_scrollbarStyle 15835 */ 15836 @ViewDebug.ExportedProperty(mapping = { 15837 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 15838 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 15839 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 15840 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 15841 }) 15842 @ScrollBarStyle 15843 public int getScrollBarStyle() { 15844 return mViewFlags & SCROLLBARS_STYLE_MASK; 15845 } 15846 15847 /** 15848 * <p>Compute the horizontal range that the horizontal scrollbar 15849 * represents.</p> 15850 * 15851 * <p>The range is expressed in arbitrary units that must be the same as the 15852 * units used by {@link #computeHorizontalScrollExtent()} and 15853 * {@link #computeHorizontalScrollOffset()}.</p> 15854 * 15855 * <p>The default range is the drawing width of this view.</p> 15856 * 15857 * @return the total horizontal range represented by the horizontal 15858 * scrollbar 15859 * 15860 * @see #computeHorizontalScrollExtent() 15861 * @see #computeHorizontalScrollOffset() 15862 * @see android.widget.ScrollBarDrawable 15863 */ 15864 protected int computeHorizontalScrollRange() { 15865 return getWidth(); 15866 } 15867 15868 /** 15869 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 15870 * within the horizontal range. This value is used to compute the position 15871 * of the thumb within the scrollbar's track.</p> 15872 * 15873 * <p>The range is expressed in arbitrary units that must be the same as the 15874 * units used by {@link #computeHorizontalScrollRange()} and 15875 * {@link #computeHorizontalScrollExtent()}.</p> 15876 * 15877 * <p>The default offset is the scroll offset of this view.</p> 15878 * 15879 * @return the horizontal offset of the scrollbar's thumb 15880 * 15881 * @see #computeHorizontalScrollRange() 15882 * @see #computeHorizontalScrollExtent() 15883 * @see android.widget.ScrollBarDrawable 15884 */ 15885 protected int computeHorizontalScrollOffset() { 15886 return mScrollX; 15887 } 15888 15889 /** 15890 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 15891 * within the horizontal range. This value is used to compute the length 15892 * of the thumb within the scrollbar's track.</p> 15893 * 15894 * <p>The range is expressed in arbitrary units that must be the same as the 15895 * units used by {@link #computeHorizontalScrollRange()} and 15896 * {@link #computeHorizontalScrollOffset()}.</p> 15897 * 15898 * <p>The default extent is the drawing width of this view.</p> 15899 * 15900 * @return the horizontal extent of the scrollbar's thumb 15901 * 15902 * @see #computeHorizontalScrollRange() 15903 * @see #computeHorizontalScrollOffset() 15904 * @see android.widget.ScrollBarDrawable 15905 */ 15906 protected int computeHorizontalScrollExtent() { 15907 return getWidth(); 15908 } 15909 15910 /** 15911 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 15912 * 15913 * <p>The range is expressed in arbitrary units that must be the same as the 15914 * units used by {@link #computeVerticalScrollExtent()} and 15915 * {@link #computeVerticalScrollOffset()}.</p> 15916 * 15917 * @return the total vertical range represented by the vertical scrollbar 15918 * 15919 * <p>The default range is the drawing height of this view.</p> 15920 * 15921 * @see #computeVerticalScrollExtent() 15922 * @see #computeVerticalScrollOffset() 15923 * @see android.widget.ScrollBarDrawable 15924 */ 15925 protected int computeVerticalScrollRange() { 15926 return getHeight(); 15927 } 15928 15929 /** 15930 * <p>Compute the vertical offset of the vertical scrollbar's thumb 15931 * within the horizontal range. This value is used to compute the position 15932 * of the thumb within the scrollbar's track.</p> 15933 * 15934 * <p>The range is expressed in arbitrary units that must be the same as the 15935 * units used by {@link #computeVerticalScrollRange()} and 15936 * {@link #computeVerticalScrollExtent()}.</p> 15937 * 15938 * <p>The default offset is the scroll offset of this view.</p> 15939 * 15940 * @return the vertical offset of the scrollbar's thumb 15941 * 15942 * @see #computeVerticalScrollRange() 15943 * @see #computeVerticalScrollExtent() 15944 * @see android.widget.ScrollBarDrawable 15945 */ 15946 protected int computeVerticalScrollOffset() { 15947 return mScrollY; 15948 } 15949 15950 /** 15951 * <p>Compute the vertical extent of the vertical scrollbar's thumb 15952 * within the vertical range. This value is used to compute the length 15953 * of the thumb within the scrollbar's track.</p> 15954 * 15955 * <p>The range is expressed in arbitrary units that must be the same as the 15956 * units used by {@link #computeVerticalScrollRange()} and 15957 * {@link #computeVerticalScrollOffset()}.</p> 15958 * 15959 * <p>The default extent is the drawing height of this view.</p> 15960 * 15961 * @return the vertical extent of the scrollbar's thumb 15962 * 15963 * @see #computeVerticalScrollRange() 15964 * @see #computeVerticalScrollOffset() 15965 * @see android.widget.ScrollBarDrawable 15966 */ 15967 protected int computeVerticalScrollExtent() { 15968 return getHeight(); 15969 } 15970 15971 /** 15972 * Check if this view can be scrolled horizontally in a certain direction. 15973 * 15974 * @param direction Negative to check scrolling left, positive to check scrolling right. 15975 * @return true if this view can be scrolled in the specified direction, false otherwise. 15976 */ 15977 public boolean canScrollHorizontally(int direction) { 15978 final int offset = computeHorizontalScrollOffset(); 15979 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 15980 if (range == 0) return false; 15981 if (direction < 0) { 15982 return offset > 0; 15983 } else { 15984 return offset < range - 1; 15985 } 15986 } 15987 15988 /** 15989 * Check if this view can be scrolled vertically in a certain direction. 15990 * 15991 * @param direction Negative to check scrolling up, positive to check scrolling down. 15992 * @return true if this view can be scrolled in the specified direction, false otherwise. 15993 */ 15994 public boolean canScrollVertically(int direction) { 15995 final int offset = computeVerticalScrollOffset(); 15996 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 15997 if (range == 0) return false; 15998 if (direction < 0) { 15999 return offset > 0; 16000 } else { 16001 return offset < range - 1; 16002 } 16003 } 16004 16005 void getScrollIndicatorBounds(@NonNull Rect out) { 16006 out.left = mScrollX; 16007 out.right = mScrollX + mRight - mLeft; 16008 out.top = mScrollY; 16009 out.bottom = mScrollY + mBottom - mTop; 16010 } 16011 16012 private void onDrawScrollIndicators(Canvas c) { 16013 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 16014 // No scroll indicators enabled. 16015 return; 16016 } 16017 16018 final Drawable dr = mScrollIndicatorDrawable; 16019 if (dr == null) { 16020 // Scroll indicators aren't supported here. 16021 return; 16022 } 16023 16024 final int h = dr.getIntrinsicHeight(); 16025 final int w = dr.getIntrinsicWidth(); 16026 final Rect rect = mAttachInfo.mTmpInvalRect; 16027 getScrollIndicatorBounds(rect); 16028 16029 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 16030 final boolean canScrollUp = canScrollVertically(-1); 16031 if (canScrollUp) { 16032 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 16033 dr.draw(c); 16034 } 16035 } 16036 16037 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 16038 final boolean canScrollDown = canScrollVertically(1); 16039 if (canScrollDown) { 16040 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 16041 dr.draw(c); 16042 } 16043 } 16044 16045 final int leftRtl; 16046 final int rightRtl; 16047 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 16048 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 16049 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 16050 } else { 16051 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 16052 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 16053 } 16054 16055 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 16056 if ((mPrivateFlags3 & leftMask) != 0) { 16057 final boolean canScrollLeft = canScrollHorizontally(-1); 16058 if (canScrollLeft) { 16059 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 16060 dr.draw(c); 16061 } 16062 } 16063 16064 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 16065 if ((mPrivateFlags3 & rightMask) != 0) { 16066 final boolean canScrollRight = canScrollHorizontally(1); 16067 if (canScrollRight) { 16068 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 16069 dr.draw(c); 16070 } 16071 } 16072 } 16073 16074 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 16075 @Nullable Rect touchBounds) { 16076 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16077 if (bounds == null) { 16078 return; 16079 } 16080 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16081 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16082 && !isVerticalScrollBarHidden(); 16083 final int size = getHorizontalScrollbarHeight(); 16084 final int verticalScrollBarGap = drawVerticalScrollBar ? 16085 getVerticalScrollbarWidth() : 0; 16086 final int width = mRight - mLeft; 16087 final int height = mBottom - mTop; 16088 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 16089 bounds.left = mScrollX + (mPaddingLeft & inside); 16090 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 16091 bounds.bottom = bounds.top + size; 16092 16093 if (touchBounds == null) { 16094 return; 16095 } 16096 if (touchBounds != bounds) { 16097 touchBounds.set(bounds); 16098 } 16099 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16100 if (touchBounds.height() < minTouchTarget) { 16101 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16102 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 16103 touchBounds.top = touchBounds.bottom - minTouchTarget; 16104 } 16105 if (touchBounds.width() < minTouchTarget) { 16106 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16107 touchBounds.left -= adjust; 16108 touchBounds.right = touchBounds.left + minTouchTarget; 16109 } 16110 } 16111 16112 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 16113 if (mRoundScrollbarRenderer == null) { 16114 getStraightVerticalScrollBarBounds(bounds, touchBounds); 16115 } else { 16116 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 16117 } 16118 } 16119 16120 private void getRoundVerticalScrollBarBounds(Rect bounds) { 16121 final int width = mRight - mLeft; 16122 final int height = mBottom - mTop; 16123 // Do not take padding into account as we always want the scrollbars 16124 // to hug the screen for round wearable devices. 16125 bounds.left = mScrollX; 16126 bounds.top = mScrollY; 16127 bounds.right = bounds.left + width; 16128 bounds.bottom = mScrollY + height; 16129 } 16130 16131 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 16132 @Nullable Rect touchBounds) { 16133 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16134 if (bounds == null) { 16135 return; 16136 } 16137 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16138 final int size = getVerticalScrollbarWidth(); 16139 int verticalScrollbarPosition = mVerticalScrollbarPosition; 16140 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 16141 verticalScrollbarPosition = isLayoutRtl() ? 16142 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 16143 } 16144 final int width = mRight - mLeft; 16145 final int height = mBottom - mTop; 16146 switch (verticalScrollbarPosition) { 16147 default: 16148 case SCROLLBAR_POSITION_RIGHT: 16149 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 16150 break; 16151 case SCROLLBAR_POSITION_LEFT: 16152 bounds.left = mScrollX + (mUserPaddingLeft & inside); 16153 break; 16154 } 16155 bounds.top = mScrollY + (mPaddingTop & inside); 16156 bounds.right = bounds.left + size; 16157 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 16158 16159 if (touchBounds == null) { 16160 return; 16161 } 16162 if (touchBounds != bounds) { 16163 touchBounds.set(bounds); 16164 } 16165 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16166 if (touchBounds.width() < minTouchTarget) { 16167 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16168 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 16169 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 16170 touchBounds.left = touchBounds.right - minTouchTarget; 16171 } else { 16172 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 16173 touchBounds.right = touchBounds.left + minTouchTarget; 16174 } 16175 } 16176 if (touchBounds.height() < minTouchTarget) { 16177 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16178 touchBounds.top -= adjust; 16179 touchBounds.bottom = touchBounds.top + minTouchTarget; 16180 } 16181 } 16182 16183 /** 16184 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 16185 * scrollbars are painted only if they have been awakened first.</p> 16186 * 16187 * @param canvas the canvas on which to draw the scrollbars 16188 * 16189 * @see #awakenScrollBars(int) 16190 */ 16191 protected final void onDrawScrollBars(Canvas canvas) { 16192 // scrollbars are drawn only when the animation is running 16193 final ScrollabilityCache cache = mScrollCache; 16194 16195 if (cache != null) { 16196 16197 int state = cache.state; 16198 16199 if (state == ScrollabilityCache.OFF) { 16200 return; 16201 } 16202 16203 boolean invalidate = false; 16204 16205 if (state == ScrollabilityCache.FADING) { 16206 // We're fading -- get our fade interpolation 16207 if (cache.interpolatorValues == null) { 16208 cache.interpolatorValues = new float[1]; 16209 } 16210 16211 float[] values = cache.interpolatorValues; 16212 16213 // Stops the animation if we're done 16214 if (cache.scrollBarInterpolator.timeToValues(values) == 16215 Interpolator.Result.FREEZE_END) { 16216 cache.state = ScrollabilityCache.OFF; 16217 } else { 16218 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 16219 } 16220 16221 // This will make the scroll bars inval themselves after 16222 // drawing. We only want this when we're fading so that 16223 // we prevent excessive redraws 16224 invalidate = true; 16225 } else { 16226 // We're just on -- but we may have been fading before so 16227 // reset alpha 16228 cache.scrollBar.mutate().setAlpha(255); 16229 } 16230 16231 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 16232 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16233 && !isVerticalScrollBarHidden(); 16234 16235 // Fork out the scroll bar drawing for round wearable devices. 16236 if (mRoundScrollbarRenderer != null) { 16237 if (drawVerticalScrollBar) { 16238 final Rect bounds = cache.mScrollBarBounds; 16239 getVerticalScrollBarBounds(bounds, null); 16240 mRoundScrollbarRenderer.drawRoundScrollbars( 16241 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 16242 if (invalidate) { 16243 invalidate(); 16244 } 16245 } 16246 // Do not draw horizontal scroll bars for round wearable devices. 16247 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 16248 final ScrollBarDrawable scrollBar = cache.scrollBar; 16249 16250 if (drawHorizontalScrollBar) { 16251 scrollBar.setParameters(computeHorizontalScrollRange(), 16252 computeHorizontalScrollOffset(), 16253 computeHorizontalScrollExtent(), false); 16254 final Rect bounds = cache.mScrollBarBounds; 16255 getHorizontalScrollBarBounds(bounds, null); 16256 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16257 bounds.right, bounds.bottom); 16258 if (invalidate) { 16259 invalidate(bounds); 16260 } 16261 } 16262 16263 if (drawVerticalScrollBar) { 16264 scrollBar.setParameters(computeVerticalScrollRange(), 16265 computeVerticalScrollOffset(), 16266 computeVerticalScrollExtent(), true); 16267 final Rect bounds = cache.mScrollBarBounds; 16268 getVerticalScrollBarBounds(bounds, null); 16269 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16270 bounds.right, bounds.bottom); 16271 if (invalidate) { 16272 invalidate(bounds); 16273 } 16274 } 16275 } 16276 } 16277 } 16278 16279 /** 16280 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 16281 * FastScroller is visible. 16282 * @return whether to temporarily hide the vertical scrollbar 16283 * @hide 16284 */ 16285 protected boolean isVerticalScrollBarHidden() { 16286 return false; 16287 } 16288 16289 /** 16290 * <p>Draw the horizontal scrollbar if 16291 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 16292 * 16293 * @param canvas the canvas on which to draw the scrollbar 16294 * @param scrollBar the scrollbar's drawable 16295 * 16296 * @see #isHorizontalScrollBarEnabled() 16297 * @see #computeHorizontalScrollRange() 16298 * @see #computeHorizontalScrollExtent() 16299 * @see #computeHorizontalScrollOffset() 16300 * @see android.widget.ScrollBarDrawable 16301 * @hide 16302 */ 16303 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 16304 int l, int t, int r, int b) { 16305 scrollBar.setBounds(l, t, r, b); 16306 scrollBar.draw(canvas); 16307 } 16308 16309 /** 16310 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 16311 * returns true.</p> 16312 * 16313 * @param canvas the canvas on which to draw the scrollbar 16314 * @param scrollBar the scrollbar's drawable 16315 * 16316 * @see #isVerticalScrollBarEnabled() 16317 * @see #computeVerticalScrollRange() 16318 * @see #computeVerticalScrollExtent() 16319 * @see #computeVerticalScrollOffset() 16320 * @see android.widget.ScrollBarDrawable 16321 * @hide 16322 */ 16323 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 16324 int l, int t, int r, int b) { 16325 scrollBar.setBounds(l, t, r, b); 16326 scrollBar.draw(canvas); 16327 } 16328 16329 /** 16330 * Implement this to do your drawing. 16331 * 16332 * @param canvas the canvas on which the background will be drawn 16333 */ 16334 protected void onDraw(Canvas canvas) { 16335 } 16336 16337 /* 16338 * Caller is responsible for calling requestLayout if necessary. 16339 * (This allows addViewInLayout to not request a new layout.) 16340 */ 16341 void assignParent(ViewParent parent) { 16342 if (mParent == null) { 16343 mParent = parent; 16344 } else if (parent == null) { 16345 mParent = null; 16346 } else { 16347 throw new RuntimeException("view " + this + " being added, but" 16348 + " it already has a parent"); 16349 } 16350 } 16351 16352 /** 16353 * This is called when the view is attached to a window. At this point it 16354 * has a Surface and will start drawing. Note that this function is 16355 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 16356 * however it may be called any time before the first onDraw -- including 16357 * before or after {@link #onMeasure(int, int)}. 16358 * 16359 * @see #onDetachedFromWindow() 16360 */ 16361 @CallSuper 16362 protected void onAttachedToWindow() { 16363 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 16364 mParent.requestTransparentRegion(this); 16365 } 16366 16367 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 16368 16369 jumpDrawablesToCurrentState(); 16370 16371 resetSubtreeAccessibilityStateChanged(); 16372 16373 // rebuild, since Outline not maintained while View is detached 16374 rebuildOutline(); 16375 16376 if (isFocused()) { 16377 InputMethodManager imm = InputMethodManager.peekInstance(); 16378 if (imm != null) { 16379 imm.focusIn(this); 16380 } 16381 } 16382 } 16383 16384 /** 16385 * Resolve all RTL related properties. 16386 * 16387 * @return true if resolution of RTL properties has been done 16388 * 16389 * @hide 16390 */ 16391 public boolean resolveRtlPropertiesIfNeeded() { 16392 if (!needRtlPropertiesResolution()) return false; 16393 16394 // Order is important here: LayoutDirection MUST be resolved first 16395 if (!isLayoutDirectionResolved()) { 16396 resolveLayoutDirection(); 16397 resolveLayoutParams(); 16398 } 16399 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 16400 if (!isTextDirectionResolved()) { 16401 resolveTextDirection(); 16402 } 16403 if (!isTextAlignmentResolved()) { 16404 resolveTextAlignment(); 16405 } 16406 // Should resolve Drawables before Padding because we need the layout direction of the 16407 // Drawable to correctly resolve Padding. 16408 if (!areDrawablesResolved()) { 16409 resolveDrawables(); 16410 } 16411 if (!isPaddingResolved()) { 16412 resolvePadding(); 16413 } 16414 onRtlPropertiesChanged(getLayoutDirection()); 16415 return true; 16416 } 16417 16418 /** 16419 * Reset resolution of all RTL related properties. 16420 * 16421 * @hide 16422 */ 16423 public void resetRtlProperties() { 16424 resetResolvedLayoutDirection(); 16425 resetResolvedTextDirection(); 16426 resetResolvedTextAlignment(); 16427 resetResolvedPadding(); 16428 resetResolvedDrawables(); 16429 } 16430 16431 /** 16432 * @see #onScreenStateChanged(int) 16433 */ 16434 void dispatchScreenStateChanged(int screenState) { 16435 onScreenStateChanged(screenState); 16436 } 16437 16438 /** 16439 * This method is called whenever the state of the screen this view is 16440 * attached to changes. A state change will usually occurs when the screen 16441 * turns on or off (whether it happens automatically or the user does it 16442 * manually.) 16443 * 16444 * @param screenState The new state of the screen. Can be either 16445 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 16446 */ 16447 public void onScreenStateChanged(int screenState) { 16448 } 16449 16450 /** 16451 * @see #onMovedToDisplay(int) 16452 */ 16453 void dispatchMovedToDisplay(Display display) { 16454 mAttachInfo.mDisplay = display; 16455 mAttachInfo.mDisplayState = display.getState(); 16456 onMovedToDisplay(display.getDisplayId()); 16457 } 16458 16459 /** 16460 * Called by the system when the hosting activity is moved from one display to another without 16461 * recreation. This means that the activity is declared to handle all changes to configuration 16462 * that happened when it was switched to another display, so it wasn't destroyed and created 16463 * again. This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 16464 * applied configuration actually changed. 16465 * 16466 * <p>Use this callback to track changes to the displays if some functionality relies on an 16467 * association with some display properties. 16468 * 16469 * @param displayId The id of the display to which the view was moved. 16470 * 16471 * @see #onConfigurationChanged(Configuration) 16472 */ 16473 public void onMovedToDisplay(int displayId) { 16474 } 16475 16476 /** 16477 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 16478 */ 16479 private boolean hasRtlSupport() { 16480 return mContext.getApplicationInfo().hasRtlSupport(); 16481 } 16482 16483 /** 16484 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 16485 * RTL not supported) 16486 */ 16487 private boolean isRtlCompatibilityMode() { 16488 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 16489 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 16490 } 16491 16492 /** 16493 * @return true if RTL properties need resolution. 16494 * 16495 */ 16496 private boolean needRtlPropertiesResolution() { 16497 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 16498 } 16499 16500 /** 16501 * Called when any RTL property (layout direction or text direction or text alignment) has 16502 * been changed. 16503 * 16504 * Subclasses need to override this method to take care of cached information that depends on the 16505 * resolved layout direction, or to inform child views that inherit their layout direction. 16506 * 16507 * The default implementation does nothing. 16508 * 16509 * @param layoutDirection the direction of the layout 16510 * 16511 * @see #LAYOUT_DIRECTION_LTR 16512 * @see #LAYOUT_DIRECTION_RTL 16513 */ 16514 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 16515 } 16516 16517 /** 16518 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 16519 * that the parent directionality can and will be resolved before its children. 16520 * 16521 * @return true if resolution has been done, false otherwise. 16522 * 16523 * @hide 16524 */ 16525 public boolean resolveLayoutDirection() { 16526 // Clear any previous layout direction resolution 16527 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 16528 16529 if (hasRtlSupport()) { 16530 // Set resolved depending on layout direction 16531 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 16532 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 16533 case LAYOUT_DIRECTION_INHERIT: 16534 // We cannot resolve yet. LTR is by default and let the resolution happen again 16535 // later to get the correct resolved value 16536 if (!canResolveLayoutDirection()) return false; 16537 16538 // Parent has not yet resolved, LTR is still the default 16539 try { 16540 if (!mParent.isLayoutDirectionResolved()) return false; 16541 16542 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 16543 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 16544 } 16545 } catch (AbstractMethodError e) { 16546 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 16547 " does not fully implement ViewParent", e); 16548 } 16549 break; 16550 case LAYOUT_DIRECTION_RTL: 16551 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 16552 break; 16553 case LAYOUT_DIRECTION_LOCALE: 16554 if((LAYOUT_DIRECTION_RTL == 16555 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 16556 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 16557 } 16558 break; 16559 default: 16560 // Nothing to do, LTR by default 16561 } 16562 } 16563 16564 // Set to resolved 16565 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 16566 return true; 16567 } 16568 16569 /** 16570 * Check if layout direction resolution can be done. 16571 * 16572 * @return true if layout direction resolution can be done otherwise return false. 16573 */ 16574 public boolean canResolveLayoutDirection() { 16575 switch (getRawLayoutDirection()) { 16576 case LAYOUT_DIRECTION_INHERIT: 16577 if (mParent != null) { 16578 try { 16579 return mParent.canResolveLayoutDirection(); 16580 } catch (AbstractMethodError e) { 16581 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 16582 " does not fully implement ViewParent", e); 16583 } 16584 } 16585 return false; 16586 16587 default: 16588 return true; 16589 } 16590 } 16591 16592 /** 16593 * Reset the resolved layout direction. Layout direction will be resolved during a call to 16594 * {@link #onMeasure(int, int)}. 16595 * 16596 * @hide 16597 */ 16598 public void resetResolvedLayoutDirection() { 16599 // Reset the current resolved bits 16600 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 16601 } 16602 16603 /** 16604 * @return true if the layout direction is inherited. 16605 * 16606 * @hide 16607 */ 16608 public boolean isLayoutDirectionInherited() { 16609 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 16610 } 16611 16612 /** 16613 * @return true if layout direction has been resolved. 16614 */ 16615 public boolean isLayoutDirectionResolved() { 16616 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 16617 } 16618 16619 /** 16620 * Return if padding has been resolved 16621 * 16622 * @hide 16623 */ 16624 boolean isPaddingResolved() { 16625 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 16626 } 16627 16628 /** 16629 * Resolves padding depending on layout direction, if applicable, and 16630 * recomputes internal padding values to adjust for scroll bars. 16631 * 16632 * @hide 16633 */ 16634 public void resolvePadding() { 16635 final int resolvedLayoutDirection = getLayoutDirection(); 16636 16637 if (!isRtlCompatibilityMode()) { 16638 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 16639 // If start / end padding are defined, they will be resolved (hence overriding) to 16640 // left / right or right / left depending on the resolved layout direction. 16641 // If start / end padding are not defined, use the left / right ones. 16642 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 16643 Rect padding = sThreadLocal.get(); 16644 if (padding == null) { 16645 padding = new Rect(); 16646 sThreadLocal.set(padding); 16647 } 16648 mBackground.getPadding(padding); 16649 if (!mLeftPaddingDefined) { 16650 mUserPaddingLeftInitial = padding.left; 16651 } 16652 if (!mRightPaddingDefined) { 16653 mUserPaddingRightInitial = padding.right; 16654 } 16655 } 16656 switch (resolvedLayoutDirection) { 16657 case LAYOUT_DIRECTION_RTL: 16658 if (mUserPaddingStart != UNDEFINED_PADDING) { 16659 mUserPaddingRight = mUserPaddingStart; 16660 } else { 16661 mUserPaddingRight = mUserPaddingRightInitial; 16662 } 16663 if (mUserPaddingEnd != UNDEFINED_PADDING) { 16664 mUserPaddingLeft = mUserPaddingEnd; 16665 } else { 16666 mUserPaddingLeft = mUserPaddingLeftInitial; 16667 } 16668 break; 16669 case LAYOUT_DIRECTION_LTR: 16670 default: 16671 if (mUserPaddingStart != UNDEFINED_PADDING) { 16672 mUserPaddingLeft = mUserPaddingStart; 16673 } else { 16674 mUserPaddingLeft = mUserPaddingLeftInitial; 16675 } 16676 if (mUserPaddingEnd != UNDEFINED_PADDING) { 16677 mUserPaddingRight = mUserPaddingEnd; 16678 } else { 16679 mUserPaddingRight = mUserPaddingRightInitial; 16680 } 16681 } 16682 16683 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 16684 } 16685 16686 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 16687 onRtlPropertiesChanged(resolvedLayoutDirection); 16688 16689 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 16690 } 16691 16692 /** 16693 * Reset the resolved layout direction. 16694 * 16695 * @hide 16696 */ 16697 public void resetResolvedPadding() { 16698 resetResolvedPaddingInternal(); 16699 } 16700 16701 /** 16702 * Used when we only want to reset *this* view's padding and not trigger overrides 16703 * in ViewGroup that reset children too. 16704 */ 16705 void resetResolvedPaddingInternal() { 16706 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 16707 } 16708 16709 /** 16710 * This is called when the view is detached from a window. At this point it 16711 * no longer has a surface for drawing. 16712 * 16713 * @see #onAttachedToWindow() 16714 */ 16715 @CallSuper 16716 protected void onDetachedFromWindow() { 16717 } 16718 16719 /** 16720 * This is a framework-internal mirror of onDetachedFromWindow() that's called 16721 * after onDetachedFromWindow(). 16722 * 16723 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 16724 * The super method should be called at the end of the overridden method to ensure 16725 * subclasses are destroyed first 16726 * 16727 * @hide 16728 */ 16729 @CallSuper 16730 protected void onDetachedFromWindowInternal() { 16731 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 16732 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 16733 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 16734 16735 removeUnsetPressCallback(); 16736 removeLongPressCallback(); 16737 removePerformClickCallback(); 16738 removeSendViewScrolledAccessibilityEventCallback(); 16739 stopNestedScroll(); 16740 16741 // Anything that started animating right before detach should already 16742 // be in its final state when re-attached. 16743 jumpDrawablesToCurrentState(); 16744 16745 destroyDrawingCache(); 16746 16747 cleanupDraw(); 16748 mCurrentAnimation = null; 16749 16750 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 16751 hideTooltip(); 16752 } 16753 } 16754 16755 private void cleanupDraw() { 16756 resetDisplayList(); 16757 if (mAttachInfo != null) { 16758 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 16759 } 16760 } 16761 16762 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 16763 } 16764 16765 /** 16766 * @return The number of times this view has been attached to a window 16767 */ 16768 protected int getWindowAttachCount() { 16769 return mWindowAttachCount; 16770 } 16771 16772 /** 16773 * Retrieve a unique token identifying the window this view is attached to. 16774 * @return Return the window's token for use in 16775 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 16776 */ 16777 public IBinder getWindowToken() { 16778 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 16779 } 16780 16781 /** 16782 * Retrieve the {@link WindowId} for the window this view is 16783 * currently attached to. 16784 */ 16785 public WindowId getWindowId() { 16786 if (mAttachInfo == null) { 16787 return null; 16788 } 16789 if (mAttachInfo.mWindowId == null) { 16790 try { 16791 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 16792 mAttachInfo.mWindowToken); 16793 mAttachInfo.mWindowId = new WindowId( 16794 mAttachInfo.mIWindowId); 16795 } catch (RemoteException e) { 16796 } 16797 } 16798 return mAttachInfo.mWindowId; 16799 } 16800 16801 /** 16802 * Retrieve a unique token identifying the top-level "real" window of 16803 * the window that this view is attached to. That is, this is like 16804 * {@link #getWindowToken}, except if the window this view in is a panel 16805 * window (attached to another containing window), then the token of 16806 * the containing window is returned instead. 16807 * 16808 * @return Returns the associated window token, either 16809 * {@link #getWindowToken()} or the containing window's token. 16810 */ 16811 public IBinder getApplicationWindowToken() { 16812 AttachInfo ai = mAttachInfo; 16813 if (ai != null) { 16814 IBinder appWindowToken = ai.mPanelParentWindowToken; 16815 if (appWindowToken == null) { 16816 appWindowToken = ai.mWindowToken; 16817 } 16818 return appWindowToken; 16819 } 16820 return null; 16821 } 16822 16823 /** 16824 * Gets the logical display to which the view's window has been attached. 16825 * 16826 * @return The logical display, or null if the view is not currently attached to a window. 16827 */ 16828 public Display getDisplay() { 16829 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 16830 } 16831 16832 /** 16833 * Retrieve private session object this view hierarchy is using to 16834 * communicate with the window manager. 16835 * @return the session object to communicate with the window manager 16836 */ 16837 /*package*/ IWindowSession getWindowSession() { 16838 return mAttachInfo != null ? mAttachInfo.mSession : null; 16839 } 16840 16841 /** 16842 * Return the visibility value of the least visible component passed. 16843 */ 16844 int combineVisibility(int vis1, int vis2) { 16845 // This works because VISIBLE < INVISIBLE < GONE. 16846 return Math.max(vis1, vis2); 16847 } 16848 16849 /** 16850 * @param info the {@link android.view.View.AttachInfo} to associated with 16851 * this view 16852 */ 16853 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 16854 mAttachInfo = info; 16855 if (mOverlay != null) { 16856 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 16857 } 16858 mWindowAttachCount++; 16859 // We will need to evaluate the drawable state at least once. 16860 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 16861 if (mFloatingTreeObserver != null) { 16862 info.mTreeObserver.merge(mFloatingTreeObserver); 16863 mFloatingTreeObserver = null; 16864 } 16865 16866 registerPendingFrameMetricsObservers(); 16867 16868 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 16869 mAttachInfo.mScrollContainers.add(this); 16870 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 16871 } 16872 // Transfer all pending runnables. 16873 if (mRunQueue != null) { 16874 mRunQueue.executeActions(info.mHandler); 16875 mRunQueue = null; 16876 } 16877 performCollectViewAttributes(mAttachInfo, visibility); 16878 onAttachedToWindow(); 16879 16880 ListenerInfo li = mListenerInfo; 16881 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 16882 li != null ? li.mOnAttachStateChangeListeners : null; 16883 if (listeners != null && listeners.size() > 0) { 16884 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 16885 // perform the dispatching. The iterator is a safe guard against listeners that 16886 // could mutate the list by calling the various add/remove methods. This prevents 16887 // the array from being modified while we iterate it. 16888 for (OnAttachStateChangeListener listener : listeners) { 16889 listener.onViewAttachedToWindow(this); 16890 } 16891 } 16892 16893 int vis = info.mWindowVisibility; 16894 if (vis != GONE) { 16895 onWindowVisibilityChanged(vis); 16896 if (isShown()) { 16897 // Calling onVisibilityAggregated directly here since the subtree will also 16898 // receive dispatchAttachedToWindow and this same call 16899 onVisibilityAggregated(vis == VISIBLE); 16900 } 16901 } 16902 16903 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 16904 // As all views in the subtree will already receive dispatchAttachedToWindow 16905 // traversing the subtree again here is not desired. 16906 onVisibilityChanged(this, visibility); 16907 16908 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 16909 // If nobody has evaluated the drawable state yet, then do it now. 16910 refreshDrawableState(); 16911 } 16912 needGlobalAttributesUpdate(false); 16913 16914 notifyEnterOrExitForAutoFillIfNeeded(true); 16915 } 16916 16917 void dispatchDetachedFromWindow() { 16918 AttachInfo info = mAttachInfo; 16919 if (info != null) { 16920 int vis = info.mWindowVisibility; 16921 if (vis != GONE) { 16922 onWindowVisibilityChanged(GONE); 16923 if (isShown()) { 16924 // Invoking onVisibilityAggregated directly here since the subtree 16925 // will also receive detached from window 16926 onVisibilityAggregated(false); 16927 } 16928 } 16929 } 16930 16931 onDetachedFromWindow(); 16932 onDetachedFromWindowInternal(); 16933 16934 InputMethodManager imm = InputMethodManager.peekInstance(); 16935 if (imm != null) { 16936 imm.onViewDetachedFromWindow(this); 16937 } 16938 16939 ListenerInfo li = mListenerInfo; 16940 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 16941 li != null ? li.mOnAttachStateChangeListeners : null; 16942 if (listeners != null && listeners.size() > 0) { 16943 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 16944 // perform the dispatching. The iterator is a safe guard against listeners that 16945 // could mutate the list by calling the various add/remove methods. This prevents 16946 // the array from being modified while we iterate it. 16947 for (OnAttachStateChangeListener listener : listeners) { 16948 listener.onViewDetachedFromWindow(this); 16949 } 16950 } 16951 16952 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 16953 mAttachInfo.mScrollContainers.remove(this); 16954 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 16955 } 16956 16957 mAttachInfo = null; 16958 if (mOverlay != null) { 16959 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 16960 } 16961 16962 notifyEnterOrExitForAutoFillIfNeeded(false); 16963 } 16964 16965 /** 16966 * Cancel any deferred high-level input events that were previously posted to the event queue. 16967 * 16968 * <p>Many views post high-level events such as click handlers to the event queue 16969 * to run deferred in order to preserve a desired user experience - clearing visible 16970 * pressed states before executing, etc. This method will abort any events of this nature 16971 * that are currently in flight.</p> 16972 * 16973 * <p>Custom views that generate their own high-level deferred input events should override 16974 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 16975 * 16976 * <p>This will also cancel pending input events for any child views.</p> 16977 * 16978 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 16979 * This will not impact newer events posted after this call that may occur as a result of 16980 * lower-level input events still waiting in the queue. If you are trying to prevent 16981 * double-submitted events for the duration of some sort of asynchronous transaction 16982 * you should also take other steps to protect against unexpected double inputs e.g. calling 16983 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 16984 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 16985 */ 16986 public final void cancelPendingInputEvents() { 16987 dispatchCancelPendingInputEvents(); 16988 } 16989 16990 /** 16991 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 16992 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 16993 */ 16994 void dispatchCancelPendingInputEvents() { 16995 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 16996 onCancelPendingInputEvents(); 16997 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 16998 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 16999 " did not call through to super.onCancelPendingInputEvents()"); 17000 } 17001 } 17002 17003 /** 17004 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 17005 * a parent view. 17006 * 17007 * <p>This method is responsible for removing any pending high-level input events that were 17008 * posted to the event queue to run later. Custom view classes that post their own deferred 17009 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 17010 * {@link android.os.Handler} should override this method, call 17011 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 17012 * </p> 17013 */ 17014 public void onCancelPendingInputEvents() { 17015 removePerformClickCallback(); 17016 cancelLongPress(); 17017 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 17018 } 17019 17020 /** 17021 * Store this view hierarchy's frozen state into the given container. 17022 * 17023 * @param container The SparseArray in which to save the view's state. 17024 * 17025 * @see #restoreHierarchyState(android.util.SparseArray) 17026 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17027 * @see #onSaveInstanceState() 17028 */ 17029 public void saveHierarchyState(SparseArray<Parcelable> container) { 17030 dispatchSaveInstanceState(container); 17031 } 17032 17033 /** 17034 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 17035 * this view and its children. May be overridden to modify how freezing happens to a 17036 * view's children; for example, some views may want to not store state for their children. 17037 * 17038 * @param container The SparseArray in which to save the view's state. 17039 * 17040 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17041 * @see #saveHierarchyState(android.util.SparseArray) 17042 * @see #onSaveInstanceState() 17043 */ 17044 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 17045 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 17046 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17047 Parcelable state = onSaveInstanceState(); 17048 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17049 throw new IllegalStateException( 17050 "Derived class did not call super.onSaveInstanceState()"); 17051 } 17052 if (state != null) { 17053 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 17054 // + ": " + state); 17055 container.put(mID, state); 17056 } 17057 } 17058 } 17059 17060 /** 17061 * Hook allowing a view to generate a representation of its internal state 17062 * that can later be used to create a new instance with that same state. 17063 * This state should only contain information that is not persistent or can 17064 * not be reconstructed later. For example, you will never store your 17065 * current position on screen because that will be computed again when a 17066 * new instance of the view is placed in its view hierarchy. 17067 * <p> 17068 * Some examples of things you may store here: the current cursor position 17069 * in a text view (but usually not the text itself since that is stored in a 17070 * content provider or other persistent storage), the currently selected 17071 * item in a list view. 17072 * 17073 * @return Returns a Parcelable object containing the view's current dynamic 17074 * state, or null if there is nothing interesting to save. The 17075 * default implementation returns null. 17076 * @see #onRestoreInstanceState(android.os.Parcelable) 17077 * @see #saveHierarchyState(android.util.SparseArray) 17078 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17079 * @see #setSaveEnabled(boolean) 17080 */ 17081 @CallSuper 17082 protected Parcelable onSaveInstanceState() { 17083 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17084 if (mStartActivityRequestWho != null) { 17085 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 17086 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 17087 return state; 17088 } 17089 return BaseSavedState.EMPTY_STATE; 17090 } 17091 17092 /** 17093 * Restore this view hierarchy's frozen state from the given container. 17094 * 17095 * @param container The SparseArray which holds previously frozen states. 17096 * 17097 * @see #saveHierarchyState(android.util.SparseArray) 17098 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17099 * @see #onRestoreInstanceState(android.os.Parcelable) 17100 */ 17101 public void restoreHierarchyState(SparseArray<Parcelable> container) { 17102 dispatchRestoreInstanceState(container); 17103 } 17104 17105 /** 17106 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 17107 * state for this view and its children. May be overridden to modify how restoring 17108 * happens to a view's children; for example, some views may want to not store state 17109 * for their children. 17110 * 17111 * @param container The SparseArray which holds previously saved state. 17112 * 17113 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17114 * @see #restoreHierarchyState(android.util.SparseArray) 17115 * @see #onRestoreInstanceState(android.os.Parcelable) 17116 */ 17117 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 17118 if (mID != NO_ID) { 17119 Parcelable state = container.get(mID); 17120 if (state != null) { 17121 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 17122 // + ": " + state); 17123 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17124 onRestoreInstanceState(state); 17125 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17126 throw new IllegalStateException( 17127 "Derived class did not call super.onRestoreInstanceState()"); 17128 } 17129 } 17130 } 17131 } 17132 17133 /** 17134 * Hook allowing a view to re-apply a representation of its internal state that had previously 17135 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 17136 * null state. 17137 * 17138 * @param state The frozen state that had previously been returned by 17139 * {@link #onSaveInstanceState}. 17140 * 17141 * @see #onSaveInstanceState() 17142 * @see #restoreHierarchyState(android.util.SparseArray) 17143 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17144 */ 17145 @CallSuper 17146 protected void onRestoreInstanceState(Parcelable state) { 17147 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17148 if (state != null && !(state instanceof AbsSavedState)) { 17149 throw new IllegalArgumentException("Wrong state class, expecting View State but " 17150 + "received " + state.getClass().toString() + " instead. This usually happens " 17151 + "when two views of different type have the same id in the same hierarchy. " 17152 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 17153 + "other views do not use the same id."); 17154 } 17155 if (state != null && state instanceof BaseSavedState) { 17156 mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved; 17157 } 17158 } 17159 17160 /** 17161 * <p>Return the time at which the drawing of the view hierarchy started.</p> 17162 * 17163 * @return the drawing start time in milliseconds 17164 */ 17165 public long getDrawingTime() { 17166 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 17167 } 17168 17169 /** 17170 * <p>Enables or disables the duplication of the parent's state into this view. When 17171 * duplication is enabled, this view gets its drawable state from its parent rather 17172 * than from its own internal properties.</p> 17173 * 17174 * <p>Note: in the current implementation, setting this property to true after the 17175 * view was added to a ViewGroup might have no effect at all. This property should 17176 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 17177 * 17178 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 17179 * property is enabled, an exception will be thrown.</p> 17180 * 17181 * <p>Note: if the child view uses and updates additional states which are unknown to the 17182 * parent, these states should not be affected by this method.</p> 17183 * 17184 * @param enabled True to enable duplication of the parent's drawable state, false 17185 * to disable it. 17186 * 17187 * @see #getDrawableState() 17188 * @see #isDuplicateParentStateEnabled() 17189 */ 17190 public void setDuplicateParentStateEnabled(boolean enabled) { 17191 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 17192 } 17193 17194 /** 17195 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 17196 * 17197 * @return True if this view's drawable state is duplicated from the parent, 17198 * false otherwise 17199 * 17200 * @see #getDrawableState() 17201 * @see #setDuplicateParentStateEnabled(boolean) 17202 */ 17203 public boolean isDuplicateParentStateEnabled() { 17204 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 17205 } 17206 17207 /** 17208 * <p>Specifies the type of layer backing this view. The layer can be 17209 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17210 * {@link #LAYER_TYPE_HARDWARE}.</p> 17211 * 17212 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17213 * instance that controls how the layer is composed on screen. The following 17214 * properties of the paint are taken into account when composing the layer:</p> 17215 * <ul> 17216 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17217 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17218 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17219 * </ul> 17220 * 17221 * <p>If this view has an alpha value set to < 1.0 by calling 17222 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 17223 * by this view's alpha value.</p> 17224 * 17225 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 17226 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 17227 * for more information on when and how to use layers.</p> 17228 * 17229 * @param layerType The type of layer to use with this view, must be one of 17230 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17231 * {@link #LAYER_TYPE_HARDWARE} 17232 * @param paint The paint used to compose the layer. This argument is optional 17233 * and can be null. It is ignored when the layer type is 17234 * {@link #LAYER_TYPE_NONE} 17235 * 17236 * @see #getLayerType() 17237 * @see #LAYER_TYPE_NONE 17238 * @see #LAYER_TYPE_SOFTWARE 17239 * @see #LAYER_TYPE_HARDWARE 17240 * @see #setAlpha(float) 17241 * 17242 * @attr ref android.R.styleable#View_layerType 17243 */ 17244 public void setLayerType(int layerType, @Nullable Paint paint) { 17245 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 17246 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 17247 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 17248 } 17249 17250 boolean typeChanged = mRenderNode.setLayerType(layerType); 17251 17252 if (!typeChanged) { 17253 setLayerPaint(paint); 17254 return; 17255 } 17256 17257 if (layerType != LAYER_TYPE_SOFTWARE) { 17258 // Destroy any previous software drawing cache if present 17259 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 17260 // drawing cache created in View#draw when drawing to a SW canvas. 17261 destroyDrawingCache(); 17262 } 17263 17264 mLayerType = layerType; 17265 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 17266 mRenderNode.setLayerPaint(mLayerPaint); 17267 17268 // draw() behaves differently if we are on a layer, so we need to 17269 // invalidate() here 17270 invalidateParentCaches(); 17271 invalidate(true); 17272 } 17273 17274 /** 17275 * Updates the {@link Paint} object used with the current layer (used only if the current 17276 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 17277 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 17278 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 17279 * ensure that the view gets redrawn immediately. 17280 * 17281 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17282 * instance that controls how the layer is composed on screen. The following 17283 * properties of the paint are taken into account when composing the layer:</p> 17284 * <ul> 17285 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17286 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17287 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17288 * </ul> 17289 * 17290 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 17291 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 17292 * 17293 * @param paint The paint used to compose the layer. This argument is optional 17294 * and can be null. It is ignored when the layer type is 17295 * {@link #LAYER_TYPE_NONE} 17296 * 17297 * @see #setLayerType(int, android.graphics.Paint) 17298 */ 17299 public void setLayerPaint(@Nullable Paint paint) { 17300 int layerType = getLayerType(); 17301 if (layerType != LAYER_TYPE_NONE) { 17302 mLayerPaint = paint; 17303 if (layerType == LAYER_TYPE_HARDWARE) { 17304 if (mRenderNode.setLayerPaint(paint)) { 17305 invalidateViewProperty(false, false); 17306 } 17307 } else { 17308 invalidate(); 17309 } 17310 } 17311 } 17312 17313 /** 17314 * Indicates what type of layer is currently associated with this view. By default 17315 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 17316 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 17317 * for more information on the different types of layers. 17318 * 17319 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17320 * {@link #LAYER_TYPE_HARDWARE} 17321 * 17322 * @see #setLayerType(int, android.graphics.Paint) 17323 * @see #buildLayer() 17324 * @see #LAYER_TYPE_NONE 17325 * @see #LAYER_TYPE_SOFTWARE 17326 * @see #LAYER_TYPE_HARDWARE 17327 */ 17328 public int getLayerType() { 17329 return mLayerType; 17330 } 17331 17332 /** 17333 * Forces this view's layer to be created and this view to be rendered 17334 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 17335 * invoking this method will have no effect. 17336 * 17337 * This method can for instance be used to render a view into its layer before 17338 * starting an animation. If this view is complex, rendering into the layer 17339 * before starting the animation will avoid skipping frames. 17340 * 17341 * @throws IllegalStateException If this view is not attached to a window 17342 * 17343 * @see #setLayerType(int, android.graphics.Paint) 17344 */ 17345 public void buildLayer() { 17346 if (mLayerType == LAYER_TYPE_NONE) return; 17347 17348 final AttachInfo attachInfo = mAttachInfo; 17349 if (attachInfo == null) { 17350 throw new IllegalStateException("This view must be attached to a window first"); 17351 } 17352 17353 if (getWidth() == 0 || getHeight() == 0) { 17354 return; 17355 } 17356 17357 switch (mLayerType) { 17358 case LAYER_TYPE_HARDWARE: 17359 updateDisplayListIfDirty(); 17360 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 17361 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 17362 } 17363 break; 17364 case LAYER_TYPE_SOFTWARE: 17365 buildDrawingCache(true); 17366 break; 17367 } 17368 } 17369 17370 /** 17371 * Destroys all hardware rendering resources. This method is invoked 17372 * when the system needs to reclaim resources. Upon execution of this 17373 * method, you should free any OpenGL resources created by the view. 17374 * 17375 * Note: you <strong>must</strong> call 17376 * <code>super.destroyHardwareResources()</code> when overriding 17377 * this method. 17378 * 17379 * @hide 17380 */ 17381 @CallSuper 17382 protected void destroyHardwareResources() { 17383 if (mOverlay != null) { 17384 mOverlay.getOverlayView().destroyHardwareResources(); 17385 } 17386 if (mGhostView != null) { 17387 mGhostView.destroyHardwareResources(); 17388 } 17389 } 17390 17391 /** 17392 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 17393 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 17394 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 17395 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 17396 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 17397 * null.</p> 17398 * 17399 * <p>Enabling the drawing cache is similar to 17400 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 17401 * acceleration is turned off. When hardware acceleration is turned on, enabling the 17402 * drawing cache has no effect on rendering because the system uses a different mechanism 17403 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 17404 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 17405 * for information on how to enable software and hardware layers.</p> 17406 * 17407 * <p>This API can be used to manually generate 17408 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 17409 * {@link #getDrawingCache()}.</p> 17410 * 17411 * @param enabled true to enable the drawing cache, false otherwise 17412 * 17413 * @see #isDrawingCacheEnabled() 17414 * @see #getDrawingCache() 17415 * @see #buildDrawingCache() 17416 * @see #setLayerType(int, android.graphics.Paint) 17417 */ 17418 public void setDrawingCacheEnabled(boolean enabled) { 17419 mCachingFailed = false; 17420 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 17421 } 17422 17423 /** 17424 * <p>Indicates whether the drawing cache is enabled for this view.</p> 17425 * 17426 * @return true if the drawing cache is enabled 17427 * 17428 * @see #setDrawingCacheEnabled(boolean) 17429 * @see #getDrawingCache() 17430 */ 17431 @ViewDebug.ExportedProperty(category = "drawing") 17432 public boolean isDrawingCacheEnabled() { 17433 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 17434 } 17435 17436 /** 17437 * Debugging utility which recursively outputs the dirty state of a view and its 17438 * descendants. 17439 * 17440 * @hide 17441 */ 17442 @SuppressWarnings({"UnusedDeclaration"}) 17443 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 17444 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 17445 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 17446 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 17447 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 17448 if (clear) { 17449 mPrivateFlags &= clearMask; 17450 } 17451 if (this instanceof ViewGroup) { 17452 ViewGroup parent = (ViewGroup) this; 17453 final int count = parent.getChildCount(); 17454 for (int i = 0; i < count; i++) { 17455 final View child = parent.getChildAt(i); 17456 child.outputDirtyFlags(indent + " ", clear, clearMask); 17457 } 17458 } 17459 } 17460 17461 /** 17462 * This method is used by ViewGroup to cause its children to restore or recreate their 17463 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 17464 * to recreate its own display list, which would happen if it went through the normal 17465 * draw/dispatchDraw mechanisms. 17466 * 17467 * @hide 17468 */ 17469 protected void dispatchGetDisplayList() {} 17470 17471 /** 17472 * A view that is not attached or hardware accelerated cannot create a display list. 17473 * This method checks these conditions and returns the appropriate result. 17474 * 17475 * @return true if view has the ability to create a display list, false otherwise. 17476 * 17477 * @hide 17478 */ 17479 public boolean canHaveDisplayList() { 17480 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 17481 } 17482 17483 /** 17484 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 17485 * @hide 17486 */ 17487 @NonNull 17488 public RenderNode updateDisplayListIfDirty() { 17489 final RenderNode renderNode = mRenderNode; 17490 if (!canHaveDisplayList()) { 17491 // can't populate RenderNode, don't try 17492 return renderNode; 17493 } 17494 17495 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 17496 || !renderNode.isValid() 17497 || (mRecreateDisplayList)) { 17498 // Don't need to recreate the display list, just need to tell our 17499 // children to restore/recreate theirs 17500 if (renderNode.isValid() 17501 && !mRecreateDisplayList) { 17502 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 17503 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17504 dispatchGetDisplayList(); 17505 17506 return renderNode; // no work needed 17507 } 17508 17509 // If we got here, we're recreating it. Mark it as such to ensure that 17510 // we copy in child display lists into ours in drawChild() 17511 mRecreateDisplayList = true; 17512 17513 int width = mRight - mLeft; 17514 int height = mBottom - mTop; 17515 int layerType = getLayerType(); 17516 17517 final DisplayListCanvas canvas = renderNode.start(width, height); 17518 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 17519 17520 try { 17521 if (layerType == LAYER_TYPE_SOFTWARE) { 17522 buildDrawingCache(true); 17523 Bitmap cache = getDrawingCache(true); 17524 if (cache != null) { 17525 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 17526 } 17527 } else { 17528 computeScroll(); 17529 17530 canvas.translate(-mScrollX, -mScrollY); 17531 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 17532 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17533 17534 // Fast path for layouts with no backgrounds 17535 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17536 dispatchDraw(canvas); 17537 if (mOverlay != null && !mOverlay.isEmpty()) { 17538 mOverlay.getOverlayView().draw(canvas); 17539 } 17540 if (debugDraw()) { 17541 debugDrawFocus(canvas); 17542 } 17543 } else { 17544 draw(canvas); 17545 } 17546 } 17547 } finally { 17548 renderNode.end(canvas); 17549 setDisplayListProperties(renderNode); 17550 } 17551 } else { 17552 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 17553 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17554 } 17555 return renderNode; 17556 } 17557 17558 private void resetDisplayList() { 17559 mRenderNode.discardDisplayList(); 17560 if (mBackgroundRenderNode != null) { 17561 mBackgroundRenderNode.discardDisplayList(); 17562 } 17563 } 17564 17565 /** 17566 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 17567 * 17568 * @return A non-scaled bitmap representing this view or null if cache is disabled. 17569 * 17570 * @see #getDrawingCache(boolean) 17571 */ 17572 public Bitmap getDrawingCache() { 17573 return getDrawingCache(false); 17574 } 17575 17576 /** 17577 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 17578 * is null when caching is disabled. If caching is enabled and the cache is not ready, 17579 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 17580 * draw from the cache when the cache is enabled. To benefit from the cache, you must 17581 * request the drawing cache by calling this method and draw it on screen if the 17582 * returned bitmap is not null.</p> 17583 * 17584 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 17585 * this method will create a bitmap of the same size as this view. Because this bitmap 17586 * will be drawn scaled by the parent ViewGroup, the result on screen might show 17587 * scaling artifacts. To avoid such artifacts, you should call this method by setting 17588 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 17589 * size than the view. This implies that your application must be able to handle this 17590 * size.</p> 17591 * 17592 * @param autoScale Indicates whether the generated bitmap should be scaled based on 17593 * the current density of the screen when the application is in compatibility 17594 * mode. 17595 * 17596 * @return A bitmap representing this view or null if cache is disabled. 17597 * 17598 * @see #setDrawingCacheEnabled(boolean) 17599 * @see #isDrawingCacheEnabled() 17600 * @see #buildDrawingCache(boolean) 17601 * @see #destroyDrawingCache() 17602 */ 17603 public Bitmap getDrawingCache(boolean autoScale) { 17604 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 17605 return null; 17606 } 17607 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 17608 buildDrawingCache(autoScale); 17609 } 17610 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 17611 } 17612 17613 /** 17614 * <p>Frees the resources used by the drawing cache. If you call 17615 * {@link #buildDrawingCache()} manually without calling 17616 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 17617 * should cleanup the cache with this method afterwards.</p> 17618 * 17619 * @see #setDrawingCacheEnabled(boolean) 17620 * @see #buildDrawingCache() 17621 * @see #getDrawingCache() 17622 */ 17623 public void destroyDrawingCache() { 17624 if (mDrawingCache != null) { 17625 mDrawingCache.recycle(); 17626 mDrawingCache = null; 17627 } 17628 if (mUnscaledDrawingCache != null) { 17629 mUnscaledDrawingCache.recycle(); 17630 mUnscaledDrawingCache = null; 17631 } 17632 } 17633 17634 /** 17635 * Setting a solid background color for the drawing cache's bitmaps will improve 17636 * performance and memory usage. Note, though that this should only be used if this 17637 * view will always be drawn on top of a solid color. 17638 * 17639 * @param color The background color to use for the drawing cache's bitmap 17640 * 17641 * @see #setDrawingCacheEnabled(boolean) 17642 * @see #buildDrawingCache() 17643 * @see #getDrawingCache() 17644 */ 17645 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 17646 if (color != mDrawingCacheBackgroundColor) { 17647 mDrawingCacheBackgroundColor = color; 17648 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 17649 } 17650 } 17651 17652 /** 17653 * @see #setDrawingCacheBackgroundColor(int) 17654 * 17655 * @return The background color to used for the drawing cache's bitmap 17656 */ 17657 @ColorInt 17658 public int getDrawingCacheBackgroundColor() { 17659 return mDrawingCacheBackgroundColor; 17660 } 17661 17662 /** 17663 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 17664 * 17665 * @see #buildDrawingCache(boolean) 17666 */ 17667 public void buildDrawingCache() { 17668 buildDrawingCache(false); 17669 } 17670 17671 /** 17672 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 17673 * 17674 * <p>If you call {@link #buildDrawingCache()} manually without calling 17675 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 17676 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 17677 * 17678 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 17679 * this method will create a bitmap of the same size as this view. Because this bitmap 17680 * will be drawn scaled by the parent ViewGroup, the result on screen might show 17681 * scaling artifacts. To avoid such artifacts, you should call this method by setting 17682 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 17683 * size than the view. This implies that your application must be able to handle this 17684 * size.</p> 17685 * 17686 * <p>You should avoid calling this method when hardware acceleration is enabled. If 17687 * you do not need the drawing cache bitmap, calling this method will increase memory 17688 * usage and cause the view to be rendered in software once, thus negatively impacting 17689 * performance.</p> 17690 * 17691 * @see #getDrawingCache() 17692 * @see #destroyDrawingCache() 17693 */ 17694 public void buildDrawingCache(boolean autoScale) { 17695 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 17696 mDrawingCache == null : mUnscaledDrawingCache == null)) { 17697 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 17698 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 17699 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 17700 } 17701 try { 17702 buildDrawingCacheImpl(autoScale); 17703 } finally { 17704 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 17705 } 17706 } 17707 } 17708 17709 /** 17710 * private, internal implementation of buildDrawingCache, used to enable tracing 17711 */ 17712 private void buildDrawingCacheImpl(boolean autoScale) { 17713 mCachingFailed = false; 17714 17715 int width = mRight - mLeft; 17716 int height = mBottom - mTop; 17717 17718 final AttachInfo attachInfo = mAttachInfo; 17719 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 17720 17721 if (autoScale && scalingRequired) { 17722 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 17723 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 17724 } 17725 17726 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 17727 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 17728 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 17729 17730 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 17731 final long drawingCacheSize = 17732 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 17733 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 17734 if (width > 0 && height > 0) { 17735 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 17736 + " too large to fit into a software layer (or drawing cache), needs " 17737 + projectedBitmapSize + " bytes, only " 17738 + drawingCacheSize + " available"); 17739 } 17740 destroyDrawingCache(); 17741 mCachingFailed = true; 17742 return; 17743 } 17744 17745 boolean clear = true; 17746 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 17747 17748 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 17749 Bitmap.Config quality; 17750 if (!opaque) { 17751 // Never pick ARGB_4444 because it looks awful 17752 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 17753 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 17754 case DRAWING_CACHE_QUALITY_AUTO: 17755 case DRAWING_CACHE_QUALITY_LOW: 17756 case DRAWING_CACHE_QUALITY_HIGH: 17757 default: 17758 quality = Bitmap.Config.ARGB_8888; 17759 break; 17760 } 17761 } else { 17762 // Optimization for translucent windows 17763 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 17764 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 17765 } 17766 17767 // Try to cleanup memory 17768 if (bitmap != null) bitmap.recycle(); 17769 17770 try { 17771 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17772 width, height, quality); 17773 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 17774 if (autoScale) { 17775 mDrawingCache = bitmap; 17776 } else { 17777 mUnscaledDrawingCache = bitmap; 17778 } 17779 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 17780 } catch (OutOfMemoryError e) { 17781 // If there is not enough memory to create the bitmap cache, just 17782 // ignore the issue as bitmap caches are not required to draw the 17783 // view hierarchy 17784 if (autoScale) { 17785 mDrawingCache = null; 17786 } else { 17787 mUnscaledDrawingCache = null; 17788 } 17789 mCachingFailed = true; 17790 return; 17791 } 17792 17793 clear = drawingCacheBackgroundColor != 0; 17794 } 17795 17796 Canvas canvas; 17797 if (attachInfo != null) { 17798 canvas = attachInfo.mCanvas; 17799 if (canvas == null) { 17800 canvas = new Canvas(); 17801 } 17802 canvas.setBitmap(bitmap); 17803 // Temporarily clobber the cached Canvas in case one of our children 17804 // is also using a drawing cache. Without this, the children would 17805 // steal the canvas by attaching their own bitmap to it and bad, bad 17806 // thing would happen (invisible views, corrupted drawings, etc.) 17807 attachInfo.mCanvas = null; 17808 } else { 17809 // This case should hopefully never or seldom happen 17810 canvas = new Canvas(bitmap); 17811 } 17812 17813 if (clear) { 17814 bitmap.eraseColor(drawingCacheBackgroundColor); 17815 } 17816 17817 computeScroll(); 17818 final int restoreCount = canvas.save(); 17819 17820 if (autoScale && scalingRequired) { 17821 final float scale = attachInfo.mApplicationScale; 17822 canvas.scale(scale, scale); 17823 } 17824 17825 canvas.translate(-mScrollX, -mScrollY); 17826 17827 mPrivateFlags |= PFLAG_DRAWN; 17828 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 17829 mLayerType != LAYER_TYPE_NONE) { 17830 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 17831 } 17832 17833 // Fast path for layouts with no backgrounds 17834 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17835 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17836 dispatchDraw(canvas); 17837 if (mOverlay != null && !mOverlay.isEmpty()) { 17838 mOverlay.getOverlayView().draw(canvas); 17839 } 17840 } else { 17841 draw(canvas); 17842 } 17843 17844 canvas.restoreToCount(restoreCount); 17845 canvas.setBitmap(null); 17846 17847 if (attachInfo != null) { 17848 // Restore the cached Canvas for our siblings 17849 attachInfo.mCanvas = canvas; 17850 } 17851 } 17852 17853 /** 17854 * Create a snapshot of the view into a bitmap. We should probably make 17855 * some form of this public, but should think about the API. 17856 * 17857 * @hide 17858 */ 17859 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 17860 int width = mRight - mLeft; 17861 int height = mBottom - mTop; 17862 17863 final AttachInfo attachInfo = mAttachInfo; 17864 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 17865 width = (int) ((width * scale) + 0.5f); 17866 height = (int) ((height * scale) + 0.5f); 17867 17868 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17869 width > 0 ? width : 1, height > 0 ? height : 1, quality); 17870 if (bitmap == null) { 17871 throw new OutOfMemoryError(); 17872 } 17873 17874 Resources resources = getResources(); 17875 if (resources != null) { 17876 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 17877 } 17878 17879 Canvas canvas; 17880 if (attachInfo != null) { 17881 canvas = attachInfo.mCanvas; 17882 if (canvas == null) { 17883 canvas = new Canvas(); 17884 } 17885 canvas.setBitmap(bitmap); 17886 // Temporarily clobber the cached Canvas in case one of our children 17887 // is also using a drawing cache. Without this, the children would 17888 // steal the canvas by attaching their own bitmap to it and bad, bad 17889 // things would happen (invisible views, corrupted drawings, etc.) 17890 attachInfo.mCanvas = null; 17891 } else { 17892 // This case should hopefully never or seldom happen 17893 canvas = new Canvas(bitmap); 17894 } 17895 17896 if ((backgroundColor & 0xff000000) != 0) { 17897 bitmap.eraseColor(backgroundColor); 17898 } 17899 17900 computeScroll(); 17901 final int restoreCount = canvas.save(); 17902 canvas.scale(scale, scale); 17903 canvas.translate(-mScrollX, -mScrollY); 17904 17905 // Temporarily remove the dirty mask 17906 int flags = mPrivateFlags; 17907 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17908 17909 // Fast path for layouts with no backgrounds 17910 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17911 dispatchDraw(canvas); 17912 if (mOverlay != null && !mOverlay.isEmpty()) { 17913 mOverlay.getOverlayView().draw(canvas); 17914 } 17915 } else { 17916 draw(canvas); 17917 } 17918 17919 mPrivateFlags = flags; 17920 17921 canvas.restoreToCount(restoreCount); 17922 canvas.setBitmap(null); 17923 17924 if (attachInfo != null) { 17925 // Restore the cached Canvas for our siblings 17926 attachInfo.mCanvas = canvas; 17927 } 17928 17929 return bitmap; 17930 } 17931 17932 /** 17933 * Indicates whether this View is currently in edit mode. A View is usually 17934 * in edit mode when displayed within a developer tool. For instance, if 17935 * this View is being drawn by a visual user interface builder, this method 17936 * should return true. 17937 * 17938 * Subclasses should check the return value of this method to provide 17939 * different behaviors if their normal behavior might interfere with the 17940 * host environment. For instance: the class spawns a thread in its 17941 * constructor, the drawing code relies on device-specific features, etc. 17942 * 17943 * This method is usually checked in the drawing code of custom widgets. 17944 * 17945 * @return True if this View is in edit mode, false otherwise. 17946 */ 17947 public boolean isInEditMode() { 17948 return false; 17949 } 17950 17951 /** 17952 * If the View draws content inside its padding and enables fading edges, 17953 * it needs to support padding offsets. Padding offsets are added to the 17954 * fading edges to extend the length of the fade so that it covers pixels 17955 * drawn inside the padding. 17956 * 17957 * Subclasses of this class should override this method if they need 17958 * to draw content inside the padding. 17959 * 17960 * @return True if padding offset must be applied, false otherwise. 17961 * 17962 * @see #getLeftPaddingOffset() 17963 * @see #getRightPaddingOffset() 17964 * @see #getTopPaddingOffset() 17965 * @see #getBottomPaddingOffset() 17966 * 17967 * @since CURRENT 17968 */ 17969 protected boolean isPaddingOffsetRequired() { 17970 return false; 17971 } 17972 17973 /** 17974 * Amount by which to extend the left fading region. Called only when 17975 * {@link #isPaddingOffsetRequired()} returns true. 17976 * 17977 * @return The left padding offset in pixels. 17978 * 17979 * @see #isPaddingOffsetRequired() 17980 * 17981 * @since CURRENT 17982 */ 17983 protected int getLeftPaddingOffset() { 17984 return 0; 17985 } 17986 17987 /** 17988 * Amount by which to extend the right fading region. Called only when 17989 * {@link #isPaddingOffsetRequired()} returns true. 17990 * 17991 * @return The right padding offset in pixels. 17992 * 17993 * @see #isPaddingOffsetRequired() 17994 * 17995 * @since CURRENT 17996 */ 17997 protected int getRightPaddingOffset() { 17998 return 0; 17999 } 18000 18001 /** 18002 * Amount by which to extend the top fading region. Called only when 18003 * {@link #isPaddingOffsetRequired()} returns true. 18004 * 18005 * @return The top padding offset in pixels. 18006 * 18007 * @see #isPaddingOffsetRequired() 18008 * 18009 * @since CURRENT 18010 */ 18011 protected int getTopPaddingOffset() { 18012 return 0; 18013 } 18014 18015 /** 18016 * Amount by which to extend the bottom fading region. Called only when 18017 * {@link #isPaddingOffsetRequired()} returns true. 18018 * 18019 * @return The bottom padding offset in pixels. 18020 * 18021 * @see #isPaddingOffsetRequired() 18022 * 18023 * @since CURRENT 18024 */ 18025 protected int getBottomPaddingOffset() { 18026 return 0; 18027 } 18028 18029 /** 18030 * @hide 18031 * @param offsetRequired 18032 */ 18033 protected int getFadeTop(boolean offsetRequired) { 18034 int top = mPaddingTop; 18035 if (offsetRequired) top += getTopPaddingOffset(); 18036 return top; 18037 } 18038 18039 /** 18040 * @hide 18041 * @param offsetRequired 18042 */ 18043 protected int getFadeHeight(boolean offsetRequired) { 18044 int padding = mPaddingTop; 18045 if (offsetRequired) padding += getTopPaddingOffset(); 18046 return mBottom - mTop - mPaddingBottom - padding; 18047 } 18048 18049 /** 18050 * <p>Indicates whether this view is attached to a hardware accelerated 18051 * window or not.</p> 18052 * 18053 * <p>Even if this method returns true, it does not mean that every call 18054 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 18055 * accelerated {@link android.graphics.Canvas}. For instance, if this view 18056 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 18057 * window is hardware accelerated, 18058 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 18059 * return false, and this method will return true.</p> 18060 * 18061 * @return True if the view is attached to a window and the window is 18062 * hardware accelerated; false in any other case. 18063 */ 18064 @ViewDebug.ExportedProperty(category = "drawing") 18065 public boolean isHardwareAccelerated() { 18066 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 18067 } 18068 18069 /** 18070 * Sets a rectangular area on this view to which the view will be clipped 18071 * when it is drawn. Setting the value to null will remove the clip bounds 18072 * and the view will draw normally, using its full bounds. 18073 * 18074 * @param clipBounds The rectangular area, in the local coordinates of 18075 * this view, to which future drawing operations will be clipped. 18076 */ 18077 public void setClipBounds(Rect clipBounds) { 18078 if (clipBounds == mClipBounds 18079 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 18080 return; 18081 } 18082 if (clipBounds != null) { 18083 if (mClipBounds == null) { 18084 mClipBounds = new Rect(clipBounds); 18085 } else { 18086 mClipBounds.set(clipBounds); 18087 } 18088 } else { 18089 mClipBounds = null; 18090 } 18091 mRenderNode.setClipBounds(mClipBounds); 18092 invalidateViewProperty(false, false); 18093 } 18094 18095 /** 18096 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 18097 * 18098 * @return A copy of the current clip bounds if clip bounds are set, 18099 * otherwise null. 18100 */ 18101 public Rect getClipBounds() { 18102 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 18103 } 18104 18105 18106 /** 18107 * Populates an output rectangle with the clip bounds of the view, 18108 * returning {@code true} if successful or {@code false} if the view's 18109 * clip bounds are {@code null}. 18110 * 18111 * @param outRect rectangle in which to place the clip bounds of the view 18112 * @return {@code true} if successful or {@code false} if the view's 18113 * clip bounds are {@code null} 18114 */ 18115 public boolean getClipBounds(Rect outRect) { 18116 if (mClipBounds != null) { 18117 outRect.set(mClipBounds); 18118 return true; 18119 } 18120 return false; 18121 } 18122 18123 /** 18124 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 18125 * case of an active Animation being run on the view. 18126 */ 18127 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 18128 Animation a, boolean scalingRequired) { 18129 Transformation invalidationTransform; 18130 final int flags = parent.mGroupFlags; 18131 final boolean initialized = a.isInitialized(); 18132 if (!initialized) { 18133 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 18134 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 18135 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 18136 onAnimationStart(); 18137 } 18138 18139 final Transformation t = parent.getChildTransformation(); 18140 boolean more = a.getTransformation(drawingTime, t, 1f); 18141 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 18142 if (parent.mInvalidationTransformation == null) { 18143 parent.mInvalidationTransformation = new Transformation(); 18144 } 18145 invalidationTransform = parent.mInvalidationTransformation; 18146 a.getTransformation(drawingTime, invalidationTransform, 1f); 18147 } else { 18148 invalidationTransform = t; 18149 } 18150 18151 if (more) { 18152 if (!a.willChangeBounds()) { 18153 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 18154 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 18155 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 18156 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 18157 // The child need to draw an animation, potentially offscreen, so 18158 // make sure we do not cancel invalidate requests 18159 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18160 parent.invalidate(mLeft, mTop, mRight, mBottom); 18161 } 18162 } else { 18163 if (parent.mInvalidateRegion == null) { 18164 parent.mInvalidateRegion = new RectF(); 18165 } 18166 final RectF region = parent.mInvalidateRegion; 18167 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 18168 invalidationTransform); 18169 18170 // The child need to draw an animation, potentially offscreen, so 18171 // make sure we do not cancel invalidate requests 18172 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18173 18174 final int left = mLeft + (int) region.left; 18175 final int top = mTop + (int) region.top; 18176 parent.invalidate(left, top, left + (int) (region.width() + .5f), 18177 top + (int) (region.height() + .5f)); 18178 } 18179 } 18180 return more; 18181 } 18182 18183 /** 18184 * This method is called by getDisplayList() when a display list is recorded for a View. 18185 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 18186 */ 18187 void setDisplayListProperties(RenderNode renderNode) { 18188 if (renderNode != null) { 18189 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 18190 renderNode.setClipToBounds(mParent instanceof ViewGroup 18191 && ((ViewGroup) mParent).getClipChildren()); 18192 18193 float alpha = 1; 18194 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 18195 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18196 ViewGroup parentVG = (ViewGroup) mParent; 18197 final Transformation t = parentVG.getChildTransformation(); 18198 if (parentVG.getChildStaticTransformation(this, t)) { 18199 final int transformType = t.getTransformationType(); 18200 if (transformType != Transformation.TYPE_IDENTITY) { 18201 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 18202 alpha = t.getAlpha(); 18203 } 18204 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 18205 renderNode.setStaticMatrix(t.getMatrix()); 18206 } 18207 } 18208 } 18209 } 18210 if (mTransformationInfo != null) { 18211 alpha *= getFinalAlpha(); 18212 if (alpha < 1) { 18213 final int multipliedAlpha = (int) (255 * alpha); 18214 if (onSetAlpha(multipliedAlpha)) { 18215 alpha = 1; 18216 } 18217 } 18218 renderNode.setAlpha(alpha); 18219 } else if (alpha < 1) { 18220 renderNode.setAlpha(alpha); 18221 } 18222 } 18223 } 18224 18225 /** 18226 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 18227 * 18228 * This is where the View specializes rendering behavior based on layer type, 18229 * and hardware acceleration. 18230 */ 18231 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 18232 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 18233 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 18234 * 18235 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 18236 * HW accelerated, it can't handle drawing RenderNodes. 18237 */ 18238 boolean drawingWithRenderNode = mAttachInfo != null 18239 && mAttachInfo.mHardwareAccelerated 18240 && hardwareAcceleratedCanvas; 18241 18242 boolean more = false; 18243 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 18244 final int parentFlags = parent.mGroupFlags; 18245 18246 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 18247 parent.getChildTransformation().clear(); 18248 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18249 } 18250 18251 Transformation transformToApply = null; 18252 boolean concatMatrix = false; 18253 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 18254 final Animation a = getAnimation(); 18255 if (a != null) { 18256 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 18257 concatMatrix = a.willChangeTransformationMatrix(); 18258 if (concatMatrix) { 18259 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18260 } 18261 transformToApply = parent.getChildTransformation(); 18262 } else { 18263 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 18264 // No longer animating: clear out old animation matrix 18265 mRenderNode.setAnimationMatrix(null); 18266 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18267 } 18268 if (!drawingWithRenderNode 18269 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18270 final Transformation t = parent.getChildTransformation(); 18271 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 18272 if (hasTransform) { 18273 final int transformType = t.getTransformationType(); 18274 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 18275 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 18276 } 18277 } 18278 } 18279 18280 concatMatrix |= !childHasIdentityMatrix; 18281 18282 // Sets the flag as early as possible to allow draw() implementations 18283 // to call invalidate() successfully when doing animations 18284 mPrivateFlags |= PFLAG_DRAWN; 18285 18286 if (!concatMatrix && 18287 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 18288 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 18289 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 18290 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 18291 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 18292 return more; 18293 } 18294 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 18295 18296 if (hardwareAcceleratedCanvas) { 18297 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 18298 // retain the flag's value temporarily in the mRecreateDisplayList flag 18299 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 18300 mPrivateFlags &= ~PFLAG_INVALIDATED; 18301 } 18302 18303 RenderNode renderNode = null; 18304 Bitmap cache = null; 18305 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 18306 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 18307 if (layerType != LAYER_TYPE_NONE) { 18308 // If not drawing with RenderNode, treat HW layers as SW 18309 layerType = LAYER_TYPE_SOFTWARE; 18310 buildDrawingCache(true); 18311 } 18312 cache = getDrawingCache(true); 18313 } 18314 18315 if (drawingWithRenderNode) { 18316 // Delay getting the display list until animation-driven alpha values are 18317 // set up and possibly passed on to the view 18318 renderNode = updateDisplayListIfDirty(); 18319 if (!renderNode.isValid()) { 18320 // Uncommon, but possible. If a view is removed from the hierarchy during the call 18321 // to getDisplayList(), the display list will be marked invalid and we should not 18322 // try to use it again. 18323 renderNode = null; 18324 drawingWithRenderNode = false; 18325 } 18326 } 18327 18328 int sx = 0; 18329 int sy = 0; 18330 if (!drawingWithRenderNode) { 18331 computeScroll(); 18332 sx = mScrollX; 18333 sy = mScrollY; 18334 } 18335 18336 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 18337 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 18338 18339 int restoreTo = -1; 18340 if (!drawingWithRenderNode || transformToApply != null) { 18341 restoreTo = canvas.save(); 18342 } 18343 if (offsetForScroll) { 18344 canvas.translate(mLeft - sx, mTop - sy); 18345 } else { 18346 if (!drawingWithRenderNode) { 18347 canvas.translate(mLeft, mTop); 18348 } 18349 if (scalingRequired) { 18350 if (drawingWithRenderNode) { 18351 // TODO: Might not need this if we put everything inside the DL 18352 restoreTo = canvas.save(); 18353 } 18354 // mAttachInfo cannot be null, otherwise scalingRequired == false 18355 final float scale = 1.0f / mAttachInfo.mApplicationScale; 18356 canvas.scale(scale, scale); 18357 } 18358 } 18359 18360 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 18361 if (transformToApply != null 18362 || alpha < 1 18363 || !hasIdentityMatrix() 18364 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18365 if (transformToApply != null || !childHasIdentityMatrix) { 18366 int transX = 0; 18367 int transY = 0; 18368 18369 if (offsetForScroll) { 18370 transX = -sx; 18371 transY = -sy; 18372 } 18373 18374 if (transformToApply != null) { 18375 if (concatMatrix) { 18376 if (drawingWithRenderNode) { 18377 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 18378 } else { 18379 // Undo the scroll translation, apply the transformation matrix, 18380 // then redo the scroll translate to get the correct result. 18381 canvas.translate(-transX, -transY); 18382 canvas.concat(transformToApply.getMatrix()); 18383 canvas.translate(transX, transY); 18384 } 18385 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18386 } 18387 18388 float transformAlpha = transformToApply.getAlpha(); 18389 if (transformAlpha < 1) { 18390 alpha *= transformAlpha; 18391 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18392 } 18393 } 18394 18395 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 18396 canvas.translate(-transX, -transY); 18397 canvas.concat(getMatrix()); 18398 canvas.translate(transX, transY); 18399 } 18400 } 18401 18402 // Deal with alpha if it is or used to be <1 18403 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18404 if (alpha < 1) { 18405 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 18406 } else { 18407 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 18408 } 18409 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18410 if (!drawingWithDrawingCache) { 18411 final int multipliedAlpha = (int) (255 * alpha); 18412 if (!onSetAlpha(multipliedAlpha)) { 18413 if (drawingWithRenderNode) { 18414 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 18415 } else if (layerType == LAYER_TYPE_NONE) { 18416 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 18417 multipliedAlpha); 18418 } 18419 } else { 18420 // Alpha is handled by the child directly, clobber the layer's alpha 18421 mPrivateFlags |= PFLAG_ALPHA_SET; 18422 } 18423 } 18424 } 18425 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 18426 onSetAlpha(255); 18427 mPrivateFlags &= ~PFLAG_ALPHA_SET; 18428 } 18429 18430 if (!drawingWithRenderNode) { 18431 // apply clips directly, since RenderNode won't do it for this draw 18432 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 18433 if (offsetForScroll) { 18434 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 18435 } else { 18436 if (!scalingRequired || cache == null) { 18437 canvas.clipRect(0, 0, getWidth(), getHeight()); 18438 } else { 18439 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 18440 } 18441 } 18442 } 18443 18444 if (mClipBounds != null) { 18445 // clip bounds ignore scroll 18446 canvas.clipRect(mClipBounds); 18447 } 18448 } 18449 18450 if (!drawingWithDrawingCache) { 18451 if (drawingWithRenderNode) { 18452 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18453 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18454 } else { 18455 // Fast path for layouts with no backgrounds 18456 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18457 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18458 dispatchDraw(canvas); 18459 } else { 18460 draw(canvas); 18461 } 18462 } 18463 } else if (cache != null) { 18464 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18465 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 18466 // no layer paint, use temporary paint to draw bitmap 18467 Paint cachePaint = parent.mCachePaint; 18468 if (cachePaint == null) { 18469 cachePaint = new Paint(); 18470 cachePaint.setDither(false); 18471 parent.mCachePaint = cachePaint; 18472 } 18473 cachePaint.setAlpha((int) (alpha * 255)); 18474 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 18475 } else { 18476 // use layer paint to draw the bitmap, merging the two alphas, but also restore 18477 int layerPaintAlpha = mLayerPaint.getAlpha(); 18478 if (alpha < 1) { 18479 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 18480 } 18481 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 18482 if (alpha < 1) { 18483 mLayerPaint.setAlpha(layerPaintAlpha); 18484 } 18485 } 18486 } 18487 18488 if (restoreTo >= 0) { 18489 canvas.restoreToCount(restoreTo); 18490 } 18491 18492 if (a != null && !more) { 18493 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 18494 onSetAlpha(255); 18495 } 18496 parent.finishAnimatingView(this, a); 18497 } 18498 18499 if (more && hardwareAcceleratedCanvas) { 18500 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 18501 // alpha animations should cause the child to recreate its display list 18502 invalidate(true); 18503 } 18504 } 18505 18506 mRecreateDisplayList = false; 18507 18508 return more; 18509 } 18510 18511 static Paint getDebugPaint() { 18512 if (sDebugPaint == null) { 18513 sDebugPaint = new Paint(); 18514 sDebugPaint.setAntiAlias(false); 18515 } 18516 return sDebugPaint; 18517 } 18518 18519 final int dipsToPixels(int dips) { 18520 float scale = getContext().getResources().getDisplayMetrics().density; 18521 return (int) (dips * scale + 0.5f); 18522 } 18523 18524 final private void debugDrawFocus(Canvas canvas) { 18525 if (isFocused()) { 18526 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 18527 final int l = mScrollX; 18528 final int r = l + mRight - mLeft; 18529 final int t = mScrollY; 18530 final int b = t + mBottom - mTop; 18531 18532 final Paint paint = getDebugPaint(); 18533 paint.setColor(DEBUG_CORNERS_COLOR); 18534 18535 // Draw squares in corners. 18536 paint.setStyle(Paint.Style.FILL); 18537 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 18538 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 18539 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 18540 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 18541 18542 // Draw big X across the view. 18543 paint.setStyle(Paint.Style.STROKE); 18544 canvas.drawLine(l, t, r, b, paint); 18545 canvas.drawLine(l, b, r, t, paint); 18546 } 18547 } 18548 18549 /** 18550 * Manually render this view (and all of its children) to the given Canvas. 18551 * The view must have already done a full layout before this function is 18552 * called. When implementing a view, implement 18553 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 18554 * If you do need to override this method, call the superclass version. 18555 * 18556 * @param canvas The Canvas to which the View is rendered. 18557 */ 18558 @CallSuper 18559 public void draw(Canvas canvas) { 18560 final int privateFlags = mPrivateFlags; 18561 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 18562 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 18563 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 18564 18565 /* 18566 * Draw traversal performs several drawing steps which must be executed 18567 * in the appropriate order: 18568 * 18569 * 1. Draw the background 18570 * 2. If necessary, save the canvas' layers to prepare for fading 18571 * 3. Draw view's content 18572 * 4. Draw children 18573 * 5. If necessary, draw the fading edges and restore layers 18574 * 6. Draw decorations (scrollbars for instance) 18575 */ 18576 18577 // Step 1, draw the background, if needed 18578 int saveCount; 18579 18580 if (!dirtyOpaque) { 18581 drawBackground(canvas); 18582 } 18583 18584 // skip step 2 & 5 if possible (common case) 18585 final int viewFlags = mViewFlags; 18586 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 18587 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 18588 if (!verticalEdges && !horizontalEdges) { 18589 // Step 3, draw the content 18590 if (!dirtyOpaque) onDraw(canvas); 18591 18592 // Step 4, draw the children 18593 dispatchDraw(canvas); 18594 18595 // Overlay is part of the content and draws beneath Foreground 18596 if (mOverlay != null && !mOverlay.isEmpty()) { 18597 mOverlay.getOverlayView().dispatchDraw(canvas); 18598 } 18599 18600 // Step 6, draw decorations (foreground, scrollbars) 18601 onDrawForeground(canvas); 18602 18603 if (debugDraw()) { 18604 debugDrawFocus(canvas); 18605 } 18606 18607 // we're done... 18608 return; 18609 } 18610 18611 /* 18612 * Here we do the full fledged routine... 18613 * (this is an uncommon case where speed matters less, 18614 * this is why we repeat some of the tests that have been 18615 * done above) 18616 */ 18617 18618 boolean drawTop = false; 18619 boolean drawBottom = false; 18620 boolean drawLeft = false; 18621 boolean drawRight = false; 18622 18623 float topFadeStrength = 0.0f; 18624 float bottomFadeStrength = 0.0f; 18625 float leftFadeStrength = 0.0f; 18626 float rightFadeStrength = 0.0f; 18627 18628 // Step 2, save the canvas' layers 18629 int paddingLeft = mPaddingLeft; 18630 18631 final boolean offsetRequired = isPaddingOffsetRequired(); 18632 if (offsetRequired) { 18633 paddingLeft += getLeftPaddingOffset(); 18634 } 18635 18636 int left = mScrollX + paddingLeft; 18637 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 18638 int top = mScrollY + getFadeTop(offsetRequired); 18639 int bottom = top + getFadeHeight(offsetRequired); 18640 18641 if (offsetRequired) { 18642 right += getRightPaddingOffset(); 18643 bottom += getBottomPaddingOffset(); 18644 } 18645 18646 final ScrollabilityCache scrollabilityCache = mScrollCache; 18647 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 18648 int length = (int) fadeHeight; 18649 18650 // clip the fade length if top and bottom fades overlap 18651 // overlapping fades produce odd-looking artifacts 18652 if (verticalEdges && (top + length > bottom - length)) { 18653 length = (bottom - top) / 2; 18654 } 18655 18656 // also clip horizontal fades if necessary 18657 if (horizontalEdges && (left + length > right - length)) { 18658 length = (right - left) / 2; 18659 } 18660 18661 if (verticalEdges) { 18662 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 18663 drawTop = topFadeStrength * fadeHeight > 1.0f; 18664 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 18665 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 18666 } 18667 18668 if (horizontalEdges) { 18669 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 18670 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 18671 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 18672 drawRight = rightFadeStrength * fadeHeight > 1.0f; 18673 } 18674 18675 saveCount = canvas.getSaveCount(); 18676 18677 int solidColor = getSolidColor(); 18678 if (solidColor == 0) { 18679 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 18680 18681 if (drawTop) { 18682 canvas.saveLayer(left, top, right, top + length, null, flags); 18683 } 18684 18685 if (drawBottom) { 18686 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 18687 } 18688 18689 if (drawLeft) { 18690 canvas.saveLayer(left, top, left + length, bottom, null, flags); 18691 } 18692 18693 if (drawRight) { 18694 canvas.saveLayer(right - length, top, right, bottom, null, flags); 18695 } 18696 } else { 18697 scrollabilityCache.setFadeColor(solidColor); 18698 } 18699 18700 // Step 3, draw the content 18701 if (!dirtyOpaque) onDraw(canvas); 18702 18703 // Step 4, draw the children 18704 dispatchDraw(canvas); 18705 18706 // Step 5, draw the fade effect and restore layers 18707 final Paint p = scrollabilityCache.paint; 18708 final Matrix matrix = scrollabilityCache.matrix; 18709 final Shader fade = scrollabilityCache.shader; 18710 18711 if (drawTop) { 18712 matrix.setScale(1, fadeHeight * topFadeStrength); 18713 matrix.postTranslate(left, top); 18714 fade.setLocalMatrix(matrix); 18715 p.setShader(fade); 18716 canvas.drawRect(left, top, right, top + length, p); 18717 } 18718 18719 if (drawBottom) { 18720 matrix.setScale(1, fadeHeight * bottomFadeStrength); 18721 matrix.postRotate(180); 18722 matrix.postTranslate(left, bottom); 18723 fade.setLocalMatrix(matrix); 18724 p.setShader(fade); 18725 canvas.drawRect(left, bottom - length, right, bottom, p); 18726 } 18727 18728 if (drawLeft) { 18729 matrix.setScale(1, fadeHeight * leftFadeStrength); 18730 matrix.postRotate(-90); 18731 matrix.postTranslate(left, top); 18732 fade.setLocalMatrix(matrix); 18733 p.setShader(fade); 18734 canvas.drawRect(left, top, left + length, bottom, p); 18735 } 18736 18737 if (drawRight) { 18738 matrix.setScale(1, fadeHeight * rightFadeStrength); 18739 matrix.postRotate(90); 18740 matrix.postTranslate(right, top); 18741 fade.setLocalMatrix(matrix); 18742 p.setShader(fade); 18743 canvas.drawRect(right - length, top, right, bottom, p); 18744 } 18745 18746 canvas.restoreToCount(saveCount); 18747 18748 // Overlay is part of the content and draws beneath Foreground 18749 if (mOverlay != null && !mOverlay.isEmpty()) { 18750 mOverlay.getOverlayView().dispatchDraw(canvas); 18751 } 18752 18753 // Step 6, draw decorations (foreground, scrollbars) 18754 onDrawForeground(canvas); 18755 18756 if (debugDraw()) { 18757 debugDrawFocus(canvas); 18758 } 18759 } 18760 18761 /** 18762 * Draws the background onto the specified canvas. 18763 * 18764 * @param canvas Canvas on which to draw the background 18765 */ 18766 private void drawBackground(Canvas canvas) { 18767 final Drawable background = mBackground; 18768 if (background == null) { 18769 return; 18770 } 18771 18772 setBackgroundBounds(); 18773 18774 // Attempt to use a display list if requested. 18775 if (canvas.isHardwareAccelerated() && mAttachInfo != null 18776 && mAttachInfo.mThreadedRenderer != null) { 18777 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 18778 18779 final RenderNode renderNode = mBackgroundRenderNode; 18780 if (renderNode != null && renderNode.isValid()) { 18781 setBackgroundRenderNodeProperties(renderNode); 18782 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18783 return; 18784 } 18785 } 18786 18787 final int scrollX = mScrollX; 18788 final int scrollY = mScrollY; 18789 if ((scrollX | scrollY) == 0) { 18790 background.draw(canvas); 18791 } else { 18792 canvas.translate(scrollX, scrollY); 18793 background.draw(canvas); 18794 canvas.translate(-scrollX, -scrollY); 18795 } 18796 } 18797 18798 /** 18799 * Sets the correct background bounds and rebuilds the outline, if needed. 18800 * <p/> 18801 * This is called by LayoutLib. 18802 */ 18803 void setBackgroundBounds() { 18804 if (mBackgroundSizeChanged && mBackground != null) { 18805 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 18806 mBackgroundSizeChanged = false; 18807 rebuildOutline(); 18808 } 18809 } 18810 18811 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 18812 renderNode.setTranslationX(mScrollX); 18813 renderNode.setTranslationY(mScrollY); 18814 } 18815 18816 /** 18817 * Creates a new display list or updates the existing display list for the 18818 * specified Drawable. 18819 * 18820 * @param drawable Drawable for which to create a display list 18821 * @param renderNode Existing RenderNode, or {@code null} 18822 * @return A valid display list for the specified drawable 18823 */ 18824 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 18825 if (renderNode == null) { 18826 renderNode = RenderNode.create(drawable.getClass().getName(), this); 18827 } 18828 18829 final Rect bounds = drawable.getBounds(); 18830 final int width = bounds.width(); 18831 final int height = bounds.height(); 18832 final DisplayListCanvas canvas = renderNode.start(width, height); 18833 18834 // Reverse left/top translation done by drawable canvas, which will 18835 // instead be applied by rendernode's LTRB bounds below. This way, the 18836 // drawable's bounds match with its rendernode bounds and its content 18837 // will lie within those bounds in the rendernode tree. 18838 canvas.translate(-bounds.left, -bounds.top); 18839 18840 try { 18841 drawable.draw(canvas); 18842 } finally { 18843 renderNode.end(canvas); 18844 } 18845 18846 // Set up drawable properties that are view-independent. 18847 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 18848 renderNode.setProjectBackwards(drawable.isProjected()); 18849 renderNode.setProjectionReceiver(true); 18850 renderNode.setClipToBounds(false); 18851 return renderNode; 18852 } 18853 18854 /** 18855 * Returns the overlay for this view, creating it if it does not yet exist. 18856 * Adding drawables to the overlay will cause them to be displayed whenever 18857 * the view itself is redrawn. Objects in the overlay should be actively 18858 * managed: remove them when they should not be displayed anymore. The 18859 * overlay will always have the same size as its host view. 18860 * 18861 * <p>Note: Overlays do not currently work correctly with {@link 18862 * SurfaceView} or {@link TextureView}; contents in overlays for these 18863 * types of views may not display correctly.</p> 18864 * 18865 * @return The ViewOverlay object for this view. 18866 * @see ViewOverlay 18867 */ 18868 public ViewOverlay getOverlay() { 18869 if (mOverlay == null) { 18870 mOverlay = new ViewOverlay(mContext, this); 18871 } 18872 return mOverlay; 18873 } 18874 18875 /** 18876 * Override this if your view is known to always be drawn on top of a solid color background, 18877 * and needs to draw fading edges. Returning a non-zero color enables the view system to 18878 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 18879 * should be set to 0xFF. 18880 * 18881 * @see #setVerticalFadingEdgeEnabled(boolean) 18882 * @see #setHorizontalFadingEdgeEnabled(boolean) 18883 * 18884 * @return The known solid color background for this view, or 0 if the color may vary 18885 */ 18886 @ViewDebug.ExportedProperty(category = "drawing") 18887 @ColorInt 18888 public int getSolidColor() { 18889 return 0; 18890 } 18891 18892 /** 18893 * Build a human readable string representation of the specified view flags. 18894 * 18895 * @param flags the view flags to convert to a string 18896 * @return a String representing the supplied flags 18897 */ 18898 private static String printFlags(int flags) { 18899 String output = ""; 18900 int numFlags = 0; 18901 if ((flags & FOCUSABLE) == FOCUSABLE) { 18902 output += "TAKES_FOCUS"; 18903 numFlags++; 18904 } 18905 18906 switch (flags & VISIBILITY_MASK) { 18907 case INVISIBLE: 18908 if (numFlags > 0) { 18909 output += " "; 18910 } 18911 output += "INVISIBLE"; 18912 // USELESS HERE numFlags++; 18913 break; 18914 case GONE: 18915 if (numFlags > 0) { 18916 output += " "; 18917 } 18918 output += "GONE"; 18919 // USELESS HERE numFlags++; 18920 break; 18921 default: 18922 break; 18923 } 18924 return output; 18925 } 18926 18927 /** 18928 * Build a human readable string representation of the specified private 18929 * view flags. 18930 * 18931 * @param privateFlags the private view flags to convert to a string 18932 * @return a String representing the supplied flags 18933 */ 18934 private static String printPrivateFlags(int privateFlags) { 18935 String output = ""; 18936 int numFlags = 0; 18937 18938 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 18939 output += "WANTS_FOCUS"; 18940 numFlags++; 18941 } 18942 18943 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 18944 if (numFlags > 0) { 18945 output += " "; 18946 } 18947 output += "FOCUSED"; 18948 numFlags++; 18949 } 18950 18951 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 18952 if (numFlags > 0) { 18953 output += " "; 18954 } 18955 output += "SELECTED"; 18956 numFlags++; 18957 } 18958 18959 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 18960 if (numFlags > 0) { 18961 output += " "; 18962 } 18963 output += "IS_ROOT_NAMESPACE"; 18964 numFlags++; 18965 } 18966 18967 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 18968 if (numFlags > 0) { 18969 output += " "; 18970 } 18971 output += "HAS_BOUNDS"; 18972 numFlags++; 18973 } 18974 18975 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 18976 if (numFlags > 0) { 18977 output += " "; 18978 } 18979 output += "DRAWN"; 18980 // USELESS HERE numFlags++; 18981 } 18982 return output; 18983 } 18984 18985 /** 18986 * <p>Indicates whether or not this view's layout will be requested during 18987 * the next hierarchy layout pass.</p> 18988 * 18989 * @return true if the layout will be forced during next layout pass 18990 */ 18991 public boolean isLayoutRequested() { 18992 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 18993 } 18994 18995 /** 18996 * Return true if o is a ViewGroup that is laying out using optical bounds. 18997 * @hide 18998 */ 18999 public static boolean isLayoutModeOptical(Object o) { 19000 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 19001 } 19002 19003 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 19004 Insets parentInsets = mParent instanceof View ? 19005 ((View) mParent).getOpticalInsets() : Insets.NONE; 19006 Insets childInsets = getOpticalInsets(); 19007 return setFrame( 19008 left + parentInsets.left - childInsets.left, 19009 top + parentInsets.top - childInsets.top, 19010 right + parentInsets.left + childInsets.right, 19011 bottom + parentInsets.top + childInsets.bottom); 19012 } 19013 19014 /** 19015 * Assign a size and position to a view and all of its 19016 * descendants 19017 * 19018 * <p>This is the second phase of the layout mechanism. 19019 * (The first is measuring). In this phase, each parent calls 19020 * layout on all of its children to position them. 19021 * This is typically done using the child measurements 19022 * that were stored in the measure pass().</p> 19023 * 19024 * <p>Derived classes should not override this method. 19025 * Derived classes with children should override 19026 * onLayout. In that method, they should 19027 * call layout on each of their children.</p> 19028 * 19029 * @param l Left position, relative to parent 19030 * @param t Top position, relative to parent 19031 * @param r Right position, relative to parent 19032 * @param b Bottom position, relative to parent 19033 */ 19034 @SuppressWarnings({"unchecked"}) 19035 public void layout(int l, int t, int r, int b) { 19036 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 19037 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 19038 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 19039 } 19040 19041 int oldL = mLeft; 19042 int oldT = mTop; 19043 int oldB = mBottom; 19044 int oldR = mRight; 19045 19046 boolean changed = isLayoutModeOptical(mParent) ? 19047 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 19048 19049 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 19050 onLayout(changed, l, t, r, b); 19051 19052 if (shouldDrawRoundScrollbar()) { 19053 if(mRoundScrollbarRenderer == null) { 19054 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 19055 } 19056 } else { 19057 mRoundScrollbarRenderer = null; 19058 } 19059 19060 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 19061 19062 ListenerInfo li = mListenerInfo; 19063 if (li != null && li.mOnLayoutChangeListeners != null) { 19064 ArrayList<OnLayoutChangeListener> listenersCopy = 19065 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 19066 int numListeners = listenersCopy.size(); 19067 for (int i = 0; i < numListeners; ++i) { 19068 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 19069 } 19070 } 19071 } 19072 19073 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 19074 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 19075 } 19076 19077 /** 19078 * Called from layout when this view should 19079 * assign a size and position to each of its children. 19080 * 19081 * Derived classes with children should override 19082 * this method and call layout on each of 19083 * their children. 19084 * @param changed This is a new size or position for this view 19085 * @param left Left position, relative to parent 19086 * @param top Top position, relative to parent 19087 * @param right Right position, relative to parent 19088 * @param bottom Bottom position, relative to parent 19089 */ 19090 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 19091 } 19092 19093 /** 19094 * Assign a size and position to this view. 19095 * 19096 * This is called from layout. 19097 * 19098 * @param left Left position, relative to parent 19099 * @param top Top position, relative to parent 19100 * @param right Right position, relative to parent 19101 * @param bottom Bottom position, relative to parent 19102 * @return true if the new size and position are different than the 19103 * previous ones 19104 * {@hide} 19105 */ 19106 protected boolean setFrame(int left, int top, int right, int bottom) { 19107 boolean changed = false; 19108 19109 if (DBG) { 19110 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 19111 + right + "," + bottom + ")"); 19112 } 19113 19114 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 19115 changed = true; 19116 19117 // Remember our drawn bit 19118 int drawn = mPrivateFlags & PFLAG_DRAWN; 19119 19120 int oldWidth = mRight - mLeft; 19121 int oldHeight = mBottom - mTop; 19122 int newWidth = right - left; 19123 int newHeight = bottom - top; 19124 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 19125 19126 // Invalidate our old position 19127 invalidate(sizeChanged); 19128 19129 mLeft = left; 19130 mTop = top; 19131 mRight = right; 19132 mBottom = bottom; 19133 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 19134 19135 mPrivateFlags |= PFLAG_HAS_BOUNDS; 19136 19137 19138 if (sizeChanged) { 19139 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 19140 } 19141 19142 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 19143 // If we are visible, force the DRAWN bit to on so that 19144 // this invalidate will go through (at least to our parent). 19145 // This is because someone may have invalidated this view 19146 // before this call to setFrame came in, thereby clearing 19147 // the DRAWN bit. 19148 mPrivateFlags |= PFLAG_DRAWN; 19149 invalidate(sizeChanged); 19150 // parent display list may need to be recreated based on a change in the bounds 19151 // of any child 19152 invalidateParentCaches(); 19153 } 19154 19155 // Reset drawn bit to original value (invalidate turns it off) 19156 mPrivateFlags |= drawn; 19157 19158 mBackgroundSizeChanged = true; 19159 if (mForegroundInfo != null) { 19160 mForegroundInfo.mBoundsChanged = true; 19161 } 19162 19163 notifySubtreeAccessibilityStateChangedIfNeeded(); 19164 } 19165 return changed; 19166 } 19167 19168 /** 19169 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 19170 * @hide 19171 */ 19172 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 19173 setFrame(left, top, right, bottom); 19174 } 19175 19176 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 19177 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 19178 if (mOverlay != null) { 19179 mOverlay.getOverlayView().setRight(newWidth); 19180 mOverlay.getOverlayView().setBottom(newHeight); 19181 } 19182 rebuildOutline(); 19183 } 19184 19185 /** 19186 * Finalize inflating a view from XML. This is called as the last phase 19187 * of inflation, after all child views have been added. 19188 * 19189 * <p>Even if the subclass overrides onFinishInflate, they should always be 19190 * sure to call the super method, so that we get called. 19191 */ 19192 @CallSuper 19193 protected void onFinishInflate() { 19194 } 19195 19196 /** 19197 * Returns the resources associated with this view. 19198 * 19199 * @return Resources object. 19200 */ 19201 public Resources getResources() { 19202 return mResources; 19203 } 19204 19205 /** 19206 * Invalidates the specified Drawable. 19207 * 19208 * @param drawable the drawable to invalidate 19209 */ 19210 @Override 19211 public void invalidateDrawable(@NonNull Drawable drawable) { 19212 if (verifyDrawable(drawable)) { 19213 final Rect dirty = drawable.getDirtyBounds(); 19214 final int scrollX = mScrollX; 19215 final int scrollY = mScrollY; 19216 19217 invalidate(dirty.left + scrollX, dirty.top + scrollY, 19218 dirty.right + scrollX, dirty.bottom + scrollY); 19219 rebuildOutline(); 19220 } 19221 } 19222 19223 /** 19224 * Schedules an action on a drawable to occur at a specified time. 19225 * 19226 * @param who the recipient of the action 19227 * @param what the action to run on the drawable 19228 * @param when the time at which the action must occur. Uses the 19229 * {@link SystemClock#uptimeMillis} timebase. 19230 */ 19231 @Override 19232 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 19233 if (verifyDrawable(who) && what != null) { 19234 final long delay = when - SystemClock.uptimeMillis(); 19235 if (mAttachInfo != null) { 19236 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 19237 Choreographer.CALLBACK_ANIMATION, what, who, 19238 Choreographer.subtractFrameDelay(delay)); 19239 } else { 19240 // Postpone the runnable until we know 19241 // on which thread it needs to run. 19242 getRunQueue().postDelayed(what, delay); 19243 } 19244 } 19245 } 19246 19247 /** 19248 * Cancels a scheduled action on a drawable. 19249 * 19250 * @param who the recipient of the action 19251 * @param what the action to cancel 19252 */ 19253 @Override 19254 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 19255 if (verifyDrawable(who) && what != null) { 19256 if (mAttachInfo != null) { 19257 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19258 Choreographer.CALLBACK_ANIMATION, what, who); 19259 } 19260 getRunQueue().removeCallbacks(what); 19261 } 19262 } 19263 19264 /** 19265 * Unschedule any events associated with the given Drawable. This can be 19266 * used when selecting a new Drawable into a view, so that the previous 19267 * one is completely unscheduled. 19268 * 19269 * @param who The Drawable to unschedule. 19270 * 19271 * @see #drawableStateChanged 19272 */ 19273 public void unscheduleDrawable(Drawable who) { 19274 if (mAttachInfo != null && who != null) { 19275 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19276 Choreographer.CALLBACK_ANIMATION, null, who); 19277 } 19278 } 19279 19280 /** 19281 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 19282 * that the View directionality can and will be resolved before its Drawables. 19283 * 19284 * Will call {@link View#onResolveDrawables} when resolution is done. 19285 * 19286 * @hide 19287 */ 19288 protected void resolveDrawables() { 19289 // Drawables resolution may need to happen before resolving the layout direction (which is 19290 // done only during the measure() call). 19291 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 19292 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 19293 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 19294 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 19295 // direction to be resolved as its resolved value will be the same as its raw value. 19296 if (!isLayoutDirectionResolved() && 19297 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 19298 return; 19299 } 19300 19301 final int layoutDirection = isLayoutDirectionResolved() ? 19302 getLayoutDirection() : getRawLayoutDirection(); 19303 19304 if (mBackground != null) { 19305 mBackground.setLayoutDirection(layoutDirection); 19306 } 19307 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19308 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 19309 } 19310 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 19311 onResolveDrawables(layoutDirection); 19312 } 19313 19314 boolean areDrawablesResolved() { 19315 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 19316 } 19317 19318 /** 19319 * Called when layout direction has been resolved. 19320 * 19321 * The default implementation does nothing. 19322 * 19323 * @param layoutDirection The resolved layout direction. 19324 * 19325 * @see #LAYOUT_DIRECTION_LTR 19326 * @see #LAYOUT_DIRECTION_RTL 19327 * 19328 * @hide 19329 */ 19330 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 19331 } 19332 19333 /** 19334 * @hide 19335 */ 19336 protected void resetResolvedDrawables() { 19337 resetResolvedDrawablesInternal(); 19338 } 19339 19340 void resetResolvedDrawablesInternal() { 19341 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 19342 } 19343 19344 /** 19345 * If your view subclass is displaying its own Drawable objects, it should 19346 * override this function and return true for any Drawable it is 19347 * displaying. This allows animations for those drawables to be 19348 * scheduled. 19349 * 19350 * <p>Be sure to call through to the super class when overriding this 19351 * function. 19352 * 19353 * @param who The Drawable to verify. Return true if it is one you are 19354 * displaying, else return the result of calling through to the 19355 * super class. 19356 * 19357 * @return boolean If true than the Drawable is being displayed in the 19358 * view; else false and it is not allowed to animate. 19359 * 19360 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 19361 * @see #drawableStateChanged() 19362 */ 19363 @CallSuper 19364 protected boolean verifyDrawable(@NonNull Drawable who) { 19365 // Avoid verifying the scroll bar drawable so that we don't end up in 19366 // an invalidation loop. This effectively prevents the scroll bar 19367 // drawable from triggering invalidations and scheduling runnables. 19368 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); 19369 } 19370 19371 /** 19372 * This function is called whenever the state of the view changes in such 19373 * a way that it impacts the state of drawables being shown. 19374 * <p> 19375 * If the View has a StateListAnimator, it will also be called to run necessary state 19376 * change animations. 19377 * <p> 19378 * Be sure to call through to the superclass when overriding this function. 19379 * 19380 * @see Drawable#setState(int[]) 19381 */ 19382 @CallSuper 19383 protected void drawableStateChanged() { 19384 final int[] state = getDrawableState(); 19385 boolean changed = false; 19386 19387 final Drawable bg = mBackground; 19388 if (bg != null && bg.isStateful()) { 19389 changed |= bg.setState(state); 19390 } 19391 19392 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19393 if (fg != null && fg.isStateful()) { 19394 changed |= fg.setState(state); 19395 } 19396 19397 if (mScrollCache != null) { 19398 final Drawable scrollBar = mScrollCache.scrollBar; 19399 if (scrollBar != null && scrollBar.isStateful()) { 19400 changed |= scrollBar.setState(state) 19401 && mScrollCache.state != ScrollabilityCache.OFF; 19402 } 19403 } 19404 19405 if (mStateListAnimator != null) { 19406 mStateListAnimator.setState(state); 19407 } 19408 19409 if (changed) { 19410 invalidate(); 19411 } 19412 } 19413 19414 /** 19415 * This function is called whenever the view hotspot changes and needs to 19416 * be propagated to drawables or child views managed by the view. 19417 * <p> 19418 * Dispatching to child views is handled by 19419 * {@link #dispatchDrawableHotspotChanged(float, float)}. 19420 * <p> 19421 * Be sure to call through to the superclass when overriding this function. 19422 * 19423 * @param x hotspot x coordinate 19424 * @param y hotspot y coordinate 19425 */ 19426 @CallSuper 19427 public void drawableHotspotChanged(float x, float y) { 19428 if (mBackground != null) { 19429 mBackground.setHotspot(x, y); 19430 } 19431 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19432 mForegroundInfo.mDrawable.setHotspot(x, y); 19433 } 19434 19435 dispatchDrawableHotspotChanged(x, y); 19436 } 19437 19438 /** 19439 * Dispatches drawableHotspotChanged to all of this View's children. 19440 * 19441 * @param x hotspot x coordinate 19442 * @param y hotspot y coordinate 19443 * @see #drawableHotspotChanged(float, float) 19444 */ 19445 public void dispatchDrawableHotspotChanged(float x, float y) { 19446 } 19447 19448 /** 19449 * Call this to force a view to update its drawable state. This will cause 19450 * drawableStateChanged to be called on this view. Views that are interested 19451 * in the new state should call getDrawableState. 19452 * 19453 * @see #drawableStateChanged 19454 * @see #getDrawableState 19455 */ 19456 public void refreshDrawableState() { 19457 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 19458 drawableStateChanged(); 19459 19460 ViewParent parent = mParent; 19461 if (parent != null) { 19462 parent.childDrawableStateChanged(this); 19463 } 19464 } 19465 19466 /** 19467 * Return an array of resource IDs of the drawable states representing the 19468 * current state of the view. 19469 * 19470 * @return The current drawable state 19471 * 19472 * @see Drawable#setState(int[]) 19473 * @see #drawableStateChanged() 19474 * @see #onCreateDrawableState(int) 19475 */ 19476 public final int[] getDrawableState() { 19477 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 19478 return mDrawableState; 19479 } else { 19480 mDrawableState = onCreateDrawableState(0); 19481 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 19482 return mDrawableState; 19483 } 19484 } 19485 19486 /** 19487 * Generate the new {@link android.graphics.drawable.Drawable} state for 19488 * this view. This is called by the view 19489 * system when the cached Drawable state is determined to be invalid. To 19490 * retrieve the current state, you should use {@link #getDrawableState}. 19491 * 19492 * @param extraSpace if non-zero, this is the number of extra entries you 19493 * would like in the returned array in which you can place your own 19494 * states. 19495 * 19496 * @return Returns an array holding the current {@link Drawable} state of 19497 * the view. 19498 * 19499 * @see #mergeDrawableStates(int[], int[]) 19500 */ 19501 protected int[] onCreateDrawableState(int extraSpace) { 19502 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 19503 mParent instanceof View) { 19504 return ((View) mParent).onCreateDrawableState(extraSpace); 19505 } 19506 19507 int[] drawableState; 19508 19509 int privateFlags = mPrivateFlags; 19510 19511 int viewStateIndex = 0; 19512 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 19513 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 19514 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 19515 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 19516 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 19517 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 19518 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 19519 ThreadedRenderer.isAvailable()) { 19520 // This is set if HW acceleration is requested, even if the current 19521 // process doesn't allow it. This is just to allow app preview 19522 // windows to better match their app. 19523 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 19524 } 19525 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 19526 19527 final int privateFlags2 = mPrivateFlags2; 19528 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 19529 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 19530 } 19531 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 19532 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 19533 } 19534 19535 drawableState = StateSet.get(viewStateIndex); 19536 19537 //noinspection ConstantIfStatement 19538 if (false) { 19539 Log.i("View", "drawableStateIndex=" + viewStateIndex); 19540 Log.i("View", toString() 19541 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 19542 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 19543 + " fo=" + hasFocus() 19544 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 19545 + " wf=" + hasWindowFocus() 19546 + ": " + Arrays.toString(drawableState)); 19547 } 19548 19549 if (extraSpace == 0) { 19550 return drawableState; 19551 } 19552 19553 final int[] fullState; 19554 if (drawableState != null) { 19555 fullState = new int[drawableState.length + extraSpace]; 19556 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 19557 } else { 19558 fullState = new int[extraSpace]; 19559 } 19560 19561 return fullState; 19562 } 19563 19564 /** 19565 * Merge your own state values in <var>additionalState</var> into the base 19566 * state values <var>baseState</var> that were returned by 19567 * {@link #onCreateDrawableState(int)}. 19568 * 19569 * @param baseState The base state values returned by 19570 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 19571 * own additional state values. 19572 * 19573 * @param additionalState The additional state values you would like 19574 * added to <var>baseState</var>; this array is not modified. 19575 * 19576 * @return As a convenience, the <var>baseState</var> array you originally 19577 * passed into the function is returned. 19578 * 19579 * @see #onCreateDrawableState(int) 19580 */ 19581 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 19582 final int N = baseState.length; 19583 int i = N - 1; 19584 while (i >= 0 && baseState[i] == 0) { 19585 i--; 19586 } 19587 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 19588 return baseState; 19589 } 19590 19591 /** 19592 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 19593 * on all Drawable objects associated with this view. 19594 * <p> 19595 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 19596 * attached to this view. 19597 */ 19598 @CallSuper 19599 public void jumpDrawablesToCurrentState() { 19600 if (mBackground != null) { 19601 mBackground.jumpToCurrentState(); 19602 } 19603 if (mStateListAnimator != null) { 19604 mStateListAnimator.jumpToCurrentState(); 19605 } 19606 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19607 mForegroundInfo.mDrawable.jumpToCurrentState(); 19608 } 19609 } 19610 19611 /** 19612 * Sets the background color for this view. 19613 * @param color the color of the background 19614 */ 19615 @RemotableViewMethod 19616 public void setBackgroundColor(@ColorInt int color) { 19617 if (mBackground instanceof ColorDrawable) { 19618 ((ColorDrawable) mBackground.mutate()).setColor(color); 19619 computeOpaqueFlags(); 19620 mBackgroundResource = 0; 19621 } else { 19622 setBackground(new ColorDrawable(color)); 19623 } 19624 } 19625 19626 /** 19627 * Set the background to a given resource. The resource should refer to 19628 * a Drawable object or 0 to remove the background. 19629 * @param resid The identifier of the resource. 19630 * 19631 * @attr ref android.R.styleable#View_background 19632 */ 19633 @RemotableViewMethod 19634 public void setBackgroundResource(@DrawableRes int resid) { 19635 if (resid != 0 && resid == mBackgroundResource) { 19636 return; 19637 } 19638 19639 Drawable d = null; 19640 if (resid != 0) { 19641 d = mContext.getDrawable(resid); 19642 } 19643 setBackground(d); 19644 19645 mBackgroundResource = resid; 19646 } 19647 19648 /** 19649 * Set the background to a given Drawable, or remove the background. If the 19650 * background has padding, this View's padding is set to the background's 19651 * padding. However, when a background is removed, this View's padding isn't 19652 * touched. If setting the padding is desired, please use 19653 * {@link #setPadding(int, int, int, int)}. 19654 * 19655 * @param background The Drawable to use as the background, or null to remove the 19656 * background 19657 */ 19658 public void setBackground(Drawable background) { 19659 //noinspection deprecation 19660 setBackgroundDrawable(background); 19661 } 19662 19663 /** 19664 * @deprecated use {@link #setBackground(Drawable)} instead 19665 */ 19666 @Deprecated 19667 public void setBackgroundDrawable(Drawable background) { 19668 computeOpaqueFlags(); 19669 19670 if (background == mBackground) { 19671 return; 19672 } 19673 19674 boolean requestLayout = false; 19675 19676 mBackgroundResource = 0; 19677 19678 /* 19679 * Regardless of whether we're setting a new background or not, we want 19680 * to clear the previous drawable. setVisible first while we still have the callback set. 19681 */ 19682 if (mBackground != null) { 19683 if (isAttachedToWindow()) { 19684 mBackground.setVisible(false, false); 19685 } 19686 mBackground.setCallback(null); 19687 unscheduleDrawable(mBackground); 19688 } 19689 19690 if (background != null) { 19691 Rect padding = sThreadLocal.get(); 19692 if (padding == null) { 19693 padding = new Rect(); 19694 sThreadLocal.set(padding); 19695 } 19696 resetResolvedDrawablesInternal(); 19697 background.setLayoutDirection(getLayoutDirection()); 19698 if (background.getPadding(padding)) { 19699 resetResolvedPaddingInternal(); 19700 switch (background.getLayoutDirection()) { 19701 case LAYOUT_DIRECTION_RTL: 19702 mUserPaddingLeftInitial = padding.right; 19703 mUserPaddingRightInitial = padding.left; 19704 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 19705 break; 19706 case LAYOUT_DIRECTION_LTR: 19707 default: 19708 mUserPaddingLeftInitial = padding.left; 19709 mUserPaddingRightInitial = padding.right; 19710 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 19711 } 19712 mLeftPaddingDefined = false; 19713 mRightPaddingDefined = false; 19714 } 19715 19716 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 19717 // if it has a different minimum size, we should layout again 19718 if (mBackground == null 19719 || mBackground.getMinimumHeight() != background.getMinimumHeight() 19720 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 19721 requestLayout = true; 19722 } 19723 19724 // Set mBackground before we set this as the callback and start making other 19725 // background drawable state change calls. In particular, the setVisible call below 19726 // can result in drawables attempting to start animations or otherwise invalidate, 19727 // which requires the view set as the callback (us) to recognize the drawable as 19728 // belonging to it as per verifyDrawable. 19729 mBackground = background; 19730 if (background.isStateful()) { 19731 background.setState(getDrawableState()); 19732 } 19733 if (isAttachedToWindow()) { 19734 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 19735 } 19736 19737 applyBackgroundTint(); 19738 19739 // Set callback last, since the view may still be initializing. 19740 background.setCallback(this); 19741 19742 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19743 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19744 requestLayout = true; 19745 } 19746 } else { 19747 /* Remove the background */ 19748 mBackground = null; 19749 if ((mViewFlags & WILL_NOT_DRAW) != 0 19750 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 19751 mPrivateFlags |= PFLAG_SKIP_DRAW; 19752 } 19753 19754 /* 19755 * When the background is set, we try to apply its padding to this 19756 * View. When the background is removed, we don't touch this View's 19757 * padding. This is noted in the Javadocs. Hence, we don't need to 19758 * requestLayout(), the invalidate() below is sufficient. 19759 */ 19760 19761 // The old background's minimum size could have affected this 19762 // View's layout, so let's requestLayout 19763 requestLayout = true; 19764 } 19765 19766 computeOpaqueFlags(); 19767 19768 if (requestLayout) { 19769 requestLayout(); 19770 } 19771 19772 mBackgroundSizeChanged = true; 19773 invalidate(true); 19774 invalidateOutline(); 19775 } 19776 19777 /** 19778 * Gets the background drawable 19779 * 19780 * @return The drawable used as the background for this view, if any. 19781 * 19782 * @see #setBackground(Drawable) 19783 * 19784 * @attr ref android.R.styleable#View_background 19785 */ 19786 public Drawable getBackground() { 19787 return mBackground; 19788 } 19789 19790 /** 19791 * Applies a tint to the background drawable. Does not modify the current tint 19792 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19793 * <p> 19794 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 19795 * mutate the drawable and apply the specified tint and tint mode using 19796 * {@link Drawable#setTintList(ColorStateList)}. 19797 * 19798 * @param tint the tint to apply, may be {@code null} to clear tint 19799 * 19800 * @attr ref android.R.styleable#View_backgroundTint 19801 * @see #getBackgroundTintList() 19802 * @see Drawable#setTintList(ColorStateList) 19803 */ 19804 public void setBackgroundTintList(@Nullable ColorStateList tint) { 19805 if (mBackgroundTint == null) { 19806 mBackgroundTint = new TintInfo(); 19807 } 19808 mBackgroundTint.mTintList = tint; 19809 mBackgroundTint.mHasTintList = true; 19810 19811 applyBackgroundTint(); 19812 } 19813 19814 /** 19815 * Return the tint applied to the background drawable, if specified. 19816 * 19817 * @return the tint applied to the background drawable 19818 * @attr ref android.R.styleable#View_backgroundTint 19819 * @see #setBackgroundTintList(ColorStateList) 19820 */ 19821 @Nullable 19822 public ColorStateList getBackgroundTintList() { 19823 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 19824 } 19825 19826 /** 19827 * Specifies the blending mode used to apply the tint specified by 19828 * {@link #setBackgroundTintList(ColorStateList)}} to the background 19829 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19830 * 19831 * @param tintMode the blending mode used to apply the tint, may be 19832 * {@code null} to clear tint 19833 * @attr ref android.R.styleable#View_backgroundTintMode 19834 * @see #getBackgroundTintMode() 19835 * @see Drawable#setTintMode(PorterDuff.Mode) 19836 */ 19837 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19838 if (mBackgroundTint == null) { 19839 mBackgroundTint = new TintInfo(); 19840 } 19841 mBackgroundTint.mTintMode = tintMode; 19842 mBackgroundTint.mHasTintMode = true; 19843 19844 applyBackgroundTint(); 19845 } 19846 19847 /** 19848 * Return the blending mode used to apply the tint to the background 19849 * drawable, if specified. 19850 * 19851 * @return the blending mode used to apply the tint to the background 19852 * drawable 19853 * @attr ref android.R.styleable#View_backgroundTintMode 19854 * @see #setBackgroundTintMode(PorterDuff.Mode) 19855 */ 19856 @Nullable 19857 public PorterDuff.Mode getBackgroundTintMode() { 19858 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 19859 } 19860 19861 private void applyBackgroundTint() { 19862 if (mBackground != null && mBackgroundTint != null) { 19863 final TintInfo tintInfo = mBackgroundTint; 19864 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19865 mBackground = mBackground.mutate(); 19866 19867 if (tintInfo.mHasTintList) { 19868 mBackground.setTintList(tintInfo.mTintList); 19869 } 19870 19871 if (tintInfo.mHasTintMode) { 19872 mBackground.setTintMode(tintInfo.mTintMode); 19873 } 19874 19875 // The drawable (or one of its children) may not have been 19876 // stateful before applying the tint, so let's try again. 19877 if (mBackground.isStateful()) { 19878 mBackground.setState(getDrawableState()); 19879 } 19880 } 19881 } 19882 } 19883 19884 /** 19885 * Returns the drawable used as the foreground of this View. The 19886 * foreground drawable, if non-null, is always drawn on top of the view's content. 19887 * 19888 * @return a Drawable or null if no foreground was set 19889 * 19890 * @see #onDrawForeground(Canvas) 19891 */ 19892 public Drawable getForeground() { 19893 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19894 } 19895 19896 /** 19897 * Supply a Drawable that is to be rendered on top of all of the content in the view. 19898 * 19899 * @param foreground the Drawable to be drawn on top of the children 19900 * 19901 * @attr ref android.R.styleable#View_foreground 19902 */ 19903 public void setForeground(Drawable foreground) { 19904 if (mForegroundInfo == null) { 19905 if (foreground == null) { 19906 // Nothing to do. 19907 return; 19908 } 19909 mForegroundInfo = new ForegroundInfo(); 19910 } 19911 19912 if (foreground == mForegroundInfo.mDrawable) { 19913 // Nothing to do 19914 return; 19915 } 19916 19917 if (mForegroundInfo.mDrawable != null) { 19918 if (isAttachedToWindow()) { 19919 mForegroundInfo.mDrawable.setVisible(false, false); 19920 } 19921 mForegroundInfo.mDrawable.setCallback(null); 19922 unscheduleDrawable(mForegroundInfo.mDrawable); 19923 } 19924 19925 mForegroundInfo.mDrawable = foreground; 19926 mForegroundInfo.mBoundsChanged = true; 19927 if (foreground != null) { 19928 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19929 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19930 } 19931 foreground.setLayoutDirection(getLayoutDirection()); 19932 if (foreground.isStateful()) { 19933 foreground.setState(getDrawableState()); 19934 } 19935 applyForegroundTint(); 19936 if (isAttachedToWindow()) { 19937 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 19938 } 19939 // Set callback last, since the view may still be initializing. 19940 foreground.setCallback(this); 19941 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) { 19942 mPrivateFlags |= PFLAG_SKIP_DRAW; 19943 } 19944 requestLayout(); 19945 invalidate(); 19946 } 19947 19948 /** 19949 * Magic bit used to support features of framework-internal window decor implementation details. 19950 * This used to live exclusively in FrameLayout. 19951 * 19952 * @return true if the foreground should draw inside the padding region or false 19953 * if it should draw inset by the view's padding 19954 * @hide internal use only; only used by FrameLayout and internal screen layouts. 19955 */ 19956 public boolean isForegroundInsidePadding() { 19957 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 19958 } 19959 19960 /** 19961 * Describes how the foreground is positioned. 19962 * 19963 * @return foreground gravity. 19964 * 19965 * @see #setForegroundGravity(int) 19966 * 19967 * @attr ref android.R.styleable#View_foregroundGravity 19968 */ 19969 public int getForegroundGravity() { 19970 return mForegroundInfo != null ? mForegroundInfo.mGravity 19971 : Gravity.START | Gravity.TOP; 19972 } 19973 19974 /** 19975 * Describes how the foreground is positioned. Defaults to START and TOP. 19976 * 19977 * @param gravity see {@link android.view.Gravity} 19978 * 19979 * @see #getForegroundGravity() 19980 * 19981 * @attr ref android.R.styleable#View_foregroundGravity 19982 */ 19983 public void setForegroundGravity(int gravity) { 19984 if (mForegroundInfo == null) { 19985 mForegroundInfo = new ForegroundInfo(); 19986 } 19987 19988 if (mForegroundInfo.mGravity != gravity) { 19989 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 19990 gravity |= Gravity.START; 19991 } 19992 19993 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 19994 gravity |= Gravity.TOP; 19995 } 19996 19997 mForegroundInfo.mGravity = gravity; 19998 requestLayout(); 19999 } 20000 } 20001 20002 /** 20003 * Applies a tint to the foreground drawable. Does not modify the current tint 20004 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20005 * <p> 20006 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 20007 * mutate the drawable and apply the specified tint and tint mode using 20008 * {@link Drawable#setTintList(ColorStateList)}. 20009 * 20010 * @param tint the tint to apply, may be {@code null} to clear tint 20011 * 20012 * @attr ref android.R.styleable#View_foregroundTint 20013 * @see #getForegroundTintList() 20014 * @see Drawable#setTintList(ColorStateList) 20015 */ 20016 public void setForegroundTintList(@Nullable ColorStateList tint) { 20017 if (mForegroundInfo == null) { 20018 mForegroundInfo = new ForegroundInfo(); 20019 } 20020 if (mForegroundInfo.mTintInfo == null) { 20021 mForegroundInfo.mTintInfo = new TintInfo(); 20022 } 20023 mForegroundInfo.mTintInfo.mTintList = tint; 20024 mForegroundInfo.mTintInfo.mHasTintList = true; 20025 20026 applyForegroundTint(); 20027 } 20028 20029 /** 20030 * Return the tint applied to the foreground drawable, if specified. 20031 * 20032 * @return the tint applied to the foreground drawable 20033 * @attr ref android.R.styleable#View_foregroundTint 20034 * @see #setForegroundTintList(ColorStateList) 20035 */ 20036 @Nullable 20037 public ColorStateList getForegroundTintList() { 20038 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20039 ? mForegroundInfo.mTintInfo.mTintList : null; 20040 } 20041 20042 /** 20043 * Specifies the blending mode used to apply the tint specified by 20044 * {@link #setForegroundTintList(ColorStateList)}} to the background 20045 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20046 * 20047 * @param tintMode the blending mode used to apply the tint, may be 20048 * {@code null} to clear tint 20049 * @attr ref android.R.styleable#View_foregroundTintMode 20050 * @see #getForegroundTintMode() 20051 * @see Drawable#setTintMode(PorterDuff.Mode) 20052 */ 20053 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20054 if (mForegroundInfo == null) { 20055 mForegroundInfo = new ForegroundInfo(); 20056 } 20057 if (mForegroundInfo.mTintInfo == null) { 20058 mForegroundInfo.mTintInfo = new TintInfo(); 20059 } 20060 mForegroundInfo.mTintInfo.mTintMode = tintMode; 20061 mForegroundInfo.mTintInfo.mHasTintMode = true; 20062 20063 applyForegroundTint(); 20064 } 20065 20066 /** 20067 * Return the blending mode used to apply the tint to the foreground 20068 * drawable, if specified. 20069 * 20070 * @return the blending mode used to apply the tint to the foreground 20071 * drawable 20072 * @attr ref android.R.styleable#View_foregroundTintMode 20073 * @see #setForegroundTintMode(PorterDuff.Mode) 20074 */ 20075 @Nullable 20076 public PorterDuff.Mode getForegroundTintMode() { 20077 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20078 ? mForegroundInfo.mTintInfo.mTintMode : null; 20079 } 20080 20081 private void applyForegroundTint() { 20082 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20083 && mForegroundInfo.mTintInfo != null) { 20084 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 20085 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20086 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 20087 20088 if (tintInfo.mHasTintList) { 20089 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 20090 } 20091 20092 if (tintInfo.mHasTintMode) { 20093 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 20094 } 20095 20096 // The drawable (or one of its children) may not have been 20097 // stateful before applying the tint, so let's try again. 20098 if (mForegroundInfo.mDrawable.isStateful()) { 20099 mForegroundInfo.mDrawable.setState(getDrawableState()); 20100 } 20101 } 20102 } 20103 } 20104 20105 /** 20106 * Draw any foreground content for this view. 20107 * 20108 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 20109 * drawable or other view-specific decorations. The foreground is drawn on top of the 20110 * primary view content.</p> 20111 * 20112 * @param canvas canvas to draw into 20113 */ 20114 public void onDrawForeground(Canvas canvas) { 20115 onDrawScrollIndicators(canvas); 20116 onDrawScrollBars(canvas); 20117 20118 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20119 if (foreground != null) { 20120 if (mForegroundInfo.mBoundsChanged) { 20121 mForegroundInfo.mBoundsChanged = false; 20122 final Rect selfBounds = mForegroundInfo.mSelfBounds; 20123 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 20124 20125 if (mForegroundInfo.mInsidePadding) { 20126 selfBounds.set(0, 0, getWidth(), getHeight()); 20127 } else { 20128 selfBounds.set(getPaddingLeft(), getPaddingTop(), 20129 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 20130 } 20131 20132 final int ld = getLayoutDirection(); 20133 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 20134 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 20135 foreground.setBounds(overlayBounds); 20136 } 20137 20138 foreground.draw(canvas); 20139 } 20140 } 20141 20142 /** 20143 * Sets the padding. The view may add on the space required to display 20144 * the scrollbars, depending on the style and visibility of the scrollbars. 20145 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 20146 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 20147 * from the values set in this call. 20148 * 20149 * @attr ref android.R.styleable#View_padding 20150 * @attr ref android.R.styleable#View_paddingBottom 20151 * @attr ref android.R.styleable#View_paddingLeft 20152 * @attr ref android.R.styleable#View_paddingRight 20153 * @attr ref android.R.styleable#View_paddingTop 20154 * @param left the left padding in pixels 20155 * @param top the top padding in pixels 20156 * @param right the right padding in pixels 20157 * @param bottom the bottom padding in pixels 20158 */ 20159 public void setPadding(int left, int top, int right, int bottom) { 20160 resetResolvedPaddingInternal(); 20161 20162 mUserPaddingStart = UNDEFINED_PADDING; 20163 mUserPaddingEnd = UNDEFINED_PADDING; 20164 20165 mUserPaddingLeftInitial = left; 20166 mUserPaddingRightInitial = right; 20167 20168 mLeftPaddingDefined = true; 20169 mRightPaddingDefined = true; 20170 20171 internalSetPadding(left, top, right, bottom); 20172 } 20173 20174 /** 20175 * @hide 20176 */ 20177 protected void internalSetPadding(int left, int top, int right, int bottom) { 20178 mUserPaddingLeft = left; 20179 mUserPaddingRight = right; 20180 mUserPaddingBottom = bottom; 20181 20182 final int viewFlags = mViewFlags; 20183 boolean changed = false; 20184 20185 // Common case is there are no scroll bars. 20186 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 20187 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 20188 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 20189 ? 0 : getVerticalScrollbarWidth(); 20190 switch (mVerticalScrollbarPosition) { 20191 case SCROLLBAR_POSITION_DEFAULT: 20192 if (isLayoutRtl()) { 20193 left += offset; 20194 } else { 20195 right += offset; 20196 } 20197 break; 20198 case SCROLLBAR_POSITION_RIGHT: 20199 right += offset; 20200 break; 20201 case SCROLLBAR_POSITION_LEFT: 20202 left += offset; 20203 break; 20204 } 20205 } 20206 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 20207 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 20208 ? 0 : getHorizontalScrollbarHeight(); 20209 } 20210 } 20211 20212 if (mPaddingLeft != left) { 20213 changed = true; 20214 mPaddingLeft = left; 20215 } 20216 if (mPaddingTop != top) { 20217 changed = true; 20218 mPaddingTop = top; 20219 } 20220 if (mPaddingRight != right) { 20221 changed = true; 20222 mPaddingRight = right; 20223 } 20224 if (mPaddingBottom != bottom) { 20225 changed = true; 20226 mPaddingBottom = bottom; 20227 } 20228 20229 if (changed) { 20230 requestLayout(); 20231 invalidateOutline(); 20232 } 20233 } 20234 20235 /** 20236 * Sets the relative padding. The view may add on the space required to display 20237 * the scrollbars, depending on the style and visibility of the scrollbars. 20238 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 20239 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 20240 * from the values set in this call. 20241 * 20242 * @attr ref android.R.styleable#View_padding 20243 * @attr ref android.R.styleable#View_paddingBottom 20244 * @attr ref android.R.styleable#View_paddingStart 20245 * @attr ref android.R.styleable#View_paddingEnd 20246 * @attr ref android.R.styleable#View_paddingTop 20247 * @param start the start padding in pixels 20248 * @param top the top padding in pixels 20249 * @param end the end padding in pixels 20250 * @param bottom the bottom padding in pixels 20251 */ 20252 public void setPaddingRelative(int start, int top, int end, int bottom) { 20253 resetResolvedPaddingInternal(); 20254 20255 mUserPaddingStart = start; 20256 mUserPaddingEnd = end; 20257 mLeftPaddingDefined = true; 20258 mRightPaddingDefined = true; 20259 20260 switch(getLayoutDirection()) { 20261 case LAYOUT_DIRECTION_RTL: 20262 mUserPaddingLeftInitial = end; 20263 mUserPaddingRightInitial = start; 20264 internalSetPadding(end, top, start, bottom); 20265 break; 20266 case LAYOUT_DIRECTION_LTR: 20267 default: 20268 mUserPaddingLeftInitial = start; 20269 mUserPaddingRightInitial = end; 20270 internalSetPadding(start, top, end, bottom); 20271 } 20272 } 20273 20274 /** 20275 * Returns the top padding of this view. 20276 * 20277 * @return the top padding in pixels 20278 */ 20279 public int getPaddingTop() { 20280 return mPaddingTop; 20281 } 20282 20283 /** 20284 * Returns the bottom padding of this view. If there are inset and enabled 20285 * scrollbars, this value may include the space required to display the 20286 * scrollbars as well. 20287 * 20288 * @return the bottom padding in pixels 20289 */ 20290 public int getPaddingBottom() { 20291 return mPaddingBottom; 20292 } 20293 20294 /** 20295 * Returns the left padding of this view. If there are inset and enabled 20296 * scrollbars, this value may include the space required to display the 20297 * scrollbars as well. 20298 * 20299 * @return the left padding in pixels 20300 */ 20301 public int getPaddingLeft() { 20302 if (!isPaddingResolved()) { 20303 resolvePadding(); 20304 } 20305 return mPaddingLeft; 20306 } 20307 20308 /** 20309 * Returns the start padding of this view depending on its resolved layout direction. 20310 * If there are inset and enabled scrollbars, this value may include the space 20311 * required to display the scrollbars as well. 20312 * 20313 * @return the start padding in pixels 20314 */ 20315 public int getPaddingStart() { 20316 if (!isPaddingResolved()) { 20317 resolvePadding(); 20318 } 20319 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 20320 mPaddingRight : mPaddingLeft; 20321 } 20322 20323 /** 20324 * Returns the right padding of this view. If there are inset and enabled 20325 * scrollbars, this value may include the space required to display the 20326 * scrollbars as well. 20327 * 20328 * @return the right padding in pixels 20329 */ 20330 public int getPaddingRight() { 20331 if (!isPaddingResolved()) { 20332 resolvePadding(); 20333 } 20334 return mPaddingRight; 20335 } 20336 20337 /** 20338 * Returns the end padding of this view depending on its resolved layout direction. 20339 * If there are inset and enabled scrollbars, this value may include the space 20340 * required to display the scrollbars as well. 20341 * 20342 * @return the end padding in pixels 20343 */ 20344 public int getPaddingEnd() { 20345 if (!isPaddingResolved()) { 20346 resolvePadding(); 20347 } 20348 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 20349 mPaddingLeft : mPaddingRight; 20350 } 20351 20352 /** 20353 * Return if the padding has been set through relative values 20354 * {@link #setPaddingRelative(int, int, int, int)} or through 20355 * @attr ref android.R.styleable#View_paddingStart or 20356 * @attr ref android.R.styleable#View_paddingEnd 20357 * 20358 * @return true if the padding is relative or false if it is not. 20359 */ 20360 public boolean isPaddingRelative() { 20361 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 20362 } 20363 20364 Insets computeOpticalInsets() { 20365 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 20366 } 20367 20368 /** 20369 * @hide 20370 */ 20371 public void resetPaddingToInitialValues() { 20372 if (isRtlCompatibilityMode()) { 20373 mPaddingLeft = mUserPaddingLeftInitial; 20374 mPaddingRight = mUserPaddingRightInitial; 20375 return; 20376 } 20377 if (isLayoutRtl()) { 20378 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 20379 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 20380 } else { 20381 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 20382 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 20383 } 20384 } 20385 20386 /** 20387 * @hide 20388 */ 20389 public Insets getOpticalInsets() { 20390 if (mLayoutInsets == null) { 20391 mLayoutInsets = computeOpticalInsets(); 20392 } 20393 return mLayoutInsets; 20394 } 20395 20396 /** 20397 * Set this view's optical insets. 20398 * 20399 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 20400 * property. Views that compute their own optical insets should call it as part of measurement. 20401 * This method does not request layout. If you are setting optical insets outside of 20402 * measure/layout itself you will want to call requestLayout() yourself. 20403 * </p> 20404 * @hide 20405 */ 20406 public void setOpticalInsets(Insets insets) { 20407 mLayoutInsets = insets; 20408 } 20409 20410 /** 20411 * Changes the selection state of this view. A view can be selected or not. 20412 * Note that selection is not the same as focus. Views are typically 20413 * selected in the context of an AdapterView like ListView or GridView; 20414 * the selected view is the view that is highlighted. 20415 * 20416 * @param selected true if the view must be selected, false otherwise 20417 */ 20418 public void setSelected(boolean selected) { 20419 //noinspection DoubleNegation 20420 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 20421 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 20422 if (!selected) resetPressedState(); 20423 invalidate(true); 20424 refreshDrawableState(); 20425 dispatchSetSelected(selected); 20426 if (selected) { 20427 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 20428 } else { 20429 notifyViewAccessibilityStateChangedIfNeeded( 20430 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 20431 } 20432 } 20433 } 20434 20435 /** 20436 * Dispatch setSelected to all of this View's children. 20437 * 20438 * @see #setSelected(boolean) 20439 * 20440 * @param selected The new selected state 20441 */ 20442 protected void dispatchSetSelected(boolean selected) { 20443 } 20444 20445 /** 20446 * Indicates the selection state of this view. 20447 * 20448 * @return true if the view is selected, false otherwise 20449 */ 20450 @ViewDebug.ExportedProperty 20451 public boolean isSelected() { 20452 return (mPrivateFlags & PFLAG_SELECTED) != 0; 20453 } 20454 20455 /** 20456 * Changes the activated state of this view. A view can be activated or not. 20457 * Note that activation is not the same as selection. Selection is 20458 * a transient property, representing the view (hierarchy) the user is 20459 * currently interacting with. Activation is a longer-term state that the 20460 * user can move views in and out of. For example, in a list view with 20461 * single or multiple selection enabled, the views in the current selection 20462 * set are activated. (Um, yeah, we are deeply sorry about the terminology 20463 * here.) The activated state is propagated down to children of the view it 20464 * is set on. 20465 * 20466 * @param activated true if the view must be activated, false otherwise 20467 */ 20468 public void setActivated(boolean activated) { 20469 //noinspection DoubleNegation 20470 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 20471 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 20472 invalidate(true); 20473 refreshDrawableState(); 20474 dispatchSetActivated(activated); 20475 } 20476 } 20477 20478 /** 20479 * Dispatch setActivated to all of this View's children. 20480 * 20481 * @see #setActivated(boolean) 20482 * 20483 * @param activated The new activated state 20484 */ 20485 protected void dispatchSetActivated(boolean activated) { 20486 } 20487 20488 /** 20489 * Indicates the activation state of this view. 20490 * 20491 * @return true if the view is activated, false otherwise 20492 */ 20493 @ViewDebug.ExportedProperty 20494 public boolean isActivated() { 20495 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 20496 } 20497 20498 /** 20499 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 20500 * observer can be used to get notifications when global events, like 20501 * layout, happen. 20502 * 20503 * The returned ViewTreeObserver observer is not guaranteed to remain 20504 * valid for the lifetime of this View. If the caller of this method keeps 20505 * a long-lived reference to ViewTreeObserver, it should always check for 20506 * the return value of {@link ViewTreeObserver#isAlive()}. 20507 * 20508 * @return The ViewTreeObserver for this view's hierarchy. 20509 */ 20510 public ViewTreeObserver getViewTreeObserver() { 20511 if (mAttachInfo != null) { 20512 return mAttachInfo.mTreeObserver; 20513 } 20514 if (mFloatingTreeObserver == null) { 20515 mFloatingTreeObserver = new ViewTreeObserver(mContext); 20516 } 20517 return mFloatingTreeObserver; 20518 } 20519 20520 /** 20521 * <p>Finds the topmost view in the current view hierarchy.</p> 20522 * 20523 * @return the topmost view containing this view 20524 */ 20525 public View getRootView() { 20526 if (mAttachInfo != null) { 20527 final View v = mAttachInfo.mRootView; 20528 if (v != null) { 20529 return v; 20530 } 20531 } 20532 20533 View parent = this; 20534 20535 while (parent.mParent != null && parent.mParent instanceof View) { 20536 parent = (View) parent.mParent; 20537 } 20538 20539 return parent; 20540 } 20541 20542 /** 20543 * Transforms a motion event from view-local coordinates to on-screen 20544 * coordinates. 20545 * 20546 * @param ev the view-local motion event 20547 * @return false if the transformation could not be applied 20548 * @hide 20549 */ 20550 public boolean toGlobalMotionEvent(MotionEvent ev) { 20551 final AttachInfo info = mAttachInfo; 20552 if (info == null) { 20553 return false; 20554 } 20555 20556 final Matrix m = info.mTmpMatrix; 20557 m.set(Matrix.IDENTITY_MATRIX); 20558 transformMatrixToGlobal(m); 20559 ev.transform(m); 20560 return true; 20561 } 20562 20563 /** 20564 * Transforms a motion event from on-screen coordinates to view-local 20565 * coordinates. 20566 * 20567 * @param ev the on-screen motion event 20568 * @return false if the transformation could not be applied 20569 * @hide 20570 */ 20571 public boolean toLocalMotionEvent(MotionEvent ev) { 20572 final AttachInfo info = mAttachInfo; 20573 if (info == null) { 20574 return false; 20575 } 20576 20577 final Matrix m = info.mTmpMatrix; 20578 m.set(Matrix.IDENTITY_MATRIX); 20579 transformMatrixToLocal(m); 20580 ev.transform(m); 20581 return true; 20582 } 20583 20584 /** 20585 * Modifies the input matrix such that it maps view-local coordinates to 20586 * on-screen coordinates. 20587 * 20588 * @param m input matrix to modify 20589 * @hide 20590 */ 20591 public void transformMatrixToGlobal(Matrix m) { 20592 final ViewParent parent = mParent; 20593 if (parent instanceof View) { 20594 final View vp = (View) parent; 20595 vp.transformMatrixToGlobal(m); 20596 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 20597 } else if (parent instanceof ViewRootImpl) { 20598 final ViewRootImpl vr = (ViewRootImpl) parent; 20599 vr.transformMatrixToGlobal(m); 20600 m.preTranslate(0, -vr.mCurScrollY); 20601 } 20602 20603 m.preTranslate(mLeft, mTop); 20604 20605 if (!hasIdentityMatrix()) { 20606 m.preConcat(getMatrix()); 20607 } 20608 } 20609 20610 /** 20611 * Modifies the input matrix such that it maps on-screen coordinates to 20612 * view-local coordinates. 20613 * 20614 * @param m input matrix to modify 20615 * @hide 20616 */ 20617 public void transformMatrixToLocal(Matrix m) { 20618 final ViewParent parent = mParent; 20619 if (parent instanceof View) { 20620 final View vp = (View) parent; 20621 vp.transformMatrixToLocal(m); 20622 m.postTranslate(vp.mScrollX, vp.mScrollY); 20623 } else if (parent instanceof ViewRootImpl) { 20624 final ViewRootImpl vr = (ViewRootImpl) parent; 20625 vr.transformMatrixToLocal(m); 20626 m.postTranslate(0, vr.mCurScrollY); 20627 } 20628 20629 m.postTranslate(-mLeft, -mTop); 20630 20631 if (!hasIdentityMatrix()) { 20632 m.postConcat(getInverseMatrix()); 20633 } 20634 } 20635 20636 /** 20637 * @hide 20638 */ 20639 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 20640 @ViewDebug.IntToString(from = 0, to = "x"), 20641 @ViewDebug.IntToString(from = 1, to = "y") 20642 }) 20643 public int[] getLocationOnScreen() { 20644 int[] location = new int[2]; 20645 getLocationOnScreen(location); 20646 return location; 20647 } 20648 20649 /** 20650 * <p>Computes the coordinates of this view on the screen. The argument 20651 * must be an array of two integers. After the method returns, the array 20652 * contains the x and y location in that order.</p> 20653 * 20654 * @param outLocation an array of two integers in which to hold the coordinates 20655 */ 20656 public void getLocationOnScreen(@Size(2) int[] outLocation) { 20657 getLocationInWindow(outLocation); 20658 20659 final AttachInfo info = mAttachInfo; 20660 if (info != null) { 20661 outLocation[0] += info.mWindowLeft; 20662 outLocation[1] += info.mWindowTop; 20663 } 20664 } 20665 20666 /** 20667 * <p>Computes the coordinates of this view in its window. The argument 20668 * must be an array of two integers. After the method returns, the array 20669 * contains the x and y location in that order.</p> 20670 * 20671 * @param outLocation an array of two integers in which to hold the coordinates 20672 */ 20673 public void getLocationInWindow(@Size(2) int[] outLocation) { 20674 if (outLocation == null || outLocation.length < 2) { 20675 throw new IllegalArgumentException("outLocation must be an array of two integers"); 20676 } 20677 20678 outLocation[0] = 0; 20679 outLocation[1] = 0; 20680 20681 transformFromViewToWindowSpace(outLocation); 20682 } 20683 20684 /** @hide */ 20685 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 20686 if (inOutLocation == null || inOutLocation.length < 2) { 20687 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 20688 } 20689 20690 if (mAttachInfo == null) { 20691 // When the view is not attached to a window, this method does not make sense 20692 inOutLocation[0] = inOutLocation[1] = 0; 20693 return; 20694 } 20695 20696 float position[] = mAttachInfo.mTmpTransformLocation; 20697 position[0] = inOutLocation[0]; 20698 position[1] = inOutLocation[1]; 20699 20700 if (!hasIdentityMatrix()) { 20701 getMatrix().mapPoints(position); 20702 } 20703 20704 position[0] += mLeft; 20705 position[1] += mTop; 20706 20707 ViewParent viewParent = mParent; 20708 while (viewParent instanceof View) { 20709 final View view = (View) viewParent; 20710 20711 position[0] -= view.mScrollX; 20712 position[1] -= view.mScrollY; 20713 20714 if (!view.hasIdentityMatrix()) { 20715 view.getMatrix().mapPoints(position); 20716 } 20717 20718 position[0] += view.mLeft; 20719 position[1] += view.mTop; 20720 20721 viewParent = view.mParent; 20722 } 20723 20724 if (viewParent instanceof ViewRootImpl) { 20725 // *cough* 20726 final ViewRootImpl vr = (ViewRootImpl) viewParent; 20727 position[1] -= vr.mCurScrollY; 20728 } 20729 20730 inOutLocation[0] = Math.round(position[0]); 20731 inOutLocation[1] = Math.round(position[1]); 20732 } 20733 20734 /** 20735 * @param id the id of the view to be found 20736 * @return the view of the specified id, null if cannot be found 20737 * @hide 20738 */ 20739 protected <T extends View> T findViewTraversal(@IdRes int id) { 20740 if (id == mID) { 20741 return (T) this; 20742 } 20743 return null; 20744 } 20745 20746 /** 20747 * @param tag the tag of the view to be found 20748 * @return the view of specified tag, null if cannot be found 20749 * @hide 20750 */ 20751 protected <T extends View> T findViewWithTagTraversal(Object tag) { 20752 if (tag != null && tag.equals(mTag)) { 20753 return (T) this; 20754 } 20755 return null; 20756 } 20757 20758 /** 20759 * @param predicate The predicate to evaluate. 20760 * @param childToSkip If not null, ignores this child during the recursive traversal. 20761 * @return The first view that matches the predicate or null. 20762 * @hide 20763 */ 20764 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 20765 View childToSkip) { 20766 if (predicate.test(this)) { 20767 return (T) this; 20768 } 20769 return null; 20770 } 20771 20772 /** 20773 * Look for a child view with the given id. If this view has the given 20774 * id, return this view. 20775 * 20776 * @param id The id to search for. 20777 * @return The view that has the given id in the hierarchy or null 20778 */ 20779 @Nullable 20780 public final <T extends View> T findViewById(@IdRes int id) { 20781 if (id < 0) { 20782 return null; 20783 } 20784 return findViewTraversal(id); 20785 } 20786 20787 /** 20788 * Finds a view by its unuque and stable accessibility id. 20789 * 20790 * @param accessibilityId The searched accessibility id. 20791 * @return The found view. 20792 */ 20793 final <T extends View> T findViewByAccessibilityId(int accessibilityId) { 20794 if (accessibilityId < 0) { 20795 return null; 20796 } 20797 T view = findViewByAccessibilityIdTraversal(accessibilityId); 20798 if (view != null) { 20799 return view.includeForAccessibility() ? view : null; 20800 } 20801 return null; 20802 } 20803 20804 /** 20805 * Performs the traversal to find a view by its unuque and stable accessibility id. 20806 * 20807 * <strong>Note:</strong>This method does not stop at the root namespace 20808 * boundary since the user can touch the screen at an arbitrary location 20809 * potentially crossing the root namespace bounday which will send an 20810 * accessibility event to accessibility services and they should be able 20811 * to obtain the event source. Also accessibility ids are guaranteed to be 20812 * unique in the window. 20813 * 20814 * @param accessibilityId The accessibility id. 20815 * @return The found view. 20816 * @hide 20817 */ 20818 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 20819 if (getAccessibilityViewId() == accessibilityId) { 20820 return (T) this; 20821 } 20822 return null; 20823 } 20824 20825 /** 20826 * Look for a child view with the given tag. If this view has the given 20827 * tag, return this view. 20828 * 20829 * @param tag The tag to search for, using "tag.equals(getTag())". 20830 * @return The View that has the given tag in the hierarchy or null 20831 */ 20832 public final <T extends View> T findViewWithTag(Object tag) { 20833 if (tag == null) { 20834 return null; 20835 } 20836 return findViewWithTagTraversal(tag); 20837 } 20838 20839 /** 20840 * Look for a child view that matches the specified predicate. 20841 * If this view matches the predicate, return this view. 20842 * 20843 * @param predicate The predicate to evaluate. 20844 * @return The first view that matches the predicate or null. 20845 * @hide 20846 */ 20847 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 20848 return findViewByPredicateTraversal(predicate, null); 20849 } 20850 20851 /** 20852 * Look for a child view that matches the specified predicate, 20853 * starting with the specified view and its descendents and then 20854 * recusively searching the ancestors and siblings of that view 20855 * until this view is reached. 20856 * 20857 * This method is useful in cases where the predicate does not match 20858 * a single unique view (perhaps multiple views use the same id) 20859 * and we are trying to find the view that is "closest" in scope to the 20860 * starting view. 20861 * 20862 * @param start The view to start from. 20863 * @param predicate The predicate to evaluate. 20864 * @return The first view that matches the predicate or null. 20865 * @hide 20866 */ 20867 public final <T extends View> T findViewByPredicateInsideOut( 20868 View start, Predicate<View> predicate) { 20869 View childToSkip = null; 20870 for (;;) { 20871 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 20872 if (view != null || start == this) { 20873 return view; 20874 } 20875 20876 ViewParent parent = start.getParent(); 20877 if (parent == null || !(parent instanceof View)) { 20878 return null; 20879 } 20880 20881 childToSkip = start; 20882 start = (View) parent; 20883 } 20884 } 20885 20886 /** 20887 * Sets the identifier for this view. The identifier does not have to be 20888 * unique in this view's hierarchy. The identifier should be a positive 20889 * number. 20890 * 20891 * @see #NO_ID 20892 * @see #getId() 20893 * @see #findViewById(int) 20894 * 20895 * @param id a number used to identify the view 20896 * 20897 * @attr ref android.R.styleable#View_id 20898 */ 20899 public void setId(@IdRes int id) { 20900 mID = id; 20901 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 20902 mID = generateViewId(); 20903 } 20904 } 20905 20906 /** 20907 * {@hide} 20908 * 20909 * @param isRoot true if the view belongs to the root namespace, false 20910 * otherwise 20911 */ 20912 public void setIsRootNamespace(boolean isRoot) { 20913 if (isRoot) { 20914 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 20915 } else { 20916 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 20917 } 20918 } 20919 20920 /** 20921 * {@hide} 20922 * 20923 * @return true if the view belongs to the root namespace, false otherwise 20924 */ 20925 public boolean isRootNamespace() { 20926 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 20927 } 20928 20929 /** 20930 * Returns this view's identifier. 20931 * 20932 * @return a positive integer used to identify the view or {@link #NO_ID} 20933 * if the view has no ID 20934 * 20935 * @see #setId(int) 20936 * @see #findViewById(int) 20937 * @attr ref android.R.styleable#View_id 20938 */ 20939 @IdRes 20940 @ViewDebug.CapturedViewProperty 20941 public int getId() { 20942 return mID; 20943 } 20944 20945 /** 20946 * Returns this view's tag. 20947 * 20948 * @return the Object stored in this view as a tag, or {@code null} if not 20949 * set 20950 * 20951 * @see #setTag(Object) 20952 * @see #getTag(int) 20953 */ 20954 @ViewDebug.ExportedProperty 20955 public Object getTag() { 20956 return mTag; 20957 } 20958 20959 /** 20960 * Sets the tag associated with this view. A tag can be used to mark 20961 * a view in its hierarchy and does not have to be unique within the 20962 * hierarchy. Tags can also be used to store data within a view without 20963 * resorting to another data structure. 20964 * 20965 * @param tag an Object to tag the view with 20966 * 20967 * @see #getTag() 20968 * @see #setTag(int, Object) 20969 */ 20970 public void setTag(final Object tag) { 20971 mTag = tag; 20972 } 20973 20974 /** 20975 * Returns the tag associated with this view and the specified key. 20976 * 20977 * @param key The key identifying the tag 20978 * 20979 * @return the Object stored in this view as a tag, or {@code null} if not 20980 * set 20981 * 20982 * @see #setTag(int, Object) 20983 * @see #getTag() 20984 */ 20985 public Object getTag(int key) { 20986 if (mKeyedTags != null) return mKeyedTags.get(key); 20987 return null; 20988 } 20989 20990 /** 20991 * Sets a tag associated with this view and a key. A tag can be used 20992 * to mark a view in its hierarchy and does not have to be unique within 20993 * the hierarchy. Tags can also be used to store data within a view 20994 * without resorting to another data structure. 20995 * 20996 * The specified key should be an id declared in the resources of the 20997 * application to ensure it is unique (see the <a 20998 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 20999 * Keys identified as belonging to 21000 * the Android framework or not associated with any package will cause 21001 * an {@link IllegalArgumentException} to be thrown. 21002 * 21003 * @param key The key identifying the tag 21004 * @param tag An Object to tag the view with 21005 * 21006 * @throws IllegalArgumentException If they specified key is not valid 21007 * 21008 * @see #setTag(Object) 21009 * @see #getTag(int) 21010 */ 21011 public void setTag(int key, final Object tag) { 21012 // If the package id is 0x00 or 0x01, it's either an undefined package 21013 // or a framework id 21014 if ((key >>> 24) < 2) { 21015 throw new IllegalArgumentException("The key must be an application-specific " 21016 + "resource id."); 21017 } 21018 21019 setKeyedTag(key, tag); 21020 } 21021 21022 /** 21023 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 21024 * framework id. 21025 * 21026 * @hide 21027 */ 21028 public void setTagInternal(int key, Object tag) { 21029 if ((key >>> 24) != 0x1) { 21030 throw new IllegalArgumentException("The key must be a framework-specific " 21031 + "resource id."); 21032 } 21033 21034 setKeyedTag(key, tag); 21035 } 21036 21037 private void setKeyedTag(int key, Object tag) { 21038 if (mKeyedTags == null) { 21039 mKeyedTags = new SparseArray<Object>(2); 21040 } 21041 21042 mKeyedTags.put(key, tag); 21043 } 21044 21045 /** 21046 * Prints information about this view in the log output, with the tag 21047 * {@link #VIEW_LOG_TAG}. 21048 * 21049 * @hide 21050 */ 21051 public void debug() { 21052 debug(0); 21053 } 21054 21055 /** 21056 * Prints information about this view in the log output, with the tag 21057 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 21058 * indentation defined by the <code>depth</code>. 21059 * 21060 * @param depth the indentation level 21061 * 21062 * @hide 21063 */ 21064 protected void debug(int depth) { 21065 String output = debugIndent(depth - 1); 21066 21067 output += "+ " + this; 21068 int id = getId(); 21069 if (id != -1) { 21070 output += " (id=" + id + ")"; 21071 } 21072 Object tag = getTag(); 21073 if (tag != null) { 21074 output += " (tag=" + tag + ")"; 21075 } 21076 Log.d(VIEW_LOG_TAG, output); 21077 21078 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 21079 output = debugIndent(depth) + " FOCUSED"; 21080 Log.d(VIEW_LOG_TAG, output); 21081 } 21082 21083 output = debugIndent(depth); 21084 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 21085 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 21086 + "} "; 21087 Log.d(VIEW_LOG_TAG, output); 21088 21089 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 21090 || mPaddingBottom != 0) { 21091 output = debugIndent(depth); 21092 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 21093 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 21094 Log.d(VIEW_LOG_TAG, output); 21095 } 21096 21097 output = debugIndent(depth); 21098 output += "mMeasureWidth=" + mMeasuredWidth + 21099 " mMeasureHeight=" + mMeasuredHeight; 21100 Log.d(VIEW_LOG_TAG, output); 21101 21102 output = debugIndent(depth); 21103 if (mLayoutParams == null) { 21104 output += "BAD! no layout params"; 21105 } else { 21106 output = mLayoutParams.debug(output); 21107 } 21108 Log.d(VIEW_LOG_TAG, output); 21109 21110 output = debugIndent(depth); 21111 output += "flags={"; 21112 output += View.printFlags(mViewFlags); 21113 output += "}"; 21114 Log.d(VIEW_LOG_TAG, output); 21115 21116 output = debugIndent(depth); 21117 output += "privateFlags={"; 21118 output += View.printPrivateFlags(mPrivateFlags); 21119 output += "}"; 21120 Log.d(VIEW_LOG_TAG, output); 21121 } 21122 21123 /** 21124 * Creates a string of whitespaces used for indentation. 21125 * 21126 * @param depth the indentation level 21127 * @return a String containing (depth * 2 + 3) * 2 white spaces 21128 * 21129 * @hide 21130 */ 21131 protected static String debugIndent(int depth) { 21132 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 21133 for (int i = 0; i < (depth * 2) + 3; i++) { 21134 spaces.append(' ').append(' '); 21135 } 21136 return spaces.toString(); 21137 } 21138 21139 /** 21140 * <p>Return the offset of the widget's text baseline from the widget's top 21141 * boundary. If this widget does not support baseline alignment, this 21142 * method returns -1. </p> 21143 * 21144 * @return the offset of the baseline within the widget's bounds or -1 21145 * if baseline alignment is not supported 21146 */ 21147 @ViewDebug.ExportedProperty(category = "layout") 21148 public int getBaseline() { 21149 return -1; 21150 } 21151 21152 /** 21153 * Returns whether the view hierarchy is currently undergoing a layout pass. This 21154 * information is useful to avoid situations such as calling {@link #requestLayout()} during 21155 * a layout pass. 21156 * 21157 * @return whether the view hierarchy is currently undergoing a layout pass 21158 */ 21159 public boolean isInLayout() { 21160 ViewRootImpl viewRoot = getViewRootImpl(); 21161 return (viewRoot != null && viewRoot.isInLayout()); 21162 } 21163 21164 /** 21165 * Call this when something has changed which has invalidated the 21166 * layout of this view. This will schedule a layout pass of the view 21167 * tree. This should not be called while the view hierarchy is currently in a layout 21168 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 21169 * end of the current layout pass (and then layout will run again) or after the current 21170 * frame is drawn and the next layout occurs. 21171 * 21172 * <p>Subclasses which override this method should call the superclass method to 21173 * handle possible request-during-layout errors correctly.</p> 21174 */ 21175 @CallSuper 21176 public void requestLayout() { 21177 if (mMeasureCache != null) mMeasureCache.clear(); 21178 21179 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 21180 // Only trigger request-during-layout logic if this is the view requesting it, 21181 // not the views in its parent hierarchy 21182 ViewRootImpl viewRoot = getViewRootImpl(); 21183 if (viewRoot != null && viewRoot.isInLayout()) { 21184 if (!viewRoot.requestLayoutDuringLayout(this)) { 21185 return; 21186 } 21187 } 21188 mAttachInfo.mViewRequestingLayout = this; 21189 } 21190 21191 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21192 mPrivateFlags |= PFLAG_INVALIDATED; 21193 21194 if (mParent != null && !mParent.isLayoutRequested()) { 21195 mParent.requestLayout(); 21196 } 21197 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 21198 mAttachInfo.mViewRequestingLayout = null; 21199 } 21200 } 21201 21202 /** 21203 * Forces this view to be laid out during the next layout pass. 21204 * This method does not call requestLayout() or forceLayout() 21205 * on the parent. 21206 */ 21207 public void forceLayout() { 21208 if (mMeasureCache != null) mMeasureCache.clear(); 21209 21210 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21211 mPrivateFlags |= PFLAG_INVALIDATED; 21212 } 21213 21214 /** 21215 * <p> 21216 * This is called to find out how big a view should be. The parent 21217 * supplies constraint information in the width and height parameters. 21218 * </p> 21219 * 21220 * <p> 21221 * The actual measurement work of a view is performed in 21222 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 21223 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 21224 * </p> 21225 * 21226 * 21227 * @param widthMeasureSpec Horizontal space requirements as imposed by the 21228 * parent 21229 * @param heightMeasureSpec Vertical space requirements as imposed by the 21230 * parent 21231 * 21232 * @see #onMeasure(int, int) 21233 */ 21234 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 21235 boolean optical = isLayoutModeOptical(this); 21236 if (optical != isLayoutModeOptical(mParent)) { 21237 Insets insets = getOpticalInsets(); 21238 int oWidth = insets.left + insets.right; 21239 int oHeight = insets.top + insets.bottom; 21240 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 21241 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 21242 } 21243 21244 // Suppress sign extension for the low bytes 21245 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 21246 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 21247 21248 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 21249 21250 // Optimize layout by avoiding an extra EXACTLY pass when the view is 21251 // already measured as the correct size. In API 23 and below, this 21252 // extra pass is required to make LinearLayout re-distribute weight. 21253 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 21254 || heightMeasureSpec != mOldHeightMeasureSpec; 21255 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 21256 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 21257 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 21258 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 21259 final boolean needsLayout = specChanged 21260 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 21261 21262 if (forceLayout || needsLayout) { 21263 // first clears the measured dimension flag 21264 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 21265 21266 resolveRtlPropertiesIfNeeded(); 21267 21268 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 21269 if (cacheIndex < 0 || sIgnoreMeasureCache) { 21270 // measure ourselves, this should set the measured dimension flag back 21271 onMeasure(widthMeasureSpec, heightMeasureSpec); 21272 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 21273 } else { 21274 long value = mMeasureCache.valueAt(cacheIndex); 21275 // Casting a long to int drops the high 32 bits, no mask needed 21276 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 21277 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 21278 } 21279 21280 // flag not set, setMeasuredDimension() was not invoked, we raise 21281 // an exception to warn the developer 21282 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 21283 throw new IllegalStateException("View with id " + getId() + ": " 21284 + getClass().getName() + "#onMeasure() did not set the" 21285 + " measured dimension by calling" 21286 + " setMeasuredDimension()"); 21287 } 21288 21289 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 21290 } 21291 21292 mOldWidthMeasureSpec = widthMeasureSpec; 21293 mOldHeightMeasureSpec = heightMeasureSpec; 21294 21295 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 21296 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 21297 } 21298 21299 /** 21300 * <p> 21301 * Measure the view and its content to determine the measured width and the 21302 * measured height. This method is invoked by {@link #measure(int, int)} and 21303 * should be overridden by subclasses to provide accurate and efficient 21304 * measurement of their contents. 21305 * </p> 21306 * 21307 * <p> 21308 * <strong>CONTRACT:</strong> When overriding this method, you 21309 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 21310 * measured width and height of this view. Failure to do so will trigger an 21311 * <code>IllegalStateException</code>, thrown by 21312 * {@link #measure(int, int)}. Calling the superclass' 21313 * {@link #onMeasure(int, int)} is a valid use. 21314 * </p> 21315 * 21316 * <p> 21317 * The base class implementation of measure defaults to the background size, 21318 * unless a larger size is allowed by the MeasureSpec. Subclasses should 21319 * override {@link #onMeasure(int, int)} to provide better measurements of 21320 * their content. 21321 * </p> 21322 * 21323 * <p> 21324 * If this method is overridden, it is the subclass's responsibility to make 21325 * sure the measured height and width are at least the view's minimum height 21326 * and width ({@link #getSuggestedMinimumHeight()} and 21327 * {@link #getSuggestedMinimumWidth()}). 21328 * </p> 21329 * 21330 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 21331 * The requirements are encoded with 21332 * {@link android.view.View.MeasureSpec}. 21333 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 21334 * The requirements are encoded with 21335 * {@link android.view.View.MeasureSpec}. 21336 * 21337 * @see #getMeasuredWidth() 21338 * @see #getMeasuredHeight() 21339 * @see #setMeasuredDimension(int, int) 21340 * @see #getSuggestedMinimumHeight() 21341 * @see #getSuggestedMinimumWidth() 21342 * @see android.view.View.MeasureSpec#getMode(int) 21343 * @see android.view.View.MeasureSpec#getSize(int) 21344 */ 21345 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 21346 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 21347 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 21348 } 21349 21350 /** 21351 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 21352 * measured width and measured height. Failing to do so will trigger an 21353 * exception at measurement time.</p> 21354 * 21355 * @param measuredWidth The measured width of this view. May be a complex 21356 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 21357 * {@link #MEASURED_STATE_TOO_SMALL}. 21358 * @param measuredHeight The measured height of this view. May be a complex 21359 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 21360 * {@link #MEASURED_STATE_TOO_SMALL}. 21361 */ 21362 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 21363 boolean optical = isLayoutModeOptical(this); 21364 if (optical != isLayoutModeOptical(mParent)) { 21365 Insets insets = getOpticalInsets(); 21366 int opticalWidth = insets.left + insets.right; 21367 int opticalHeight = insets.top + insets.bottom; 21368 21369 measuredWidth += optical ? opticalWidth : -opticalWidth; 21370 measuredHeight += optical ? opticalHeight : -opticalHeight; 21371 } 21372 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 21373 } 21374 21375 /** 21376 * Sets the measured dimension without extra processing for things like optical bounds. 21377 * Useful for reapplying consistent values that have already been cooked with adjustments 21378 * for optical bounds, etc. such as those from the measurement cache. 21379 * 21380 * @param measuredWidth The measured width of this view. May be a complex 21381 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 21382 * {@link #MEASURED_STATE_TOO_SMALL}. 21383 * @param measuredHeight The measured height of this view. May be a complex 21384 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 21385 * {@link #MEASURED_STATE_TOO_SMALL}. 21386 */ 21387 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 21388 mMeasuredWidth = measuredWidth; 21389 mMeasuredHeight = measuredHeight; 21390 21391 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 21392 } 21393 21394 /** 21395 * Merge two states as returned by {@link #getMeasuredState()}. 21396 * @param curState The current state as returned from a view or the result 21397 * of combining multiple views. 21398 * @param newState The new view state to combine. 21399 * @return Returns a new integer reflecting the combination of the two 21400 * states. 21401 */ 21402 public static int combineMeasuredStates(int curState, int newState) { 21403 return curState | newState; 21404 } 21405 21406 /** 21407 * Version of {@link #resolveSizeAndState(int, int, int)} 21408 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 21409 */ 21410 public static int resolveSize(int size, int measureSpec) { 21411 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 21412 } 21413 21414 /** 21415 * Utility to reconcile a desired size and state, with constraints imposed 21416 * by a MeasureSpec. Will take the desired size, unless a different size 21417 * is imposed by the constraints. The returned value is a compound integer, 21418 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 21419 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 21420 * resulting size is smaller than the size the view wants to be. 21421 * 21422 * @param size How big the view wants to be. 21423 * @param measureSpec Constraints imposed by the parent. 21424 * @param childMeasuredState Size information bit mask for the view's 21425 * children. 21426 * @return Size information bit mask as defined by 21427 * {@link #MEASURED_SIZE_MASK} and 21428 * {@link #MEASURED_STATE_TOO_SMALL}. 21429 */ 21430 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 21431 final int specMode = MeasureSpec.getMode(measureSpec); 21432 final int specSize = MeasureSpec.getSize(measureSpec); 21433 final int result; 21434 switch (specMode) { 21435 case MeasureSpec.AT_MOST: 21436 if (specSize < size) { 21437 result = specSize | MEASURED_STATE_TOO_SMALL; 21438 } else { 21439 result = size; 21440 } 21441 break; 21442 case MeasureSpec.EXACTLY: 21443 result = specSize; 21444 break; 21445 case MeasureSpec.UNSPECIFIED: 21446 default: 21447 result = size; 21448 } 21449 return result | (childMeasuredState & MEASURED_STATE_MASK); 21450 } 21451 21452 /** 21453 * Utility to return a default size. Uses the supplied size if the 21454 * MeasureSpec imposed no constraints. Will get larger if allowed 21455 * by the MeasureSpec. 21456 * 21457 * @param size Default size for this view 21458 * @param measureSpec Constraints imposed by the parent 21459 * @return The size this view should be. 21460 */ 21461 public static int getDefaultSize(int size, int measureSpec) { 21462 int result = size; 21463 int specMode = MeasureSpec.getMode(measureSpec); 21464 int specSize = MeasureSpec.getSize(measureSpec); 21465 21466 switch (specMode) { 21467 case MeasureSpec.UNSPECIFIED: 21468 result = size; 21469 break; 21470 case MeasureSpec.AT_MOST: 21471 case MeasureSpec.EXACTLY: 21472 result = specSize; 21473 break; 21474 } 21475 return result; 21476 } 21477 21478 /** 21479 * Returns the suggested minimum height that the view should use. This 21480 * returns the maximum of the view's minimum height 21481 * and the background's minimum height 21482 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 21483 * <p> 21484 * When being used in {@link #onMeasure(int, int)}, the caller should still 21485 * ensure the returned height is within the requirements of the parent. 21486 * 21487 * @return The suggested minimum height of the view. 21488 */ 21489 protected int getSuggestedMinimumHeight() { 21490 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 21491 21492 } 21493 21494 /** 21495 * Returns the suggested minimum width that the view should use. This 21496 * returns the maximum of the view's minimum width 21497 * and the background's minimum width 21498 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 21499 * <p> 21500 * When being used in {@link #onMeasure(int, int)}, the caller should still 21501 * ensure the returned width is within the requirements of the parent. 21502 * 21503 * @return The suggested minimum width of the view. 21504 */ 21505 protected int getSuggestedMinimumWidth() { 21506 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 21507 } 21508 21509 /** 21510 * Returns the minimum height of the view. 21511 * 21512 * @return the minimum height the view will try to be, in pixels 21513 * 21514 * @see #setMinimumHeight(int) 21515 * 21516 * @attr ref android.R.styleable#View_minHeight 21517 */ 21518 public int getMinimumHeight() { 21519 return mMinHeight; 21520 } 21521 21522 /** 21523 * Sets the minimum height of the view. It is not guaranteed the view will 21524 * be able to achieve this minimum height (for example, if its parent layout 21525 * constrains it with less available height). 21526 * 21527 * @param minHeight The minimum height the view will try to be, in pixels 21528 * 21529 * @see #getMinimumHeight() 21530 * 21531 * @attr ref android.R.styleable#View_minHeight 21532 */ 21533 @RemotableViewMethod 21534 public void setMinimumHeight(int minHeight) { 21535 mMinHeight = minHeight; 21536 requestLayout(); 21537 } 21538 21539 /** 21540 * Returns the minimum width of the view. 21541 * 21542 * @return the minimum width the view will try to be, in pixels 21543 * 21544 * @see #setMinimumWidth(int) 21545 * 21546 * @attr ref android.R.styleable#View_minWidth 21547 */ 21548 public int getMinimumWidth() { 21549 return mMinWidth; 21550 } 21551 21552 /** 21553 * Sets the minimum width of the view. It is not guaranteed the view will 21554 * be able to achieve this minimum width (for example, if its parent layout 21555 * constrains it with less available width). 21556 * 21557 * @param minWidth The minimum width the view will try to be, in pixels 21558 * 21559 * @see #getMinimumWidth() 21560 * 21561 * @attr ref android.R.styleable#View_minWidth 21562 */ 21563 public void setMinimumWidth(int minWidth) { 21564 mMinWidth = minWidth; 21565 requestLayout(); 21566 21567 } 21568 21569 /** 21570 * Get the animation currently associated with this view. 21571 * 21572 * @return The animation that is currently playing or 21573 * scheduled to play for this view. 21574 */ 21575 public Animation getAnimation() { 21576 return mCurrentAnimation; 21577 } 21578 21579 /** 21580 * Start the specified animation now. 21581 * 21582 * @param animation the animation to start now 21583 */ 21584 public void startAnimation(Animation animation) { 21585 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 21586 setAnimation(animation); 21587 invalidateParentCaches(); 21588 invalidate(true); 21589 } 21590 21591 /** 21592 * Cancels any animations for this view. 21593 */ 21594 public void clearAnimation() { 21595 if (mCurrentAnimation != null) { 21596 mCurrentAnimation.detach(); 21597 } 21598 mCurrentAnimation = null; 21599 invalidateParentIfNeeded(); 21600 } 21601 21602 /** 21603 * Sets the next animation to play for this view. 21604 * If you want the animation to play immediately, use 21605 * {@link #startAnimation(android.view.animation.Animation)} instead. 21606 * This method provides allows fine-grained 21607 * control over the start time and invalidation, but you 21608 * must make sure that 1) the animation has a start time set, and 21609 * 2) the view's parent (which controls animations on its children) 21610 * will be invalidated when the animation is supposed to 21611 * start. 21612 * 21613 * @param animation The next animation, or null. 21614 */ 21615 public void setAnimation(Animation animation) { 21616 mCurrentAnimation = animation; 21617 21618 if (animation != null) { 21619 // If the screen is off assume the animation start time is now instead of 21620 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 21621 // would cause the animation to start when the screen turns back on 21622 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 21623 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 21624 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 21625 } 21626 animation.reset(); 21627 } 21628 } 21629 21630 /** 21631 * Invoked by a parent ViewGroup to notify the start of the animation 21632 * currently associated with this view. If you override this method, 21633 * always call super.onAnimationStart(); 21634 * 21635 * @see #setAnimation(android.view.animation.Animation) 21636 * @see #getAnimation() 21637 */ 21638 @CallSuper 21639 protected void onAnimationStart() { 21640 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 21641 } 21642 21643 /** 21644 * Invoked by a parent ViewGroup to notify the end of the animation 21645 * currently associated with this view. If you override this method, 21646 * always call super.onAnimationEnd(); 21647 * 21648 * @see #setAnimation(android.view.animation.Animation) 21649 * @see #getAnimation() 21650 */ 21651 @CallSuper 21652 protected void onAnimationEnd() { 21653 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 21654 } 21655 21656 /** 21657 * Invoked if there is a Transform that involves alpha. Subclass that can 21658 * draw themselves with the specified alpha should return true, and then 21659 * respect that alpha when their onDraw() is called. If this returns false 21660 * then the view may be redirected to draw into an offscreen buffer to 21661 * fulfill the request, which will look fine, but may be slower than if the 21662 * subclass handles it internally. The default implementation returns false. 21663 * 21664 * @param alpha The alpha (0..255) to apply to the view's drawing 21665 * @return true if the view can draw with the specified alpha. 21666 */ 21667 protected boolean onSetAlpha(int alpha) { 21668 return false; 21669 } 21670 21671 /** 21672 * This is used by the RootView to perform an optimization when 21673 * the view hierarchy contains one or several SurfaceView. 21674 * SurfaceView is always considered transparent, but its children are not, 21675 * therefore all View objects remove themselves from the global transparent 21676 * region (passed as a parameter to this function). 21677 * 21678 * @param region The transparent region for this ViewAncestor (window). 21679 * 21680 * @return Returns true if the effective visibility of the view at this 21681 * point is opaque, regardless of the transparent region; returns false 21682 * if it is possible for underlying windows to be seen behind the view. 21683 * 21684 * {@hide} 21685 */ 21686 public boolean gatherTransparentRegion(Region region) { 21687 final AttachInfo attachInfo = mAttachInfo; 21688 if (region != null && attachInfo != null) { 21689 final int pflags = mPrivateFlags; 21690 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 21691 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 21692 // remove it from the transparent region. 21693 final int[] location = attachInfo.mTransparentLocation; 21694 getLocationInWindow(location); 21695 // When a view has Z value, then it will be better to leave some area below the view 21696 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 21697 // the bottom part needs more offset than the left, top and right parts due to the 21698 // spot light effects. 21699 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 21700 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 21701 location[0] + mRight - mLeft + shadowOffset, 21702 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 21703 } else { 21704 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 21705 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 21706 // the background drawable's non-transparent parts from this transparent region. 21707 applyDrawableToTransparentRegion(mBackground, region); 21708 } 21709 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 21710 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 21711 // Similarly, we remove the foreground drawable's non-transparent parts. 21712 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 21713 } 21714 } 21715 } 21716 return true; 21717 } 21718 21719 /** 21720 * Play a sound effect for this view. 21721 * 21722 * <p>The framework will play sound effects for some built in actions, such as 21723 * clicking, but you may wish to play these effects in your widget, 21724 * for instance, for internal navigation. 21725 * 21726 * <p>The sound effect will only be played if sound effects are enabled by the user, and 21727 * {@link #isSoundEffectsEnabled()} is true. 21728 * 21729 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 21730 */ 21731 public void playSoundEffect(int soundConstant) { 21732 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 21733 return; 21734 } 21735 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 21736 } 21737 21738 /** 21739 * BZZZTT!!1! 21740 * 21741 * <p>Provide haptic feedback to the user for this view. 21742 * 21743 * <p>The framework will provide haptic feedback for some built in actions, 21744 * such as long presses, but you may wish to provide feedback for your 21745 * own widget. 21746 * 21747 * <p>The feedback will only be performed if 21748 * {@link #isHapticFeedbackEnabled()} is true. 21749 * 21750 * @param feedbackConstant One of the constants defined in 21751 * {@link HapticFeedbackConstants} 21752 */ 21753 public boolean performHapticFeedback(int feedbackConstant) { 21754 return performHapticFeedback(feedbackConstant, 0); 21755 } 21756 21757 /** 21758 * BZZZTT!!1! 21759 * 21760 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 21761 * 21762 * @param feedbackConstant One of the constants defined in 21763 * {@link HapticFeedbackConstants} 21764 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 21765 */ 21766 public boolean performHapticFeedback(int feedbackConstant, int flags) { 21767 if (mAttachInfo == null) { 21768 return false; 21769 } 21770 //noinspection SimplifiableIfStatement 21771 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 21772 && !isHapticFeedbackEnabled()) { 21773 return false; 21774 } 21775 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 21776 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 21777 } 21778 21779 /** 21780 * Request that the visibility of the status bar or other screen/window 21781 * decorations be changed. 21782 * 21783 * <p>This method is used to put the over device UI into temporary modes 21784 * where the user's attention is focused more on the application content, 21785 * by dimming or hiding surrounding system affordances. This is typically 21786 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 21787 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 21788 * to be placed behind the action bar (and with these flags other system 21789 * affordances) so that smooth transitions between hiding and showing them 21790 * can be done. 21791 * 21792 * <p>Two representative examples of the use of system UI visibility is 21793 * implementing a content browsing application (like a magazine reader) 21794 * and a video playing application. 21795 * 21796 * <p>The first code shows a typical implementation of a View in a content 21797 * browsing application. In this implementation, the application goes 21798 * into a content-oriented mode by hiding the status bar and action bar, 21799 * and putting the navigation elements into lights out mode. The user can 21800 * then interact with content while in this mode. Such an application should 21801 * provide an easy way for the user to toggle out of the mode (such as to 21802 * check information in the status bar or access notifications). In the 21803 * implementation here, this is done simply by tapping on the content. 21804 * 21805 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 21806 * content} 21807 * 21808 * <p>This second code sample shows a typical implementation of a View 21809 * in a video playing application. In this situation, while the video is 21810 * playing the application would like to go into a complete full-screen mode, 21811 * to use as much of the display as possible for the video. When in this state 21812 * the user can not interact with the application; the system intercepts 21813 * touching on the screen to pop the UI out of full screen mode. See 21814 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 21815 * 21816 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 21817 * content} 21818 * 21819 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 21820 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 21821 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 21822 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 21823 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 21824 */ 21825 public void setSystemUiVisibility(int visibility) { 21826 if (visibility != mSystemUiVisibility) { 21827 mSystemUiVisibility = visibility; 21828 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 21829 mParent.recomputeViewAttributes(this); 21830 } 21831 } 21832 } 21833 21834 /** 21835 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 21836 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 21837 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 21838 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 21839 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 21840 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 21841 */ 21842 public int getSystemUiVisibility() { 21843 return mSystemUiVisibility; 21844 } 21845 21846 /** 21847 * Returns the current system UI visibility that is currently set for 21848 * the entire window. This is the combination of the 21849 * {@link #setSystemUiVisibility(int)} values supplied by all of the 21850 * views in the window. 21851 */ 21852 public int getWindowSystemUiVisibility() { 21853 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 21854 } 21855 21856 /** 21857 * Override to find out when the window's requested system UI visibility 21858 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 21859 * This is different from the callbacks received through 21860 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 21861 * in that this is only telling you about the local request of the window, 21862 * not the actual values applied by the system. 21863 */ 21864 public void onWindowSystemUiVisibilityChanged(int visible) { 21865 } 21866 21867 /** 21868 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 21869 * the view hierarchy. 21870 */ 21871 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 21872 onWindowSystemUiVisibilityChanged(visible); 21873 } 21874 21875 /** 21876 * Set a listener to receive callbacks when the visibility of the system bar changes. 21877 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 21878 */ 21879 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 21880 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 21881 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 21882 mParent.recomputeViewAttributes(this); 21883 } 21884 } 21885 21886 /** 21887 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 21888 * the view hierarchy. 21889 */ 21890 public void dispatchSystemUiVisibilityChanged(int visibility) { 21891 ListenerInfo li = mListenerInfo; 21892 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 21893 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 21894 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 21895 } 21896 } 21897 21898 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 21899 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 21900 if (val != mSystemUiVisibility) { 21901 setSystemUiVisibility(val); 21902 return true; 21903 } 21904 return false; 21905 } 21906 21907 /** @hide */ 21908 public void setDisabledSystemUiVisibility(int flags) { 21909 if (mAttachInfo != null) { 21910 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 21911 mAttachInfo.mDisabledSystemUiVisibility = flags; 21912 if (mParent != null) { 21913 mParent.recomputeViewAttributes(this); 21914 } 21915 } 21916 } 21917 } 21918 21919 /** 21920 * Creates an image that the system displays during the drag and drop 21921 * operation. This is called a "drag shadow". The default implementation 21922 * for a DragShadowBuilder based on a View returns an image that has exactly the same 21923 * appearance as the given View. The default also positions the center of the drag shadow 21924 * directly under the touch point. If no View is provided (the constructor with no parameters 21925 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 21926 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 21927 * default is an invisible drag shadow. 21928 * <p> 21929 * You are not required to use the View you provide to the constructor as the basis of the 21930 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 21931 * anything you want as the drag shadow. 21932 * </p> 21933 * <p> 21934 * You pass a DragShadowBuilder object to the system when you start the drag. The system 21935 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 21936 * size and position of the drag shadow. It uses this data to construct a 21937 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 21938 * so that your application can draw the shadow image in the Canvas. 21939 * </p> 21940 * 21941 * <div class="special reference"> 21942 * <h3>Developer Guides</h3> 21943 * <p>For a guide to implementing drag and drop features, read the 21944 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 21945 * </div> 21946 */ 21947 public static class DragShadowBuilder { 21948 private final WeakReference<View> mView; 21949 21950 /** 21951 * Constructs a shadow image builder based on a View. By default, the resulting drag 21952 * shadow will have the same appearance and dimensions as the View, with the touch point 21953 * over the center of the View. 21954 * @param view A View. Any View in scope can be used. 21955 */ 21956 public DragShadowBuilder(View view) { 21957 mView = new WeakReference<View>(view); 21958 } 21959 21960 /** 21961 * Construct a shadow builder object with no associated View. This 21962 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 21963 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 21964 * to supply the drag shadow's dimensions and appearance without 21965 * reference to any View object. If they are not overridden, then the result is an 21966 * invisible drag shadow. 21967 */ 21968 public DragShadowBuilder() { 21969 mView = new WeakReference<View>(null); 21970 } 21971 21972 /** 21973 * Returns the View object that had been passed to the 21974 * {@link #View.DragShadowBuilder(View)} 21975 * constructor. If that View parameter was {@code null} or if the 21976 * {@link #View.DragShadowBuilder()} 21977 * constructor was used to instantiate the builder object, this method will return 21978 * null. 21979 * 21980 * @return The View object associate with this builder object. 21981 */ 21982 @SuppressWarnings({"JavadocReference"}) 21983 final public View getView() { 21984 return mView.get(); 21985 } 21986 21987 /** 21988 * Provides the metrics for the shadow image. These include the dimensions of 21989 * the shadow image, and the point within that shadow that should 21990 * be centered under the touch location while dragging. 21991 * <p> 21992 * The default implementation sets the dimensions of the shadow to be the 21993 * same as the dimensions of the View itself and centers the shadow under 21994 * the touch point. 21995 * </p> 21996 * 21997 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 21998 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 21999 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 22000 * image. 22001 * 22002 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 22003 * shadow image that should be underneath the touch point during the drag and drop 22004 * operation. Your application must set {@link android.graphics.Point#x} to the 22005 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 22006 */ 22007 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 22008 final View view = mView.get(); 22009 if (view != null) { 22010 outShadowSize.set(view.getWidth(), view.getHeight()); 22011 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 22012 } else { 22013 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 22014 } 22015 } 22016 22017 /** 22018 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 22019 * based on the dimensions it received from the 22020 * {@link #onProvideShadowMetrics(Point, Point)} callback. 22021 * 22022 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 22023 */ 22024 public void onDrawShadow(Canvas canvas) { 22025 final View view = mView.get(); 22026 if (view != null) { 22027 view.draw(canvas); 22028 } else { 22029 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 22030 } 22031 } 22032 } 22033 22034 /** 22035 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 22036 * startDragAndDrop()} for newer platform versions. 22037 */ 22038 @Deprecated 22039 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 22040 Object myLocalState, int flags) { 22041 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 22042 } 22043 22044 /** 22045 * Starts a drag and drop operation. When your application calls this method, it passes a 22046 * {@link android.view.View.DragShadowBuilder} object to the system. The 22047 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 22048 * to get metrics for the drag shadow, and then calls the object's 22049 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 22050 * <p> 22051 * Once the system has the drag shadow, it begins the drag and drop operation by sending 22052 * drag events to all the View objects in your application that are currently visible. It does 22053 * this either by calling the View object's drag listener (an implementation of 22054 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 22055 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 22056 * Both are passed a {@link android.view.DragEvent} object that has a 22057 * {@link android.view.DragEvent#getAction()} value of 22058 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 22059 * </p> 22060 * <p> 22061 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 22062 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 22063 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 22064 * to the View the user selected for dragging. 22065 * </p> 22066 * @param data A {@link android.content.ClipData} object pointing to the data to be 22067 * transferred by the drag and drop operation. 22068 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22069 * drag shadow. 22070 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 22071 * drop operation. When dispatching drag events to views in the same activity this object 22072 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 22073 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 22074 * will return null). 22075 * <p> 22076 * myLocalState is a lightweight mechanism for the sending information from the dragged View 22077 * to the target Views. For example, it can contain flags that differentiate between a 22078 * a copy operation and a move operation. 22079 * </p> 22080 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 22081 * flags, or any combination of the following: 22082 * <ul> 22083 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 22084 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 22085 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 22086 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 22087 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 22088 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 22089 * </ul> 22090 * @return {@code true} if the method completes successfully, or 22091 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 22092 * do a drag, and so no drag operation is in progress. 22093 */ 22094 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 22095 Object myLocalState, int flags) { 22096 if (ViewDebug.DEBUG_DRAG) { 22097 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 22098 } 22099 if (mAttachInfo == null) { 22100 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 22101 return false; 22102 } 22103 22104 if (data != null) { 22105 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 22106 } 22107 22108 boolean okay = false; 22109 22110 Point shadowSize = new Point(); 22111 Point shadowTouchPoint = new Point(); 22112 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 22113 22114 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 22115 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 22116 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 22117 } 22118 22119 if (ViewDebug.DEBUG_DRAG) { 22120 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 22121 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 22122 } 22123 if (mAttachInfo.mDragSurface != null) { 22124 mAttachInfo.mDragSurface.release(); 22125 } 22126 mAttachInfo.mDragSurface = new Surface(); 22127 try { 22128 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 22129 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 22130 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 22131 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 22132 if (mAttachInfo.mDragToken != null) { 22133 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22134 try { 22135 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22136 shadowBuilder.onDrawShadow(canvas); 22137 } finally { 22138 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22139 } 22140 22141 final ViewRootImpl root = getViewRootImpl(); 22142 22143 // Cache the local state object for delivery with DragEvents 22144 root.setLocalDragState(myLocalState); 22145 22146 // repurpose 'shadowSize' for the last touch point 22147 root.getLastTouchPoint(shadowSize); 22148 22149 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 22150 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 22151 shadowTouchPoint.x, shadowTouchPoint.y, data); 22152 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 22153 } 22154 } catch (Exception e) { 22155 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 22156 mAttachInfo.mDragSurface.destroy(); 22157 mAttachInfo.mDragSurface = null; 22158 } 22159 22160 return okay; 22161 } 22162 22163 /** 22164 * Cancels an ongoing drag and drop operation. 22165 * <p> 22166 * A {@link android.view.DragEvent} object with 22167 * {@link android.view.DragEvent#getAction()} value of 22168 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 22169 * {@link android.view.DragEvent#getResult()} value of {@code false} 22170 * will be sent to every 22171 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 22172 * even if they are not currently visible. 22173 * </p> 22174 * <p> 22175 * This method can be called on any View in the same window as the View on which 22176 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 22177 * was called. 22178 * </p> 22179 */ 22180 public final void cancelDragAndDrop() { 22181 if (ViewDebug.DEBUG_DRAG) { 22182 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 22183 } 22184 if (mAttachInfo == null) { 22185 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 22186 return; 22187 } 22188 if (mAttachInfo.mDragToken != null) { 22189 try { 22190 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 22191 } catch (Exception e) { 22192 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 22193 } 22194 mAttachInfo.mDragToken = null; 22195 } else { 22196 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 22197 } 22198 } 22199 22200 /** 22201 * Updates the drag shadow for the ongoing drag and drop operation. 22202 * 22203 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22204 * new drag shadow. 22205 */ 22206 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 22207 if (ViewDebug.DEBUG_DRAG) { 22208 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 22209 } 22210 if (mAttachInfo == null) { 22211 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 22212 return; 22213 } 22214 if (mAttachInfo.mDragToken != null) { 22215 try { 22216 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22217 try { 22218 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22219 shadowBuilder.onDrawShadow(canvas); 22220 } finally { 22221 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22222 } 22223 } catch (Exception e) { 22224 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 22225 } 22226 } else { 22227 Log.e(VIEW_LOG_TAG, "No active drag"); 22228 } 22229 } 22230 22231 /** 22232 * Starts a move from {startX, startY}, the amount of the movement will be the offset 22233 * between {startX, startY} and the new cursor positon. 22234 * @param startX horizontal coordinate where the move started. 22235 * @param startY vertical coordinate where the move started. 22236 * @return whether moving was started successfully. 22237 * @hide 22238 */ 22239 public final boolean startMovingTask(float startX, float startY) { 22240 if (ViewDebug.DEBUG_POSITIONING) { 22241 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 22242 } 22243 try { 22244 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 22245 } catch (RemoteException e) { 22246 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 22247 } 22248 return false; 22249 } 22250 22251 /** 22252 * Handles drag events sent by the system following a call to 22253 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 22254 * startDragAndDrop()}. 22255 *<p> 22256 * When the system calls this method, it passes a 22257 * {@link android.view.DragEvent} object. A call to 22258 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 22259 * in DragEvent. The method uses these to determine what is happening in the drag and drop 22260 * operation. 22261 * @param event The {@link android.view.DragEvent} sent by the system. 22262 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 22263 * in DragEvent, indicating the type of drag event represented by this object. 22264 * @return {@code true} if the method was successful, otherwise {@code false}. 22265 * <p> 22266 * The method should return {@code true} in response to an action type of 22267 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 22268 * operation. 22269 * </p> 22270 * <p> 22271 * The method should also return {@code true} in response to an action type of 22272 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 22273 * {@code false} if it didn't. 22274 * </p> 22275 * <p> 22276 * For all other events, the return value is ignored. 22277 * </p> 22278 */ 22279 public boolean onDragEvent(DragEvent event) { 22280 return false; 22281 } 22282 22283 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 22284 boolean dispatchDragEnterExitInPreN(DragEvent event) { 22285 return callDragEventHandler(event); 22286 } 22287 22288 /** 22289 * Detects if this View is enabled and has a drag event listener. 22290 * If both are true, then it calls the drag event listener with the 22291 * {@link android.view.DragEvent} it received. If the drag event listener returns 22292 * {@code true}, then dispatchDragEvent() returns {@code true}. 22293 * <p> 22294 * For all other cases, the method calls the 22295 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 22296 * method and returns its result. 22297 * </p> 22298 * <p> 22299 * This ensures that a drag event is always consumed, even if the View does not have a drag 22300 * event listener. However, if the View has a listener and the listener returns true, then 22301 * onDragEvent() is not called. 22302 * </p> 22303 */ 22304 public boolean dispatchDragEvent(DragEvent event) { 22305 event.mEventHandlerWasCalled = true; 22306 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 22307 event.mAction == DragEvent.ACTION_DROP) { 22308 // About to deliver an event with coordinates to this view. Notify that now this view 22309 // has drag focus. This will send exit/enter events as needed. 22310 getViewRootImpl().setDragFocus(this, event); 22311 } 22312 return callDragEventHandler(event); 22313 } 22314 22315 final boolean callDragEventHandler(DragEvent event) { 22316 final boolean result; 22317 22318 ListenerInfo li = mListenerInfo; 22319 //noinspection SimplifiableIfStatement 22320 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 22321 && li.mOnDragListener.onDrag(this, event)) { 22322 result = true; 22323 } else { 22324 result = onDragEvent(event); 22325 } 22326 22327 switch (event.mAction) { 22328 case DragEvent.ACTION_DRAG_ENTERED: { 22329 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 22330 refreshDrawableState(); 22331 } break; 22332 case DragEvent.ACTION_DRAG_EXITED: { 22333 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 22334 refreshDrawableState(); 22335 } break; 22336 case DragEvent.ACTION_DRAG_ENDED: { 22337 mPrivateFlags2 &= ~View.DRAG_MASK; 22338 refreshDrawableState(); 22339 } break; 22340 } 22341 22342 return result; 22343 } 22344 22345 boolean canAcceptDrag() { 22346 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 22347 } 22348 22349 /** 22350 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 22351 * it is ever exposed at all. 22352 * @hide 22353 */ 22354 public void onCloseSystemDialogs(String reason) { 22355 } 22356 22357 /** 22358 * Given a Drawable whose bounds have been set to draw into this view, 22359 * update a Region being computed for 22360 * {@link #gatherTransparentRegion(android.graphics.Region)} so 22361 * that any non-transparent parts of the Drawable are removed from the 22362 * given transparent region. 22363 * 22364 * @param dr The Drawable whose transparency is to be applied to the region. 22365 * @param region A Region holding the current transparency information, 22366 * where any parts of the region that are set are considered to be 22367 * transparent. On return, this region will be modified to have the 22368 * transparency information reduced by the corresponding parts of the 22369 * Drawable that are not transparent. 22370 * {@hide} 22371 */ 22372 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 22373 if (DBG) { 22374 Log.i("View", "Getting transparent region for: " + this); 22375 } 22376 final Region r = dr.getTransparentRegion(); 22377 final Rect db = dr.getBounds(); 22378 final AttachInfo attachInfo = mAttachInfo; 22379 if (r != null && attachInfo != null) { 22380 final int w = getRight()-getLeft(); 22381 final int h = getBottom()-getTop(); 22382 if (db.left > 0) { 22383 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 22384 r.op(0, 0, db.left, h, Region.Op.UNION); 22385 } 22386 if (db.right < w) { 22387 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 22388 r.op(db.right, 0, w, h, Region.Op.UNION); 22389 } 22390 if (db.top > 0) { 22391 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 22392 r.op(0, 0, w, db.top, Region.Op.UNION); 22393 } 22394 if (db.bottom < h) { 22395 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 22396 r.op(0, db.bottom, w, h, Region.Op.UNION); 22397 } 22398 final int[] location = attachInfo.mTransparentLocation; 22399 getLocationInWindow(location); 22400 r.translate(location[0], location[1]); 22401 region.op(r, Region.Op.INTERSECT); 22402 } else { 22403 region.op(db, Region.Op.DIFFERENCE); 22404 } 22405 } 22406 22407 private void checkForLongClick(int delayOffset, float x, float y) { 22408 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 22409 mHasPerformedLongPress = false; 22410 22411 if (mPendingCheckForLongPress == null) { 22412 mPendingCheckForLongPress = new CheckForLongPress(); 22413 } 22414 mPendingCheckForLongPress.setAnchor(x, y); 22415 mPendingCheckForLongPress.rememberWindowAttachCount(); 22416 mPendingCheckForLongPress.rememberPressedState(); 22417 postDelayed(mPendingCheckForLongPress, 22418 ViewConfiguration.getLongPressTimeout() - delayOffset); 22419 } 22420 } 22421 22422 /** 22423 * Inflate a view from an XML resource. This convenience method wraps the {@link 22424 * LayoutInflater} class, which provides a full range of options for view inflation. 22425 * 22426 * @param context The Context object for your activity or application. 22427 * @param resource The resource ID to inflate 22428 * @param root A view group that will be the parent. Used to properly inflate the 22429 * layout_* parameters. 22430 * @see LayoutInflater 22431 */ 22432 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 22433 LayoutInflater factory = LayoutInflater.from(context); 22434 return factory.inflate(resource, root); 22435 } 22436 22437 /** 22438 * Scroll the view with standard behavior for scrolling beyond the normal 22439 * content boundaries. Views that call this method should override 22440 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 22441 * results of an over-scroll operation. 22442 * 22443 * Views can use this method to handle any touch or fling-based scrolling. 22444 * 22445 * @param deltaX Change in X in pixels 22446 * @param deltaY Change in Y in pixels 22447 * @param scrollX Current X scroll value in pixels before applying deltaX 22448 * @param scrollY Current Y scroll value in pixels before applying deltaY 22449 * @param scrollRangeX Maximum content scroll range along the X axis 22450 * @param scrollRangeY Maximum content scroll range along the Y axis 22451 * @param maxOverScrollX Number of pixels to overscroll by in either direction 22452 * along the X axis. 22453 * @param maxOverScrollY Number of pixels to overscroll by in either direction 22454 * along the Y axis. 22455 * @param isTouchEvent true if this scroll operation is the result of a touch event. 22456 * @return true if scrolling was clamped to an over-scroll boundary along either 22457 * axis, false otherwise. 22458 */ 22459 @SuppressWarnings({"UnusedParameters"}) 22460 protected boolean overScrollBy(int deltaX, int deltaY, 22461 int scrollX, int scrollY, 22462 int scrollRangeX, int scrollRangeY, 22463 int maxOverScrollX, int maxOverScrollY, 22464 boolean isTouchEvent) { 22465 final int overScrollMode = mOverScrollMode; 22466 final boolean canScrollHorizontal = 22467 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 22468 final boolean canScrollVertical = 22469 computeVerticalScrollRange() > computeVerticalScrollExtent(); 22470 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 22471 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 22472 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 22473 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 22474 22475 int newScrollX = scrollX + deltaX; 22476 if (!overScrollHorizontal) { 22477 maxOverScrollX = 0; 22478 } 22479 22480 int newScrollY = scrollY + deltaY; 22481 if (!overScrollVertical) { 22482 maxOverScrollY = 0; 22483 } 22484 22485 // Clamp values if at the limits and record 22486 final int left = -maxOverScrollX; 22487 final int right = maxOverScrollX + scrollRangeX; 22488 final int top = -maxOverScrollY; 22489 final int bottom = maxOverScrollY + scrollRangeY; 22490 22491 boolean clampedX = false; 22492 if (newScrollX > right) { 22493 newScrollX = right; 22494 clampedX = true; 22495 } else if (newScrollX < left) { 22496 newScrollX = left; 22497 clampedX = true; 22498 } 22499 22500 boolean clampedY = false; 22501 if (newScrollY > bottom) { 22502 newScrollY = bottom; 22503 clampedY = true; 22504 } else if (newScrollY < top) { 22505 newScrollY = top; 22506 clampedY = true; 22507 } 22508 22509 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 22510 22511 return clampedX || clampedY; 22512 } 22513 22514 /** 22515 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 22516 * respond to the results of an over-scroll operation. 22517 * 22518 * @param scrollX New X scroll value in pixels 22519 * @param scrollY New Y scroll value in pixels 22520 * @param clampedX True if scrollX was clamped to an over-scroll boundary 22521 * @param clampedY True if scrollY was clamped to an over-scroll boundary 22522 */ 22523 protected void onOverScrolled(int scrollX, int scrollY, 22524 boolean clampedX, boolean clampedY) { 22525 // Intentionally empty. 22526 } 22527 22528 /** 22529 * Returns the over-scroll mode for this view. The result will be 22530 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 22531 * (allow over-scrolling only if the view content is larger than the container), 22532 * or {@link #OVER_SCROLL_NEVER}. 22533 * 22534 * @return This view's over-scroll mode. 22535 */ 22536 public int getOverScrollMode() { 22537 return mOverScrollMode; 22538 } 22539 22540 /** 22541 * Set the over-scroll mode for this view. Valid over-scroll modes are 22542 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 22543 * (allow over-scrolling only if the view content is larger than the container), 22544 * or {@link #OVER_SCROLL_NEVER}. 22545 * 22546 * Setting the over-scroll mode of a view will have an effect only if the 22547 * view is capable of scrolling. 22548 * 22549 * @param overScrollMode The new over-scroll mode for this view. 22550 */ 22551 public void setOverScrollMode(int overScrollMode) { 22552 if (overScrollMode != OVER_SCROLL_ALWAYS && 22553 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 22554 overScrollMode != OVER_SCROLL_NEVER) { 22555 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 22556 } 22557 mOverScrollMode = overScrollMode; 22558 } 22559 22560 /** 22561 * Enable or disable nested scrolling for this view. 22562 * 22563 * <p>If this property is set to true the view will be permitted to initiate nested 22564 * scrolling operations with a compatible parent view in the current hierarchy. If this 22565 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 22566 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 22567 * the nested scroll.</p> 22568 * 22569 * @param enabled true to enable nested scrolling, false to disable 22570 * 22571 * @see #isNestedScrollingEnabled() 22572 */ 22573 public void setNestedScrollingEnabled(boolean enabled) { 22574 if (enabled) { 22575 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 22576 } else { 22577 stopNestedScroll(); 22578 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 22579 } 22580 } 22581 22582 /** 22583 * Returns true if nested scrolling is enabled for this view. 22584 * 22585 * <p>If nested scrolling is enabled and this View class implementation supports it, 22586 * this view will act as a nested scrolling child view when applicable, forwarding data 22587 * about the scroll operation in progress to a compatible and cooperating nested scrolling 22588 * parent.</p> 22589 * 22590 * @return true if nested scrolling is enabled 22591 * 22592 * @see #setNestedScrollingEnabled(boolean) 22593 */ 22594 public boolean isNestedScrollingEnabled() { 22595 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 22596 PFLAG3_NESTED_SCROLLING_ENABLED; 22597 } 22598 22599 /** 22600 * Begin a nestable scroll operation along the given axes. 22601 * 22602 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 22603 * 22604 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 22605 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 22606 * In the case of touch scrolling the nested scroll will be terminated automatically in 22607 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 22608 * In the event of programmatic scrolling the caller must explicitly call 22609 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 22610 * 22611 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 22612 * If it returns false the caller may ignore the rest of this contract until the next scroll. 22613 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 22614 * 22615 * <p>At each incremental step of the scroll the caller should invoke 22616 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 22617 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 22618 * parent at least partially consumed the scroll and the caller should adjust the amount it 22619 * scrolls by.</p> 22620 * 22621 * <p>After applying the remainder of the scroll delta the caller should invoke 22622 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 22623 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 22624 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 22625 * </p> 22626 * 22627 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 22628 * {@link #SCROLL_AXIS_VERTICAL}. 22629 * @return true if a cooperative parent was found and nested scrolling has been enabled for 22630 * the current gesture. 22631 * 22632 * @see #stopNestedScroll() 22633 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 22634 * @see #dispatchNestedScroll(int, int, int, int, int[]) 22635 */ 22636 public boolean startNestedScroll(int axes) { 22637 if (hasNestedScrollingParent()) { 22638 // Already in progress 22639 return true; 22640 } 22641 if (isNestedScrollingEnabled()) { 22642 ViewParent p = getParent(); 22643 View child = this; 22644 while (p != null) { 22645 try { 22646 if (p.onStartNestedScroll(child, this, axes)) { 22647 mNestedScrollingParent = p; 22648 p.onNestedScrollAccepted(child, this, axes); 22649 return true; 22650 } 22651 } catch (AbstractMethodError e) { 22652 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 22653 "method onStartNestedScroll", e); 22654 // Allow the search upward to continue 22655 } 22656 if (p instanceof View) { 22657 child = (View) p; 22658 } 22659 p = p.getParent(); 22660 } 22661 } 22662 return false; 22663 } 22664 22665 /** 22666 * Stop a nested scroll in progress. 22667 * 22668 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 22669 * 22670 * @see #startNestedScroll(int) 22671 */ 22672 public void stopNestedScroll() { 22673 if (mNestedScrollingParent != null) { 22674 mNestedScrollingParent.onStopNestedScroll(this); 22675 mNestedScrollingParent = null; 22676 } 22677 } 22678 22679 /** 22680 * Returns true if this view has a nested scrolling parent. 22681 * 22682 * <p>The presence of a nested scrolling parent indicates that this view has initiated 22683 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 22684 * 22685 * @return whether this view has a nested scrolling parent 22686 */ 22687 public boolean hasNestedScrollingParent() { 22688 return mNestedScrollingParent != null; 22689 } 22690 22691 /** 22692 * Dispatch one step of a nested scroll in progress. 22693 * 22694 * <p>Implementations of views that support nested scrolling should call this to report 22695 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 22696 * is not currently in progress or nested scrolling is not 22697 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 22698 * 22699 * <p>Compatible View implementations should also call 22700 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 22701 * consuming a component of the scroll event themselves.</p> 22702 * 22703 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 22704 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 22705 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 22706 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 22707 * @param offsetInWindow Optional. If not null, on return this will contain the offset 22708 * in local view coordinates of this view from before this operation 22709 * to after it completes. View implementations may use this to adjust 22710 * expected input coordinate tracking. 22711 * @return true if the event was dispatched, false if it could not be dispatched. 22712 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 22713 */ 22714 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 22715 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 22716 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22717 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 22718 int startX = 0; 22719 int startY = 0; 22720 if (offsetInWindow != null) { 22721 getLocationInWindow(offsetInWindow); 22722 startX = offsetInWindow[0]; 22723 startY = offsetInWindow[1]; 22724 } 22725 22726 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 22727 dxUnconsumed, dyUnconsumed); 22728 22729 if (offsetInWindow != null) { 22730 getLocationInWindow(offsetInWindow); 22731 offsetInWindow[0] -= startX; 22732 offsetInWindow[1] -= startY; 22733 } 22734 return true; 22735 } else if (offsetInWindow != null) { 22736 // No motion, no dispatch. Keep offsetInWindow up to date. 22737 offsetInWindow[0] = 0; 22738 offsetInWindow[1] = 0; 22739 } 22740 } 22741 return false; 22742 } 22743 22744 /** 22745 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 22746 * 22747 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 22748 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 22749 * scrolling operation to consume some or all of the scroll operation before the child view 22750 * consumes it.</p> 22751 * 22752 * @param dx Horizontal scroll distance in pixels 22753 * @param dy Vertical scroll distance in pixels 22754 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 22755 * and consumed[1] the consumed dy. 22756 * @param offsetInWindow Optional. If not null, on return this will contain the offset 22757 * in local view coordinates of this view from before this operation 22758 * to after it completes. View implementations may use this to adjust 22759 * expected input coordinate tracking. 22760 * @return true if the parent consumed some or all of the scroll delta 22761 * @see #dispatchNestedScroll(int, int, int, int, int[]) 22762 */ 22763 public boolean dispatchNestedPreScroll(int dx, int dy, 22764 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 22765 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22766 if (dx != 0 || dy != 0) { 22767 int startX = 0; 22768 int startY = 0; 22769 if (offsetInWindow != null) { 22770 getLocationInWindow(offsetInWindow); 22771 startX = offsetInWindow[0]; 22772 startY = offsetInWindow[1]; 22773 } 22774 22775 if (consumed == null) { 22776 if (mTempNestedScrollConsumed == null) { 22777 mTempNestedScrollConsumed = new int[2]; 22778 } 22779 consumed = mTempNestedScrollConsumed; 22780 } 22781 consumed[0] = 0; 22782 consumed[1] = 0; 22783 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 22784 22785 if (offsetInWindow != null) { 22786 getLocationInWindow(offsetInWindow); 22787 offsetInWindow[0] -= startX; 22788 offsetInWindow[1] -= startY; 22789 } 22790 return consumed[0] != 0 || consumed[1] != 0; 22791 } else if (offsetInWindow != null) { 22792 offsetInWindow[0] = 0; 22793 offsetInWindow[1] = 0; 22794 } 22795 } 22796 return false; 22797 } 22798 22799 /** 22800 * Dispatch a fling to a nested scrolling parent. 22801 * 22802 * <p>This method should be used to indicate that a nested scrolling child has detected 22803 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 22804 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 22805 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 22806 * along a scrollable axis.</p> 22807 * 22808 * <p>If a nested scrolling child view would normally fling but it is at the edge of 22809 * its own content, it can use this method to delegate the fling to its nested scrolling 22810 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 22811 * 22812 * @param velocityX Horizontal fling velocity in pixels per second 22813 * @param velocityY Vertical fling velocity in pixels per second 22814 * @param consumed true if the child consumed the fling, false otherwise 22815 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 22816 */ 22817 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 22818 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22819 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 22820 } 22821 return false; 22822 } 22823 22824 /** 22825 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 22826 * 22827 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 22828 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 22829 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 22830 * before the child view consumes it. If this method returns <code>true</code>, a nested 22831 * parent view consumed the fling and this view should not scroll as a result.</p> 22832 * 22833 * <p>For a better user experience, only one view in a nested scrolling chain should consume 22834 * the fling at a time. If a parent view consumed the fling this method will return false. 22835 * Custom view implementations should account for this in two ways:</p> 22836 * 22837 * <ul> 22838 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 22839 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 22840 * position regardless.</li> 22841 * <li>If a nested parent does consume the fling, this view should not scroll at all, 22842 * even to settle back to a valid idle position.</li> 22843 * </ul> 22844 * 22845 * <p>Views should also not offer fling velocities to nested parent views along an axis 22846 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 22847 * should not offer a horizontal fling velocity to its parents since scrolling along that 22848 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 22849 * 22850 * @param velocityX Horizontal fling velocity in pixels per second 22851 * @param velocityY Vertical fling velocity in pixels per second 22852 * @return true if a nested scrolling parent consumed the fling 22853 */ 22854 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 22855 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22856 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 22857 } 22858 return false; 22859 } 22860 22861 /** 22862 * Gets a scale factor that determines the distance the view should scroll 22863 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 22864 * @return The vertical scroll scale factor. 22865 * @hide 22866 */ 22867 protected float getVerticalScrollFactor() { 22868 if (mVerticalScrollFactor == 0) { 22869 TypedValue outValue = new TypedValue(); 22870 if (!mContext.getTheme().resolveAttribute( 22871 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 22872 throw new IllegalStateException( 22873 "Expected theme to define listPreferredItemHeight."); 22874 } 22875 mVerticalScrollFactor = outValue.getDimension( 22876 mContext.getResources().getDisplayMetrics()); 22877 } 22878 return mVerticalScrollFactor; 22879 } 22880 22881 /** 22882 * Gets a scale factor that determines the distance the view should scroll 22883 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 22884 * @return The horizontal scroll scale factor. 22885 * @hide 22886 */ 22887 protected float getHorizontalScrollFactor() { 22888 // TODO: Should use something else. 22889 return getVerticalScrollFactor(); 22890 } 22891 22892 /** 22893 * Return the value specifying the text direction or policy that was set with 22894 * {@link #setTextDirection(int)}. 22895 * 22896 * @return the defined text direction. It can be one of: 22897 * 22898 * {@link #TEXT_DIRECTION_INHERIT}, 22899 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22900 * {@link #TEXT_DIRECTION_ANY_RTL}, 22901 * {@link #TEXT_DIRECTION_LTR}, 22902 * {@link #TEXT_DIRECTION_RTL}, 22903 * {@link #TEXT_DIRECTION_LOCALE}, 22904 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22905 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22906 * 22907 * @attr ref android.R.styleable#View_textDirection 22908 * 22909 * @hide 22910 */ 22911 @ViewDebug.ExportedProperty(category = "text", mapping = { 22912 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22913 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22914 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22915 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22916 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22917 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22918 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22919 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22920 }) 22921 public int getRawTextDirection() { 22922 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 22923 } 22924 22925 /** 22926 * Set the text direction. 22927 * 22928 * @param textDirection the direction to set. Should be one of: 22929 * 22930 * {@link #TEXT_DIRECTION_INHERIT}, 22931 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22932 * {@link #TEXT_DIRECTION_ANY_RTL}, 22933 * {@link #TEXT_DIRECTION_LTR}, 22934 * {@link #TEXT_DIRECTION_RTL}, 22935 * {@link #TEXT_DIRECTION_LOCALE} 22936 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22937 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 22938 * 22939 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 22940 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 22941 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 22942 * 22943 * @attr ref android.R.styleable#View_textDirection 22944 */ 22945 public void setTextDirection(int textDirection) { 22946 if (getRawTextDirection() != textDirection) { 22947 // Reset the current text direction and the resolved one 22948 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 22949 resetResolvedTextDirection(); 22950 // Set the new text direction 22951 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 22952 // Do resolution 22953 resolveTextDirection(); 22954 // Notify change 22955 onRtlPropertiesChanged(getLayoutDirection()); 22956 // Refresh 22957 requestLayout(); 22958 invalidate(true); 22959 } 22960 } 22961 22962 /** 22963 * Return the resolved text direction. 22964 * 22965 * @return the resolved text direction. Returns one of: 22966 * 22967 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22968 * {@link #TEXT_DIRECTION_ANY_RTL}, 22969 * {@link #TEXT_DIRECTION_LTR}, 22970 * {@link #TEXT_DIRECTION_RTL}, 22971 * {@link #TEXT_DIRECTION_LOCALE}, 22972 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22973 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22974 * 22975 * @attr ref android.R.styleable#View_textDirection 22976 */ 22977 @ViewDebug.ExportedProperty(category = "text", mapping = { 22978 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22979 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22980 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22981 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22982 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22983 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22984 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22985 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22986 }) 22987 public int getTextDirection() { 22988 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 22989 } 22990 22991 /** 22992 * Resolve the text direction. 22993 * 22994 * @return true if resolution has been done, false otherwise. 22995 * 22996 * @hide 22997 */ 22998 public boolean resolveTextDirection() { 22999 // Reset any previous text direction resolution 23000 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23001 23002 if (hasRtlSupport()) { 23003 // Set resolved text direction flag depending on text direction flag 23004 final int textDirection = getRawTextDirection(); 23005 switch(textDirection) { 23006 case TEXT_DIRECTION_INHERIT: 23007 if (!canResolveTextDirection()) { 23008 // We cannot do the resolution if there is no parent, so use the default one 23009 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23010 // Resolution will need to happen again later 23011 return false; 23012 } 23013 23014 // Parent has not yet resolved, so we still return the default 23015 try { 23016 if (!mParent.isTextDirectionResolved()) { 23017 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23018 // Resolution will need to happen again later 23019 return false; 23020 } 23021 } catch (AbstractMethodError e) { 23022 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23023 " does not fully implement ViewParent", e); 23024 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 23025 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23026 return true; 23027 } 23028 23029 // Set current resolved direction to the same value as the parent's one 23030 int parentResolvedDirection; 23031 try { 23032 parentResolvedDirection = mParent.getTextDirection(); 23033 } catch (AbstractMethodError e) { 23034 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23035 " does not fully implement ViewParent", e); 23036 parentResolvedDirection = TEXT_DIRECTION_LTR; 23037 } 23038 switch (parentResolvedDirection) { 23039 case TEXT_DIRECTION_FIRST_STRONG: 23040 case TEXT_DIRECTION_ANY_RTL: 23041 case TEXT_DIRECTION_LTR: 23042 case TEXT_DIRECTION_RTL: 23043 case TEXT_DIRECTION_LOCALE: 23044 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23045 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23046 mPrivateFlags2 |= 23047 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23048 break; 23049 default: 23050 // Default resolved direction is "first strong" heuristic 23051 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23052 } 23053 break; 23054 case TEXT_DIRECTION_FIRST_STRONG: 23055 case TEXT_DIRECTION_ANY_RTL: 23056 case TEXT_DIRECTION_LTR: 23057 case TEXT_DIRECTION_RTL: 23058 case TEXT_DIRECTION_LOCALE: 23059 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23060 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23061 // Resolved direction is the same as text direction 23062 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23063 break; 23064 default: 23065 // Default resolved direction is "first strong" heuristic 23066 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23067 } 23068 } else { 23069 // Default resolved direction is "first strong" heuristic 23070 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23071 } 23072 23073 // Set to resolved 23074 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 23075 return true; 23076 } 23077 23078 /** 23079 * Check if text direction resolution can be done. 23080 * 23081 * @return true if text direction resolution can be done otherwise return false. 23082 */ 23083 public boolean canResolveTextDirection() { 23084 switch (getRawTextDirection()) { 23085 case TEXT_DIRECTION_INHERIT: 23086 if (mParent != null) { 23087 try { 23088 return mParent.canResolveTextDirection(); 23089 } catch (AbstractMethodError e) { 23090 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23091 " does not fully implement ViewParent", e); 23092 } 23093 } 23094 return false; 23095 23096 default: 23097 return true; 23098 } 23099 } 23100 23101 /** 23102 * Reset resolved text direction. Text direction will be resolved during a call to 23103 * {@link #onMeasure(int, int)}. 23104 * 23105 * @hide 23106 */ 23107 public void resetResolvedTextDirection() { 23108 // Reset any previous text direction resolution 23109 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23110 // Set to default value 23111 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23112 } 23113 23114 /** 23115 * @return true if text direction is inherited. 23116 * 23117 * @hide 23118 */ 23119 public boolean isTextDirectionInherited() { 23120 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 23121 } 23122 23123 /** 23124 * @return true if text direction is resolved. 23125 */ 23126 public boolean isTextDirectionResolved() { 23127 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 23128 } 23129 23130 /** 23131 * Return the value specifying the text alignment or policy that was set with 23132 * {@link #setTextAlignment(int)}. 23133 * 23134 * @return the defined text alignment. It can be one of: 23135 * 23136 * {@link #TEXT_ALIGNMENT_INHERIT}, 23137 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23138 * {@link #TEXT_ALIGNMENT_CENTER}, 23139 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23140 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23141 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23142 * {@link #TEXT_ALIGNMENT_VIEW_END} 23143 * 23144 * @attr ref android.R.styleable#View_textAlignment 23145 * 23146 * @hide 23147 */ 23148 @ViewDebug.ExportedProperty(category = "text", mapping = { 23149 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23150 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23151 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23152 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23153 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23154 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23155 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23156 }) 23157 @TextAlignment 23158 public int getRawTextAlignment() { 23159 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 23160 } 23161 23162 /** 23163 * Set the text alignment. 23164 * 23165 * @param textAlignment The text alignment to set. Should be one of 23166 * 23167 * {@link #TEXT_ALIGNMENT_INHERIT}, 23168 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23169 * {@link #TEXT_ALIGNMENT_CENTER}, 23170 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23171 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23172 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23173 * {@link #TEXT_ALIGNMENT_VIEW_END} 23174 * 23175 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 23176 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 23177 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 23178 * 23179 * @attr ref android.R.styleable#View_textAlignment 23180 */ 23181 public void setTextAlignment(@TextAlignment int textAlignment) { 23182 if (textAlignment != getRawTextAlignment()) { 23183 // Reset the current and resolved text alignment 23184 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 23185 resetResolvedTextAlignment(); 23186 // Set the new text alignment 23187 mPrivateFlags2 |= 23188 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 23189 // Do resolution 23190 resolveTextAlignment(); 23191 // Notify change 23192 onRtlPropertiesChanged(getLayoutDirection()); 23193 // Refresh 23194 requestLayout(); 23195 invalidate(true); 23196 } 23197 } 23198 23199 /** 23200 * Return the resolved text alignment. 23201 * 23202 * @return the resolved text alignment. Returns one of: 23203 * 23204 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23205 * {@link #TEXT_ALIGNMENT_CENTER}, 23206 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23207 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23208 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23209 * {@link #TEXT_ALIGNMENT_VIEW_END} 23210 * 23211 * @attr ref android.R.styleable#View_textAlignment 23212 */ 23213 @ViewDebug.ExportedProperty(category = "text", mapping = { 23214 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23215 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23216 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23217 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23218 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23219 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23220 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23221 }) 23222 @TextAlignment 23223 public int getTextAlignment() { 23224 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 23225 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 23226 } 23227 23228 /** 23229 * Resolve the text alignment. 23230 * 23231 * @return true if resolution has been done, false otherwise. 23232 * 23233 * @hide 23234 */ 23235 public boolean resolveTextAlignment() { 23236 // Reset any previous text alignment resolution 23237 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 23238 23239 if (hasRtlSupport()) { 23240 // Set resolved text alignment flag depending on text alignment flag 23241 final int textAlignment = getRawTextAlignment(); 23242 switch (textAlignment) { 23243 case TEXT_ALIGNMENT_INHERIT: 23244 // Check if we can resolve the text alignment 23245 if (!canResolveTextAlignment()) { 23246 // We cannot do the resolution if there is no parent so use the default 23247 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23248 // Resolution will need to happen again later 23249 return false; 23250 } 23251 23252 // Parent has not yet resolved, so we still return the default 23253 try { 23254 if (!mParent.isTextAlignmentResolved()) { 23255 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23256 // Resolution will need to happen again later 23257 return false; 23258 } 23259 } catch (AbstractMethodError e) { 23260 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23261 " does not fully implement ViewParent", e); 23262 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 23263 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23264 return true; 23265 } 23266 23267 int parentResolvedTextAlignment; 23268 try { 23269 parentResolvedTextAlignment = mParent.getTextAlignment(); 23270 } catch (AbstractMethodError e) { 23271 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23272 " does not fully implement ViewParent", e); 23273 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 23274 } 23275 switch (parentResolvedTextAlignment) { 23276 case TEXT_ALIGNMENT_GRAVITY: 23277 case TEXT_ALIGNMENT_TEXT_START: 23278 case TEXT_ALIGNMENT_TEXT_END: 23279 case TEXT_ALIGNMENT_CENTER: 23280 case TEXT_ALIGNMENT_VIEW_START: 23281 case TEXT_ALIGNMENT_VIEW_END: 23282 // Resolved text alignment is the same as the parent resolved 23283 // text alignment 23284 mPrivateFlags2 |= 23285 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 23286 break; 23287 default: 23288 // Use default resolved text alignment 23289 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23290 } 23291 break; 23292 case TEXT_ALIGNMENT_GRAVITY: 23293 case TEXT_ALIGNMENT_TEXT_START: 23294 case TEXT_ALIGNMENT_TEXT_END: 23295 case TEXT_ALIGNMENT_CENTER: 23296 case TEXT_ALIGNMENT_VIEW_START: 23297 case TEXT_ALIGNMENT_VIEW_END: 23298 // Resolved text alignment is the same as text alignment 23299 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 23300 break; 23301 default: 23302 // Use default resolved text alignment 23303 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23304 } 23305 } else { 23306 // Use default resolved text alignment 23307 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23308 } 23309 23310 // Set the resolved 23311 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 23312 return true; 23313 } 23314 23315 /** 23316 * Check if text alignment resolution can be done. 23317 * 23318 * @return true if text alignment resolution can be done otherwise return false. 23319 */ 23320 public boolean canResolveTextAlignment() { 23321 switch (getRawTextAlignment()) { 23322 case TEXT_DIRECTION_INHERIT: 23323 if (mParent != null) { 23324 try { 23325 return mParent.canResolveTextAlignment(); 23326 } catch (AbstractMethodError e) { 23327 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23328 " does not fully implement ViewParent", e); 23329 } 23330 } 23331 return false; 23332 23333 default: 23334 return true; 23335 } 23336 } 23337 23338 /** 23339 * Reset resolved text alignment. Text alignment will be resolved during a call to 23340 * {@link #onMeasure(int, int)}. 23341 * 23342 * @hide 23343 */ 23344 public void resetResolvedTextAlignment() { 23345 // Reset any previous text alignment resolution 23346 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 23347 // Set to default 23348 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23349 } 23350 23351 /** 23352 * @return true if text alignment is inherited. 23353 * 23354 * @hide 23355 */ 23356 public boolean isTextAlignmentInherited() { 23357 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 23358 } 23359 23360 /** 23361 * @return true if text alignment is resolved. 23362 */ 23363 public boolean isTextAlignmentResolved() { 23364 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 23365 } 23366 23367 /** 23368 * Generate a value suitable for use in {@link #setId(int)}. 23369 * This value will not collide with ID values generated at build time by aapt for R.id. 23370 * 23371 * @return a generated ID value 23372 */ 23373 public static int generateViewId() { 23374 for (;;) { 23375 final int result = sNextGeneratedId.get(); 23376 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 23377 int newValue = result + 1; 23378 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 23379 if (sNextGeneratedId.compareAndSet(result, newValue)) { 23380 return result; 23381 } 23382 } 23383 } 23384 23385 private static boolean isViewIdGenerated(int id) { 23386 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 23387 } 23388 23389 /** 23390 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 23391 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 23392 * a normal View or a ViewGroup with 23393 * {@link android.view.ViewGroup#isTransitionGroup()} true. 23394 * @hide 23395 */ 23396 public void captureTransitioningViews(List<View> transitioningViews) { 23397 if (getVisibility() == View.VISIBLE) { 23398 transitioningViews.add(this); 23399 } 23400 } 23401 23402 /** 23403 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 23404 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 23405 * @hide 23406 */ 23407 public void findNamedViews(Map<String, View> namedElements) { 23408 if (getVisibility() == VISIBLE || mGhostView != null) { 23409 String transitionName = getTransitionName(); 23410 if (transitionName != null) { 23411 namedElements.put(transitionName, this); 23412 } 23413 } 23414 } 23415 23416 /** 23417 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 23418 * The default implementation does not care the location or event types, but some subclasses 23419 * may use it (such as WebViews). 23420 * @param event The MotionEvent from a mouse 23421 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 23422 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 23423 * @see PointerIcon 23424 */ 23425 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 23426 final float x = event.getX(pointerIndex); 23427 final float y = event.getY(pointerIndex); 23428 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 23429 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 23430 } 23431 return mPointerIcon; 23432 } 23433 23434 /** 23435 * Set the pointer icon for the current view. 23436 * Passing {@code null} will restore the pointer icon to its default value. 23437 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 23438 */ 23439 public void setPointerIcon(PointerIcon pointerIcon) { 23440 mPointerIcon = pointerIcon; 23441 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 23442 return; 23443 } 23444 try { 23445 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 23446 } catch (RemoteException e) { 23447 } 23448 } 23449 23450 /** 23451 * Gets the pointer icon for the current view. 23452 */ 23453 public PointerIcon getPointerIcon() { 23454 return mPointerIcon; 23455 } 23456 23457 /** 23458 * Checks pointer capture status. 23459 * 23460 * @return true if the view has pointer capture. 23461 * @see #requestPointerCapture() 23462 * @see #hasPointerCapture() 23463 */ 23464 public boolean hasPointerCapture() { 23465 final ViewRootImpl viewRootImpl = getViewRootImpl(); 23466 if (viewRootImpl == null) { 23467 return false; 23468 } 23469 return viewRootImpl.hasPointerCapture(); 23470 } 23471 23472 /** 23473 * Requests pointer capture mode. 23474 * <p> 23475 * When the window has pointer capture, the mouse pointer icon will disappear and will not 23476 * change its position. Further mouse will be dispatched with the source 23477 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 23478 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 23479 * (touchscreens, or stylus) will not be affected. 23480 * <p> 23481 * If the window already has pointer capture, this call does nothing. 23482 * <p> 23483 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 23484 * automatically when the window loses focus. 23485 * 23486 * @see #releasePointerCapture() 23487 * @see #hasPointerCapture() 23488 */ 23489 public void requestPointerCapture() { 23490 final ViewRootImpl viewRootImpl = getViewRootImpl(); 23491 if (viewRootImpl != null) { 23492 viewRootImpl.requestPointerCapture(true); 23493 } 23494 } 23495 23496 23497 /** 23498 * Releases the pointer capture. 23499 * <p> 23500 * If the window does not have pointer capture, this call will do nothing. 23501 * @see #requestPointerCapture() 23502 * @see #hasPointerCapture() 23503 */ 23504 public void releasePointerCapture() { 23505 final ViewRootImpl viewRootImpl = getViewRootImpl(); 23506 if (viewRootImpl != null) { 23507 viewRootImpl.requestPointerCapture(false); 23508 } 23509 } 23510 23511 /** 23512 * Called when the window has just acquired or lost pointer capture. 23513 * 23514 * @param hasCapture True if the view now has pointerCapture, false otherwise. 23515 */ 23516 @CallSuper 23517 public void onPointerCaptureChange(boolean hasCapture) { 23518 } 23519 23520 /** 23521 * @see #onPointerCaptureChange 23522 */ 23523 public void dispatchPointerCaptureChanged(boolean hasCapture) { 23524 onPointerCaptureChange(hasCapture); 23525 } 23526 23527 /** 23528 * Implement this method to handle captured pointer events 23529 * 23530 * @param event The captured pointer event. 23531 * @return True if the event was handled, false otherwise. 23532 * @see #requestPointerCapture() 23533 */ 23534 public boolean onCapturedPointerEvent(MotionEvent event) { 23535 return false; 23536 } 23537 23538 /** 23539 * Interface definition for a callback to be invoked when a captured pointer event 23540 * is being dispatched this view. The callback will be invoked before the event is 23541 * given to the view. 23542 */ 23543 public interface OnCapturedPointerListener { 23544 /** 23545 * Called when a captured pointer event is dispatched to a view. 23546 * @param view The view this event has been dispatched to. 23547 * @param event The captured event. 23548 * @return True if the listener has consumed the event, false otherwise. 23549 */ 23550 boolean onCapturedPointer(View view, MotionEvent event); 23551 } 23552 23553 /** 23554 * Set a listener to receive callbacks when the pointer capture state of a view changes. 23555 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 23556 */ 23557 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 23558 getListenerInfo().mOnCapturedPointerListener = l; 23559 } 23560 23561 // Properties 23562 // 23563 /** 23564 * A Property wrapper around the <code>alpha</code> functionality handled by the 23565 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 23566 */ 23567 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 23568 @Override 23569 public void setValue(View object, float value) { 23570 object.setAlpha(value); 23571 } 23572 23573 @Override 23574 public Float get(View object) { 23575 return object.getAlpha(); 23576 } 23577 }; 23578 23579 /** 23580 * A Property wrapper around the <code>translationX</code> functionality handled by the 23581 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 23582 */ 23583 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 23584 @Override 23585 public void setValue(View object, float value) { 23586 object.setTranslationX(value); 23587 } 23588 23589 @Override 23590 public Float get(View object) { 23591 return object.getTranslationX(); 23592 } 23593 }; 23594 23595 /** 23596 * A Property wrapper around the <code>translationY</code> functionality handled by the 23597 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 23598 */ 23599 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 23600 @Override 23601 public void setValue(View object, float value) { 23602 object.setTranslationY(value); 23603 } 23604 23605 @Override 23606 public Float get(View object) { 23607 return object.getTranslationY(); 23608 } 23609 }; 23610 23611 /** 23612 * A Property wrapper around the <code>translationZ</code> functionality handled by the 23613 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 23614 */ 23615 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 23616 @Override 23617 public void setValue(View object, float value) { 23618 object.setTranslationZ(value); 23619 } 23620 23621 @Override 23622 public Float get(View object) { 23623 return object.getTranslationZ(); 23624 } 23625 }; 23626 23627 /** 23628 * A Property wrapper around the <code>x</code> functionality handled by the 23629 * {@link View#setX(float)} and {@link View#getX()} methods. 23630 */ 23631 public static final Property<View, Float> X = new FloatProperty<View>("x") { 23632 @Override 23633 public void setValue(View object, float value) { 23634 object.setX(value); 23635 } 23636 23637 @Override 23638 public Float get(View object) { 23639 return object.getX(); 23640 } 23641 }; 23642 23643 /** 23644 * A Property wrapper around the <code>y</code> functionality handled by the 23645 * {@link View#setY(float)} and {@link View#getY()} methods. 23646 */ 23647 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 23648 @Override 23649 public void setValue(View object, float value) { 23650 object.setY(value); 23651 } 23652 23653 @Override 23654 public Float get(View object) { 23655 return object.getY(); 23656 } 23657 }; 23658 23659 /** 23660 * A Property wrapper around the <code>z</code> functionality handled by the 23661 * {@link View#setZ(float)} and {@link View#getZ()} methods. 23662 */ 23663 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 23664 @Override 23665 public void setValue(View object, float value) { 23666 object.setZ(value); 23667 } 23668 23669 @Override 23670 public Float get(View object) { 23671 return object.getZ(); 23672 } 23673 }; 23674 23675 /** 23676 * A Property wrapper around the <code>rotation</code> functionality handled by the 23677 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 23678 */ 23679 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 23680 @Override 23681 public void setValue(View object, float value) { 23682 object.setRotation(value); 23683 } 23684 23685 @Override 23686 public Float get(View object) { 23687 return object.getRotation(); 23688 } 23689 }; 23690 23691 /** 23692 * A Property wrapper around the <code>rotationX</code> functionality handled by the 23693 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 23694 */ 23695 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 23696 @Override 23697 public void setValue(View object, float value) { 23698 object.setRotationX(value); 23699 } 23700 23701 @Override 23702 public Float get(View object) { 23703 return object.getRotationX(); 23704 } 23705 }; 23706 23707 /** 23708 * A Property wrapper around the <code>rotationY</code> functionality handled by the 23709 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 23710 */ 23711 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 23712 @Override 23713 public void setValue(View object, float value) { 23714 object.setRotationY(value); 23715 } 23716 23717 @Override 23718 public Float get(View object) { 23719 return object.getRotationY(); 23720 } 23721 }; 23722 23723 /** 23724 * A Property wrapper around the <code>scaleX</code> functionality handled by the 23725 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 23726 */ 23727 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 23728 @Override 23729 public void setValue(View object, float value) { 23730 object.setScaleX(value); 23731 } 23732 23733 @Override 23734 public Float get(View object) { 23735 return object.getScaleX(); 23736 } 23737 }; 23738 23739 /** 23740 * A Property wrapper around the <code>scaleY</code> functionality handled by the 23741 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 23742 */ 23743 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 23744 @Override 23745 public void setValue(View object, float value) { 23746 object.setScaleY(value); 23747 } 23748 23749 @Override 23750 public Float get(View object) { 23751 return object.getScaleY(); 23752 } 23753 }; 23754 23755 /** 23756 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 23757 * Each MeasureSpec represents a requirement for either the width or the height. 23758 * A MeasureSpec is comprised of a size and a mode. There are three possible 23759 * modes: 23760 * <dl> 23761 * <dt>UNSPECIFIED</dt> 23762 * <dd> 23763 * The parent has not imposed any constraint on the child. It can be whatever size 23764 * it wants. 23765 * </dd> 23766 * 23767 * <dt>EXACTLY</dt> 23768 * <dd> 23769 * The parent has determined an exact size for the child. The child is going to be 23770 * given those bounds regardless of how big it wants to be. 23771 * </dd> 23772 * 23773 * <dt>AT_MOST</dt> 23774 * <dd> 23775 * The child can be as large as it wants up to the specified size. 23776 * </dd> 23777 * </dl> 23778 * 23779 * MeasureSpecs are implemented as ints to reduce object allocation. This class 23780 * is provided to pack and unpack the <size, mode> tuple into the int. 23781 */ 23782 public static class MeasureSpec { 23783 private static final int MODE_SHIFT = 30; 23784 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 23785 23786 /** @hide */ 23787 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 23788 @Retention(RetentionPolicy.SOURCE) 23789 public @interface MeasureSpecMode {} 23790 23791 /** 23792 * Measure specification mode: The parent has not imposed any constraint 23793 * on the child. It can be whatever size it wants. 23794 */ 23795 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 23796 23797 /** 23798 * Measure specification mode: The parent has determined an exact size 23799 * for the child. The child is going to be given those bounds regardless 23800 * of how big it wants to be. 23801 */ 23802 public static final int EXACTLY = 1 << MODE_SHIFT; 23803 23804 /** 23805 * Measure specification mode: The child can be as large as it wants up 23806 * to the specified size. 23807 */ 23808 public static final int AT_MOST = 2 << MODE_SHIFT; 23809 23810 /** 23811 * Creates a measure specification based on the supplied size and mode. 23812 * 23813 * The mode must always be one of the following: 23814 * <ul> 23815 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 23816 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 23817 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 23818 * </ul> 23819 * 23820 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 23821 * implementation was such that the order of arguments did not matter 23822 * and overflow in either value could impact the resulting MeasureSpec. 23823 * {@link android.widget.RelativeLayout} was affected by this bug. 23824 * Apps targeting API levels greater than 17 will get the fixed, more strict 23825 * behavior.</p> 23826 * 23827 * @param size the size of the measure specification 23828 * @param mode the mode of the measure specification 23829 * @return the measure specification based on size and mode 23830 */ 23831 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 23832 @MeasureSpecMode int mode) { 23833 if (sUseBrokenMakeMeasureSpec) { 23834 return size + mode; 23835 } else { 23836 return (size & ~MODE_MASK) | (mode & MODE_MASK); 23837 } 23838 } 23839 23840 /** 23841 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 23842 * will automatically get a size of 0. Older apps expect this. 23843 * 23844 * @hide internal use only for compatibility with system widgets and older apps 23845 */ 23846 public static int makeSafeMeasureSpec(int size, int mode) { 23847 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 23848 return 0; 23849 } 23850 return makeMeasureSpec(size, mode); 23851 } 23852 23853 /** 23854 * Extracts the mode from the supplied measure specification. 23855 * 23856 * @param measureSpec the measure specification to extract the mode from 23857 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 23858 * {@link android.view.View.MeasureSpec#AT_MOST} or 23859 * {@link android.view.View.MeasureSpec#EXACTLY} 23860 */ 23861 @MeasureSpecMode 23862 public static int getMode(int measureSpec) { 23863 //noinspection ResourceType 23864 return (measureSpec & MODE_MASK); 23865 } 23866 23867 /** 23868 * Extracts the size from the supplied measure specification. 23869 * 23870 * @param measureSpec the measure specification to extract the size from 23871 * @return the size in pixels defined in the supplied measure specification 23872 */ 23873 public static int getSize(int measureSpec) { 23874 return (measureSpec & ~MODE_MASK); 23875 } 23876 23877 static int adjust(int measureSpec, int delta) { 23878 final int mode = getMode(measureSpec); 23879 int size = getSize(measureSpec); 23880 if (mode == UNSPECIFIED) { 23881 // No need to adjust size for UNSPECIFIED mode. 23882 return makeMeasureSpec(size, UNSPECIFIED); 23883 } 23884 size += delta; 23885 if (size < 0) { 23886 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 23887 ") spec: " + toString(measureSpec) + " delta: " + delta); 23888 size = 0; 23889 } 23890 return makeMeasureSpec(size, mode); 23891 } 23892 23893 /** 23894 * Returns a String representation of the specified measure 23895 * specification. 23896 * 23897 * @param measureSpec the measure specification to convert to a String 23898 * @return a String with the following format: "MeasureSpec: MODE SIZE" 23899 */ 23900 public static String toString(int measureSpec) { 23901 int mode = getMode(measureSpec); 23902 int size = getSize(measureSpec); 23903 23904 StringBuilder sb = new StringBuilder("MeasureSpec: "); 23905 23906 if (mode == UNSPECIFIED) 23907 sb.append("UNSPECIFIED "); 23908 else if (mode == EXACTLY) 23909 sb.append("EXACTLY "); 23910 else if (mode == AT_MOST) 23911 sb.append("AT_MOST "); 23912 else 23913 sb.append(mode).append(" "); 23914 23915 sb.append(size); 23916 return sb.toString(); 23917 } 23918 } 23919 23920 private final class CheckForLongPress implements Runnable { 23921 private int mOriginalWindowAttachCount; 23922 private float mX; 23923 private float mY; 23924 private boolean mOriginalPressedState; 23925 23926 @Override 23927 public void run() { 23928 if ((mOriginalPressedState == isPressed()) && (mParent != null) 23929 && mOriginalWindowAttachCount == mWindowAttachCount) { 23930 if (performLongClick(mX, mY)) { 23931 mHasPerformedLongPress = true; 23932 } 23933 } 23934 } 23935 23936 public void setAnchor(float x, float y) { 23937 mX = x; 23938 mY = y; 23939 } 23940 23941 public void rememberWindowAttachCount() { 23942 mOriginalWindowAttachCount = mWindowAttachCount; 23943 } 23944 23945 public void rememberPressedState() { 23946 mOriginalPressedState = isPressed(); 23947 } 23948 } 23949 23950 private final class CheckForTap implements Runnable { 23951 public float x; 23952 public float y; 23953 23954 @Override 23955 public void run() { 23956 mPrivateFlags &= ~PFLAG_PREPRESSED; 23957 setPressed(true, x, y); 23958 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 23959 } 23960 } 23961 23962 private final class PerformClick implements Runnable { 23963 @Override 23964 public void run() { 23965 performClick(); 23966 } 23967 } 23968 23969 /** 23970 * This method returns a ViewPropertyAnimator object, which can be used to animate 23971 * specific properties on this View. 23972 * 23973 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 23974 */ 23975 public ViewPropertyAnimator animate() { 23976 if (mAnimator == null) { 23977 mAnimator = new ViewPropertyAnimator(this); 23978 } 23979 return mAnimator; 23980 } 23981 23982 /** 23983 * Sets the name of the View to be used to identify Views in Transitions. 23984 * Names should be unique in the View hierarchy. 23985 * 23986 * @param transitionName The name of the View to uniquely identify it for Transitions. 23987 */ 23988 public final void setTransitionName(String transitionName) { 23989 mTransitionName = transitionName; 23990 } 23991 23992 /** 23993 * Returns the name of the View to be used to identify Views in Transitions. 23994 * Names should be unique in the View hierarchy. 23995 * 23996 * <p>This returns null if the View has not been given a name.</p> 23997 * 23998 * @return The name used of the View to be used to identify Views in Transitions or null 23999 * if no name has been given. 24000 */ 24001 @ViewDebug.ExportedProperty 24002 public String getTransitionName() { 24003 return mTransitionName; 24004 } 24005 24006 /** 24007 * @hide 24008 */ 24009 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 24010 // Do nothing. 24011 } 24012 24013 /** 24014 * Interface definition for a callback to be invoked when a hardware key event is 24015 * dispatched to this view. The callback will be invoked before the key event is 24016 * given to the view. This is only useful for hardware keyboards; a software input 24017 * method has no obligation to trigger this listener. 24018 */ 24019 public interface OnKeyListener { 24020 /** 24021 * Called when a hardware key is dispatched to a view. This allows listeners to 24022 * get a chance to respond before the target view. 24023 * <p>Key presses in software keyboards will generally NOT trigger this method, 24024 * although some may elect to do so in some situations. Do not assume a 24025 * software input method has to be key-based; even if it is, it may use key presses 24026 * in a different way than you expect, so there is no way to reliably catch soft 24027 * input key presses. 24028 * 24029 * @param v The view the key has been dispatched to. 24030 * @param keyCode The code for the physical key that was pressed 24031 * @param event The KeyEvent object containing full information about 24032 * the event. 24033 * @return True if the listener has consumed the event, false otherwise. 24034 */ 24035 boolean onKey(View v, int keyCode, KeyEvent event); 24036 } 24037 24038 /** 24039 * Interface definition for a callback to be invoked when a touch event is 24040 * dispatched to this view. The callback will be invoked before the touch 24041 * event is given to the view. 24042 */ 24043 public interface OnTouchListener { 24044 /** 24045 * Called when a touch event is dispatched to a view. This allows listeners to 24046 * get a chance to respond before the target view. 24047 * 24048 * @param v The view the touch event has been dispatched to. 24049 * @param event The MotionEvent object containing full information about 24050 * the event. 24051 * @return True if the listener has consumed the event, false otherwise. 24052 */ 24053 boolean onTouch(View v, MotionEvent event); 24054 } 24055 24056 /** 24057 * Interface definition for a callback to be invoked when a hover event is 24058 * dispatched to this view. The callback will be invoked before the hover 24059 * event is given to the view. 24060 */ 24061 public interface OnHoverListener { 24062 /** 24063 * Called when a hover event is dispatched to a view. This allows listeners to 24064 * get a chance to respond before the target view. 24065 * 24066 * @param v The view the hover event has been dispatched to. 24067 * @param event The MotionEvent object containing full information about 24068 * the event. 24069 * @return True if the listener has consumed the event, false otherwise. 24070 */ 24071 boolean onHover(View v, MotionEvent event); 24072 } 24073 24074 /** 24075 * Interface definition for a callback to be invoked when a generic motion event is 24076 * dispatched to this view. The callback will be invoked before the generic motion 24077 * event is given to the view. 24078 */ 24079 public interface OnGenericMotionListener { 24080 /** 24081 * Called when a generic motion event is dispatched to a view. This allows listeners to 24082 * get a chance to respond before the target view. 24083 * 24084 * @param v The view the generic motion event has been dispatched to. 24085 * @param event The MotionEvent object containing full information about 24086 * the event. 24087 * @return True if the listener has consumed the event, false otherwise. 24088 */ 24089 boolean onGenericMotion(View v, MotionEvent event); 24090 } 24091 24092 /** 24093 * Interface definition for a callback to be invoked when a view has been clicked and held. 24094 */ 24095 public interface OnLongClickListener { 24096 /** 24097 * Called when a view has been clicked and held. 24098 * 24099 * @param v The view that was clicked and held. 24100 * 24101 * @return true if the callback consumed the long click, false otherwise. 24102 */ 24103 boolean onLongClick(View v); 24104 } 24105 24106 /** 24107 * Interface definition for a callback to be invoked when a drag is being dispatched 24108 * to this view. The callback will be invoked before the hosting view's own 24109 * onDrag(event) method. If the listener wants to fall back to the hosting view's 24110 * onDrag(event) behavior, it should return 'false' from this callback. 24111 * 24112 * <div class="special reference"> 24113 * <h3>Developer Guides</h3> 24114 * <p>For a guide to implementing drag and drop features, read the 24115 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 24116 * </div> 24117 */ 24118 public interface OnDragListener { 24119 /** 24120 * Called when a drag event is dispatched to a view. This allows listeners 24121 * to get a chance to override base View behavior. 24122 * 24123 * @param v The View that received the drag event. 24124 * @param event The {@link android.view.DragEvent} object for the drag event. 24125 * @return {@code true} if the drag event was handled successfully, or {@code false} 24126 * if the drag event was not handled. Note that {@code false} will trigger the View 24127 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 24128 */ 24129 boolean onDrag(View v, DragEvent event); 24130 } 24131 24132 /** 24133 * Interface definition for a callback to be invoked when the focus state of 24134 * a view changed. 24135 */ 24136 public interface OnFocusChangeListener { 24137 /** 24138 * Called when the focus state of a view has changed. 24139 * 24140 * @param v The view whose state has changed. 24141 * @param hasFocus The new focus state of v. 24142 */ 24143 void onFocusChange(View v, boolean hasFocus); 24144 } 24145 24146 /** 24147 * Interface definition for a callback to be invoked when a view is clicked. 24148 */ 24149 public interface OnClickListener { 24150 /** 24151 * Called when a view has been clicked. 24152 * 24153 * @param v The view that was clicked. 24154 */ 24155 void onClick(View v); 24156 } 24157 24158 /** 24159 * Interface definition for a callback to be invoked when a view is context clicked. 24160 */ 24161 public interface OnContextClickListener { 24162 /** 24163 * Called when a view is context clicked. 24164 * 24165 * @param v The view that has been context clicked. 24166 * @return true if the callback consumed the context click, false otherwise. 24167 */ 24168 boolean onContextClick(View v); 24169 } 24170 24171 /** 24172 * Interface definition for a callback to be invoked when the context menu 24173 * for this view is being built. 24174 */ 24175 public interface OnCreateContextMenuListener { 24176 /** 24177 * Called when the context menu for this view is being built. It is not 24178 * safe to hold onto the menu after this method returns. 24179 * 24180 * @param menu The context menu that is being built 24181 * @param v The view for which the context menu is being built 24182 * @param menuInfo Extra information about the item for which the 24183 * context menu should be shown. This information will vary 24184 * depending on the class of v. 24185 */ 24186 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 24187 } 24188 24189 /** 24190 * Interface definition for a callback to be invoked when the status bar changes 24191 * visibility. This reports <strong>global</strong> changes to the system UI 24192 * state, not what the application is requesting. 24193 * 24194 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 24195 */ 24196 public interface OnSystemUiVisibilityChangeListener { 24197 /** 24198 * Called when the status bar changes visibility because of a call to 24199 * {@link View#setSystemUiVisibility(int)}. 24200 * 24201 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 24202 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 24203 * This tells you the <strong>global</strong> state of these UI visibility 24204 * flags, not what your app is currently applying. 24205 */ 24206 public void onSystemUiVisibilityChange(int visibility); 24207 } 24208 24209 /** 24210 * Interface definition for a callback to be invoked when this view is attached 24211 * or detached from its window. 24212 */ 24213 public interface OnAttachStateChangeListener { 24214 /** 24215 * Called when the view is attached to a window. 24216 * @param v The view that was attached 24217 */ 24218 public void onViewAttachedToWindow(View v); 24219 /** 24220 * Called when the view is detached from a window. 24221 * @param v The view that was detached 24222 */ 24223 public void onViewDetachedFromWindow(View v); 24224 } 24225 24226 /** 24227 * Listener for applying window insets on a view in a custom way. 24228 * 24229 * <p>Apps may choose to implement this interface if they want to apply custom policy 24230 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 24231 * is set, its 24232 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 24233 * method will be called instead of the View's own 24234 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 24235 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 24236 * the View's normal behavior as part of its own.</p> 24237 */ 24238 public interface OnApplyWindowInsetsListener { 24239 /** 24240 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 24241 * on a View, this listener method will be called instead of the view's own 24242 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 24243 * 24244 * @param v The view applying window insets 24245 * @param insets The insets to apply 24246 * @return The insets supplied, minus any insets that were consumed 24247 */ 24248 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 24249 } 24250 24251 private final class UnsetPressedState implements Runnable { 24252 @Override 24253 public void run() { 24254 setPressed(false); 24255 } 24256 } 24257 24258 /** 24259 * Base class for derived classes that want to save and restore their own 24260 * state in {@link android.view.View#onSaveInstanceState()}. 24261 */ 24262 public static class BaseSavedState extends AbsSavedState { 24263 String mStartActivityRequestWhoSaved; 24264 24265 /** 24266 * Constructor used when reading from a parcel. Reads the state of the superclass. 24267 * 24268 * @param source parcel to read from 24269 */ 24270 public BaseSavedState(Parcel source) { 24271 this(source, null); 24272 } 24273 24274 /** 24275 * Constructor used when reading from a parcel using a given class loader. 24276 * Reads the state of the superclass. 24277 * 24278 * @param source parcel to read from 24279 * @param loader ClassLoader to use for reading 24280 */ 24281 public BaseSavedState(Parcel source, ClassLoader loader) { 24282 super(source, loader); 24283 mStartActivityRequestWhoSaved = source.readString(); 24284 } 24285 24286 /** 24287 * Constructor called by derived classes when creating their SavedState objects 24288 * 24289 * @param superState The state of the superclass of this view 24290 */ 24291 public BaseSavedState(Parcelable superState) { 24292 super(superState); 24293 } 24294 24295 @Override 24296 public void writeToParcel(Parcel out, int flags) { 24297 super.writeToParcel(out, flags); 24298 out.writeString(mStartActivityRequestWhoSaved); 24299 } 24300 24301 public static final Parcelable.Creator<BaseSavedState> CREATOR 24302 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 24303 @Override 24304 public BaseSavedState createFromParcel(Parcel in) { 24305 return new BaseSavedState(in); 24306 } 24307 24308 @Override 24309 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 24310 return new BaseSavedState(in, loader); 24311 } 24312 24313 @Override 24314 public BaseSavedState[] newArray(int size) { 24315 return new BaseSavedState[size]; 24316 } 24317 }; 24318 } 24319 24320 /** 24321 * A set of information given to a view when it is attached to its parent 24322 * window. 24323 */ 24324 final static class AttachInfo { 24325 interface Callbacks { 24326 void playSoundEffect(int effectId); 24327 boolean performHapticFeedback(int effectId, boolean always); 24328 } 24329 24330 /** 24331 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 24332 * to a Handler. This class contains the target (View) to invalidate and 24333 * the coordinates of the dirty rectangle. 24334 * 24335 * For performance purposes, this class also implements a pool of up to 24336 * POOL_LIMIT objects that get reused. This reduces memory allocations 24337 * whenever possible. 24338 */ 24339 static class InvalidateInfo { 24340 private static final int POOL_LIMIT = 10; 24341 24342 private static final SynchronizedPool<InvalidateInfo> sPool = 24343 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 24344 24345 View target; 24346 24347 int left; 24348 int top; 24349 int right; 24350 int bottom; 24351 24352 public static InvalidateInfo obtain() { 24353 InvalidateInfo instance = sPool.acquire(); 24354 return (instance != null) ? instance : new InvalidateInfo(); 24355 } 24356 24357 public void recycle() { 24358 target = null; 24359 sPool.release(this); 24360 } 24361 } 24362 24363 final IWindowSession mSession; 24364 24365 final IWindow mWindow; 24366 24367 final IBinder mWindowToken; 24368 24369 Display mDisplay; 24370 24371 final Callbacks mRootCallbacks; 24372 24373 IWindowId mIWindowId; 24374 WindowId mWindowId; 24375 24376 /** 24377 * The top view of the hierarchy. 24378 */ 24379 View mRootView; 24380 24381 IBinder mPanelParentWindowToken; 24382 24383 boolean mHardwareAccelerated; 24384 boolean mHardwareAccelerationRequested; 24385 ThreadedRenderer mThreadedRenderer; 24386 List<RenderNode> mPendingAnimatingRenderNodes; 24387 24388 /** 24389 * The state of the display to which the window is attached, as reported 24390 * by {@link Display#getState()}. Note that the display state constants 24391 * declared by {@link Display} do not exactly line up with the screen state 24392 * constants declared by {@link View} (there are more display states than 24393 * screen states). 24394 */ 24395 int mDisplayState = Display.STATE_UNKNOWN; 24396 24397 /** 24398 * Scale factor used by the compatibility mode 24399 */ 24400 float mApplicationScale; 24401 24402 /** 24403 * Indicates whether the application is in compatibility mode 24404 */ 24405 boolean mScalingRequired; 24406 24407 /** 24408 * Left position of this view's window 24409 */ 24410 int mWindowLeft; 24411 24412 /** 24413 * Top position of this view's window 24414 */ 24415 int mWindowTop; 24416 24417 /** 24418 * Indicates whether views need to use 32-bit drawing caches 24419 */ 24420 boolean mUse32BitDrawingCache; 24421 24422 /** 24423 * For windows that are full-screen but using insets to layout inside 24424 * of the screen areas, these are the current insets to appear inside 24425 * the overscan area of the display. 24426 */ 24427 final Rect mOverscanInsets = new Rect(); 24428 24429 /** 24430 * For windows that are full-screen but using insets to layout inside 24431 * of the screen decorations, these are the current insets for the 24432 * content of the window. 24433 */ 24434 final Rect mContentInsets = new Rect(); 24435 24436 /** 24437 * For windows that are full-screen but using insets to layout inside 24438 * of the screen decorations, these are the current insets for the 24439 * actual visible parts of the window. 24440 */ 24441 final Rect mVisibleInsets = new Rect(); 24442 24443 /** 24444 * For windows that are full-screen but using insets to layout inside 24445 * of the screen decorations, these are the current insets for the 24446 * stable system windows. 24447 */ 24448 final Rect mStableInsets = new Rect(); 24449 24450 /** 24451 * For windows that include areas that are not covered by real surface these are the outsets 24452 * for real surface. 24453 */ 24454 final Rect mOutsets = new Rect(); 24455 24456 /** 24457 * In multi-window we force show the navigation bar. Because we don't want that the surface 24458 * size changes in this mode, we instead have a flag whether the navigation bar size should 24459 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 24460 */ 24461 boolean mAlwaysConsumeNavBar; 24462 24463 /** 24464 * The internal insets given by this window. This value is 24465 * supplied by the client (through 24466 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 24467 * be given to the window manager when changed to be used in laying 24468 * out windows behind it. 24469 */ 24470 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 24471 = new ViewTreeObserver.InternalInsetsInfo(); 24472 24473 /** 24474 * Set to true when mGivenInternalInsets is non-empty. 24475 */ 24476 boolean mHasNonEmptyGivenInternalInsets; 24477 24478 /** 24479 * All views in the window's hierarchy that serve as scroll containers, 24480 * used to determine if the window can be resized or must be panned 24481 * to adjust for a soft input area. 24482 */ 24483 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 24484 24485 final KeyEvent.DispatcherState mKeyDispatchState 24486 = new KeyEvent.DispatcherState(); 24487 24488 /** 24489 * Indicates whether the view's window currently has the focus. 24490 */ 24491 boolean mHasWindowFocus; 24492 24493 /** 24494 * The current visibility of the window. 24495 */ 24496 int mWindowVisibility; 24497 24498 /** 24499 * Indicates the time at which drawing started to occur. 24500 */ 24501 long mDrawingTime; 24502 24503 /** 24504 * Indicates whether or not ignoring the DIRTY_MASK flags. 24505 */ 24506 boolean mIgnoreDirtyState; 24507 24508 /** 24509 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 24510 * to avoid clearing that flag prematurely. 24511 */ 24512 boolean mSetIgnoreDirtyState = false; 24513 24514 /** 24515 * Indicates whether the view's window is currently in touch mode. 24516 */ 24517 boolean mInTouchMode; 24518 24519 /** 24520 * Indicates whether the view has requested unbuffered input dispatching for the current 24521 * event stream. 24522 */ 24523 boolean mUnbufferedDispatchRequested; 24524 24525 /** 24526 * Indicates that ViewAncestor should trigger a global layout change 24527 * the next time it performs a traversal 24528 */ 24529 boolean mRecomputeGlobalAttributes; 24530 24531 /** 24532 * Always report new attributes at next traversal. 24533 */ 24534 boolean mForceReportNewAttributes; 24535 24536 /** 24537 * Set during a traveral if any views want to keep the screen on. 24538 */ 24539 boolean mKeepScreenOn; 24540 24541 /** 24542 * Set during a traveral if the light center needs to be updated. 24543 */ 24544 boolean mNeedsUpdateLightCenter; 24545 24546 /** 24547 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 24548 */ 24549 int mSystemUiVisibility; 24550 24551 /** 24552 * Hack to force certain system UI visibility flags to be cleared. 24553 */ 24554 int mDisabledSystemUiVisibility; 24555 24556 /** 24557 * Last global system UI visibility reported by the window manager. 24558 */ 24559 int mGlobalSystemUiVisibility = -1; 24560 24561 /** 24562 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 24563 * attached. 24564 */ 24565 boolean mHasSystemUiListeners; 24566 24567 /** 24568 * Set if the window has requested to extend into the overscan region 24569 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 24570 */ 24571 boolean mOverscanRequested; 24572 24573 /** 24574 * Set if the visibility of any views has changed. 24575 */ 24576 boolean mViewVisibilityChanged; 24577 24578 /** 24579 * Set to true if a view has been scrolled. 24580 */ 24581 boolean mViewScrollChanged; 24582 24583 /** 24584 * Set to true if high contrast mode enabled 24585 */ 24586 boolean mHighContrastText; 24587 24588 /** 24589 * Set to true if a pointer event is currently being handled. 24590 */ 24591 boolean mHandlingPointerEvent; 24592 24593 /** 24594 * Global to the view hierarchy used as a temporary for dealing with 24595 * x/y points in the transparent region computations. 24596 */ 24597 final int[] mTransparentLocation = new int[2]; 24598 24599 /** 24600 * Global to the view hierarchy used as a temporary for dealing with 24601 * x/y points in the ViewGroup.invalidateChild implementation. 24602 */ 24603 final int[] mInvalidateChildLocation = new int[2]; 24604 24605 /** 24606 * Global to the view hierarchy used as a temporary for dealing with 24607 * computing absolute on-screen location. 24608 */ 24609 final int[] mTmpLocation = new int[2]; 24610 24611 /** 24612 * Global to the view hierarchy used as a temporary for dealing with 24613 * x/y location when view is transformed. 24614 */ 24615 final float[] mTmpTransformLocation = new float[2]; 24616 24617 /** 24618 * The view tree observer used to dispatch global events like 24619 * layout, pre-draw, touch mode change, etc. 24620 */ 24621 final ViewTreeObserver mTreeObserver; 24622 24623 /** 24624 * A Canvas used by the view hierarchy to perform bitmap caching. 24625 */ 24626 Canvas mCanvas; 24627 24628 /** 24629 * The view root impl. 24630 */ 24631 final ViewRootImpl mViewRootImpl; 24632 24633 /** 24634 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 24635 * handler can be used to pump events in the UI events queue. 24636 */ 24637 final Handler mHandler; 24638 24639 /** 24640 * Temporary for use in computing invalidate rectangles while 24641 * calling up the hierarchy. 24642 */ 24643 final Rect mTmpInvalRect = new Rect(); 24644 24645 /** 24646 * Temporary for use in computing hit areas with transformed views 24647 */ 24648 final RectF mTmpTransformRect = new RectF(); 24649 24650 /** 24651 * Temporary for use in computing hit areas with transformed views 24652 */ 24653 final RectF mTmpTransformRect1 = new RectF(); 24654 24655 /** 24656 * Temporary list of rectanges. 24657 */ 24658 final List<RectF> mTmpRectList = new ArrayList<>(); 24659 24660 /** 24661 * Temporary for use in transforming invalidation rect 24662 */ 24663 final Matrix mTmpMatrix = new Matrix(); 24664 24665 /** 24666 * Temporary for use in transforming invalidation rect 24667 */ 24668 final Transformation mTmpTransformation = new Transformation(); 24669 24670 /** 24671 * Temporary for use in querying outlines from OutlineProviders 24672 */ 24673 final Outline mTmpOutline = new Outline(); 24674 24675 /** 24676 * Temporary list for use in collecting focusable descendents of a view. 24677 */ 24678 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 24679 24680 /** 24681 * The id of the window for accessibility purposes. 24682 */ 24683 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 24684 24685 /** 24686 * Flags related to accessibility processing. 24687 * 24688 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 24689 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 24690 */ 24691 int mAccessibilityFetchFlags; 24692 24693 /** 24694 * The drawable for highlighting accessibility focus. 24695 */ 24696 Drawable mAccessibilityFocusDrawable; 24697 24698 /** 24699 * Show where the margins, bounds and layout bounds are for each view. 24700 */ 24701 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 24702 24703 /** 24704 * Point used to compute visible regions. 24705 */ 24706 final Point mPoint = new Point(); 24707 24708 /** 24709 * Used to track which View originated a requestLayout() call, used when 24710 * requestLayout() is called during layout. 24711 */ 24712 View mViewRequestingLayout; 24713 24714 /** 24715 * Used to track views that need (at least) a partial relayout at their current size 24716 * during the next traversal. 24717 */ 24718 List<View> mPartialLayoutViews = new ArrayList<>(); 24719 24720 /** 24721 * Swapped with mPartialLayoutViews during layout to avoid concurrent 24722 * modification. Lazily assigned during ViewRootImpl layout. 24723 */ 24724 List<View> mEmptyPartialLayoutViews; 24725 24726 /** 24727 * Used to track the identity of the current drag operation. 24728 */ 24729 IBinder mDragToken; 24730 24731 /** 24732 * The drag shadow surface for the current drag operation. 24733 */ 24734 public Surface mDragSurface; 24735 24736 24737 /** 24738 * The view that currently has a tooltip displayed. 24739 */ 24740 View mTooltipHost; 24741 24742 /** 24743 * Creates a new set of attachment information with the specified 24744 * events handler and thread. 24745 * 24746 * @param handler the events handler the view must use 24747 */ 24748 AttachInfo(IWindowSession session, IWindow window, Display display, 24749 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 24750 Context context) { 24751 mSession = session; 24752 mWindow = window; 24753 mWindowToken = window.asBinder(); 24754 mDisplay = display; 24755 mViewRootImpl = viewRootImpl; 24756 mHandler = handler; 24757 mRootCallbacks = effectPlayer; 24758 mTreeObserver = new ViewTreeObserver(context); 24759 } 24760 } 24761 24762 /** 24763 * <p>ScrollabilityCache holds various fields used by a View when scrolling 24764 * is supported. This avoids keeping too many unused fields in most 24765 * instances of View.</p> 24766 */ 24767 private static class ScrollabilityCache implements Runnable { 24768 24769 /** 24770 * Scrollbars are not visible 24771 */ 24772 public static final int OFF = 0; 24773 24774 /** 24775 * Scrollbars are visible 24776 */ 24777 public static final int ON = 1; 24778 24779 /** 24780 * Scrollbars are fading away 24781 */ 24782 public static final int FADING = 2; 24783 24784 public boolean fadeScrollBars; 24785 24786 public int fadingEdgeLength; 24787 public int scrollBarDefaultDelayBeforeFade; 24788 public int scrollBarFadeDuration; 24789 24790 public int scrollBarSize; 24791 public int scrollBarMinTouchTarget; 24792 public ScrollBarDrawable scrollBar; 24793 public float[] interpolatorValues; 24794 public View host; 24795 24796 public final Paint paint; 24797 public final Matrix matrix; 24798 public Shader shader; 24799 24800 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 24801 24802 private static final float[] OPAQUE = { 255 }; 24803 private static final float[] TRANSPARENT = { 0.0f }; 24804 24805 /** 24806 * When fading should start. This time moves into the future every time 24807 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 24808 */ 24809 public long fadeStartTime; 24810 24811 24812 /** 24813 * The current state of the scrollbars: ON, OFF, or FADING 24814 */ 24815 public int state = OFF; 24816 24817 private int mLastColor; 24818 24819 public final Rect mScrollBarBounds = new Rect(); 24820 public final Rect mScrollBarTouchBounds = new Rect(); 24821 24822 public static final int NOT_DRAGGING = 0; 24823 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 24824 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 24825 public int mScrollBarDraggingState = NOT_DRAGGING; 24826 24827 public float mScrollBarDraggingPos = 0; 24828 24829 public ScrollabilityCache(ViewConfiguration configuration, View host) { 24830 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 24831 scrollBarSize = configuration.getScaledScrollBarSize(); 24832 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 24833 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 24834 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 24835 24836 paint = new Paint(); 24837 matrix = new Matrix(); 24838 // use use a height of 1, and then wack the matrix each time we 24839 // actually use it. 24840 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 24841 paint.setShader(shader); 24842 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 24843 24844 this.host = host; 24845 } 24846 24847 public void setFadeColor(int color) { 24848 if (color != mLastColor) { 24849 mLastColor = color; 24850 24851 if (color != 0) { 24852 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 24853 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 24854 paint.setShader(shader); 24855 // Restore the default transfer mode (src_over) 24856 paint.setXfermode(null); 24857 } else { 24858 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 24859 paint.setShader(shader); 24860 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 24861 } 24862 } 24863 } 24864 24865 public void run() { 24866 long now = AnimationUtils.currentAnimationTimeMillis(); 24867 if (now >= fadeStartTime) { 24868 24869 // the animation fades the scrollbars out by changing 24870 // the opacity (alpha) from fully opaque to fully 24871 // transparent 24872 int nextFrame = (int) now; 24873 int framesCount = 0; 24874 24875 Interpolator interpolator = scrollBarInterpolator; 24876 24877 // Start opaque 24878 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 24879 24880 // End transparent 24881 nextFrame += scrollBarFadeDuration; 24882 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 24883 24884 state = FADING; 24885 24886 // Kick off the fade animation 24887 host.invalidate(true); 24888 } 24889 } 24890 } 24891 24892 /** 24893 * Resuable callback for sending 24894 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 24895 */ 24896 private class SendViewScrolledAccessibilityEvent implements Runnable { 24897 public volatile boolean mIsPending; 24898 24899 public void run() { 24900 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 24901 mIsPending = false; 24902 } 24903 } 24904 24905 /** 24906 * <p> 24907 * This class represents a delegate that can be registered in a {@link View} 24908 * to enhance accessibility support via composition rather via inheritance. 24909 * It is specifically targeted to widget developers that extend basic View 24910 * classes i.e. classes in package android.view, that would like their 24911 * applications to be backwards compatible. 24912 * </p> 24913 * <div class="special reference"> 24914 * <h3>Developer Guides</h3> 24915 * <p>For more information about making applications accessible, read the 24916 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 24917 * developer guide.</p> 24918 * </div> 24919 * <p> 24920 * A scenario in which a developer would like to use an accessibility delegate 24921 * is overriding a method introduced in a later API version than the minimal API 24922 * version supported by the application. For example, the method 24923 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 24924 * in API version 4 when the accessibility APIs were first introduced. If a 24925 * developer would like his application to run on API version 4 devices (assuming 24926 * all other APIs used by the application are version 4 or lower) and take advantage 24927 * of this method, instead of overriding the method which would break the application's 24928 * backwards compatibility, he can override the corresponding method in this 24929 * delegate and register the delegate in the target View if the API version of 24930 * the system is high enough, i.e. the API version is the same as or higher than the API 24931 * version that introduced 24932 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 24933 * </p> 24934 * <p> 24935 * Here is an example implementation: 24936 * </p> 24937 * <code><pre><p> 24938 * if (Build.VERSION.SDK_INT >= 14) { 24939 * // If the API version is equal of higher than the version in 24940 * // which onInitializeAccessibilityNodeInfo was introduced we 24941 * // register a delegate with a customized implementation. 24942 * View view = findViewById(R.id.view_id); 24943 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 24944 * public void onInitializeAccessibilityNodeInfo(View host, 24945 * AccessibilityNodeInfo info) { 24946 * // Let the default implementation populate the info. 24947 * super.onInitializeAccessibilityNodeInfo(host, info); 24948 * // Set some other information. 24949 * info.setEnabled(host.isEnabled()); 24950 * } 24951 * }); 24952 * } 24953 * </code></pre></p> 24954 * <p> 24955 * This delegate contains methods that correspond to the accessibility methods 24956 * in View. If a delegate has been specified the implementation in View hands 24957 * off handling to the corresponding method in this delegate. The default 24958 * implementation the delegate methods behaves exactly as the corresponding 24959 * method in View for the case of no accessibility delegate been set. Hence, 24960 * to customize the behavior of a View method, clients can override only the 24961 * corresponding delegate method without altering the behavior of the rest 24962 * accessibility related methods of the host view. 24963 * </p> 24964 * <p> 24965 * <strong>Note:</strong> On platform versions prior to 24966 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 24967 * views in the {@code android.widget.*} package are called <i>before</i> 24968 * host methods. This prevents certain properties such as class name from 24969 * being modified by overriding 24970 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 24971 * as any changes will be overwritten by the host class. 24972 * <p> 24973 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 24974 * methods are called <i>after</i> host methods, which all properties to be 24975 * modified without being overwritten by the host class. 24976 */ 24977 public static class AccessibilityDelegate { 24978 24979 /** 24980 * Sends an accessibility event of the given type. If accessibility is not 24981 * enabled this method has no effect. 24982 * <p> 24983 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 24984 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 24985 * been set. 24986 * </p> 24987 * 24988 * @param host The View hosting the delegate. 24989 * @param eventType The type of the event to send. 24990 * 24991 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 24992 */ 24993 public void sendAccessibilityEvent(View host, int eventType) { 24994 host.sendAccessibilityEventInternal(eventType); 24995 } 24996 24997 /** 24998 * Performs the specified accessibility action on the view. For 24999 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 25000 * <p> 25001 * The default implementation behaves as 25002 * {@link View#performAccessibilityAction(int, Bundle) 25003 * View#performAccessibilityAction(int, Bundle)} for the case of 25004 * no accessibility delegate been set. 25005 * </p> 25006 * 25007 * @param action The action to perform. 25008 * @return Whether the action was performed. 25009 * 25010 * @see View#performAccessibilityAction(int, Bundle) 25011 * View#performAccessibilityAction(int, Bundle) 25012 */ 25013 public boolean performAccessibilityAction(View host, int action, Bundle args) { 25014 return host.performAccessibilityActionInternal(action, args); 25015 } 25016 25017 /** 25018 * Sends an accessibility event. This method behaves exactly as 25019 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 25020 * empty {@link AccessibilityEvent} and does not perform a check whether 25021 * accessibility is enabled. 25022 * <p> 25023 * The default implementation behaves as 25024 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25025 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 25026 * the case of no accessibility delegate been set. 25027 * </p> 25028 * 25029 * @param host The View hosting the delegate. 25030 * @param event The event to send. 25031 * 25032 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25033 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25034 */ 25035 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 25036 host.sendAccessibilityEventUncheckedInternal(event); 25037 } 25038 25039 /** 25040 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 25041 * to its children for adding their text content to the event. 25042 * <p> 25043 * The default implementation behaves as 25044 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25045 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 25046 * the case of no accessibility delegate been set. 25047 * </p> 25048 * 25049 * @param host The View hosting the delegate. 25050 * @param event The event. 25051 * @return True if the event population was completed. 25052 * 25053 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25054 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25055 */ 25056 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25057 return host.dispatchPopulateAccessibilityEventInternal(event); 25058 } 25059 25060 /** 25061 * Gives a chance to the host View to populate the accessibility event with its 25062 * text content. 25063 * <p> 25064 * The default implementation behaves as 25065 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 25066 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 25067 * the case of no accessibility delegate been set. 25068 * </p> 25069 * 25070 * @param host The View hosting the delegate. 25071 * @param event The accessibility event which to populate. 25072 * 25073 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 25074 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 25075 */ 25076 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25077 host.onPopulateAccessibilityEventInternal(event); 25078 } 25079 25080 /** 25081 * Initializes an {@link AccessibilityEvent} with information about the 25082 * the host View which is the event source. 25083 * <p> 25084 * The default implementation behaves as 25085 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 25086 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 25087 * the case of no accessibility delegate been set. 25088 * </p> 25089 * 25090 * @param host The View hosting the delegate. 25091 * @param event The event to initialize. 25092 * 25093 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 25094 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 25095 */ 25096 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 25097 host.onInitializeAccessibilityEventInternal(event); 25098 } 25099 25100 /** 25101 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 25102 * <p> 25103 * The default implementation behaves as 25104 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25105 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 25106 * the case of no accessibility delegate been set. 25107 * </p> 25108 * 25109 * @param host The View hosting the delegate. 25110 * @param info The instance to initialize. 25111 * 25112 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25113 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25114 */ 25115 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 25116 host.onInitializeAccessibilityNodeInfoInternal(info); 25117 } 25118 25119 /** 25120 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 25121 * additional data. 25122 * <p> 25123 * This method only needs to be implemented if the View offers to provide additional data. 25124 * </p> 25125 * <p> 25126 * The default implementation behaves as 25127 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, int) for 25128 * the case where no accessibility delegate is set. 25129 * </p> 25130 * 25131 * @param host The View hosting the delegate. Never {@code null}. 25132 * @param info The info to which to add the extra data. Never {@code null}. 25133 * @param extraDataKey A key specifying the type of extra data to add to the info. The 25134 * extra data should be added to the {@link Bundle} returned by 25135 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 25136 * {@code null}. 25137 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 25138 * May be {@code null} if the if the service provided no arguments. 25139 * 25140 * @see AccessibilityNodeInfo#setExtraAvailableData 25141 */ 25142 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 25143 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 25144 @Nullable Bundle arguments) { 25145 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 25146 } 25147 25148 /** 25149 * Called when a child of the host View has requested sending an 25150 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 25151 * to augment the event. 25152 * <p> 25153 * The default implementation behaves as 25154 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25155 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 25156 * the case of no accessibility delegate been set. 25157 * </p> 25158 * 25159 * @param host The View hosting the delegate. 25160 * @param child The child which requests sending the event. 25161 * @param event The event to be sent. 25162 * @return True if the event should be sent 25163 * 25164 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25165 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25166 */ 25167 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 25168 AccessibilityEvent event) { 25169 return host.onRequestSendAccessibilityEventInternal(child, event); 25170 } 25171 25172 /** 25173 * Gets the provider for managing a virtual view hierarchy rooted at this View 25174 * and reported to {@link android.accessibilityservice.AccessibilityService}s 25175 * that explore the window content. 25176 * <p> 25177 * The default implementation behaves as 25178 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 25179 * the case of no accessibility delegate been set. 25180 * </p> 25181 * 25182 * @return The provider. 25183 * 25184 * @see AccessibilityNodeProvider 25185 */ 25186 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 25187 return null; 25188 } 25189 25190 /** 25191 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 25192 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 25193 * This method is responsible for obtaining an accessibility node info from a 25194 * pool of reusable instances and calling 25195 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 25196 * view to initialize the former. 25197 * <p> 25198 * <strong>Note:</strong> The client is responsible for recycling the obtained 25199 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 25200 * creation. 25201 * </p> 25202 * <p> 25203 * The default implementation behaves as 25204 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 25205 * the case of no accessibility delegate been set. 25206 * </p> 25207 * @return A populated {@link AccessibilityNodeInfo}. 25208 * 25209 * @see AccessibilityNodeInfo 25210 * 25211 * @hide 25212 */ 25213 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 25214 return host.createAccessibilityNodeInfoInternal(); 25215 } 25216 } 25217 25218 private static class MatchIdPredicate implements Predicate<View> { 25219 public int mId; 25220 25221 @Override 25222 public boolean test(View view) { 25223 return (view.mID == mId); 25224 } 25225 } 25226 25227 private static class MatchLabelForPredicate implements Predicate<View> { 25228 private int mLabeledId; 25229 25230 @Override 25231 public boolean test(View view) { 25232 return (view.mLabelForId == mLabeledId); 25233 } 25234 } 25235 25236 private class SendViewStateChangedAccessibilityEvent implements Runnable { 25237 private int mChangeTypes = 0; 25238 private boolean mPosted; 25239 private boolean mPostedWithDelay; 25240 private long mLastEventTimeMillis; 25241 25242 @Override 25243 public void run() { 25244 mPosted = false; 25245 mPostedWithDelay = false; 25246 mLastEventTimeMillis = SystemClock.uptimeMillis(); 25247 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 25248 final AccessibilityEvent event = AccessibilityEvent.obtain(); 25249 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 25250 event.setContentChangeTypes(mChangeTypes); 25251 sendAccessibilityEventUnchecked(event); 25252 } 25253 mChangeTypes = 0; 25254 } 25255 25256 public void runOrPost(int changeType) { 25257 mChangeTypes |= changeType; 25258 25259 // If this is a live region or the child of a live region, collect 25260 // all events from this frame and send them on the next frame. 25261 if (inLiveRegion()) { 25262 // If we're already posted with a delay, remove that. 25263 if (mPostedWithDelay) { 25264 removeCallbacks(this); 25265 mPostedWithDelay = false; 25266 } 25267 // Only post if we're not already posted. 25268 if (!mPosted) { 25269 post(this); 25270 mPosted = true; 25271 } 25272 return; 25273 } 25274 25275 if (mPosted) { 25276 return; 25277 } 25278 25279 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 25280 final long minEventIntevalMillis = 25281 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 25282 if (timeSinceLastMillis >= minEventIntevalMillis) { 25283 removeCallbacks(this); 25284 run(); 25285 } else { 25286 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 25287 mPostedWithDelay = true; 25288 } 25289 } 25290 } 25291 25292 private boolean inLiveRegion() { 25293 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { 25294 return true; 25295 } 25296 25297 ViewParent parent = getParent(); 25298 while (parent instanceof View) { 25299 if (((View) parent).getAccessibilityLiveRegion() 25300 != View.ACCESSIBILITY_LIVE_REGION_NONE) { 25301 return true; 25302 } 25303 parent = parent.getParent(); 25304 } 25305 25306 return false; 25307 } 25308 25309 /** 25310 * Dump all private flags in readable format, useful for documentation and 25311 * sanity checking. 25312 */ 25313 private static void dumpFlags() { 25314 final HashMap<String, String> found = Maps.newHashMap(); 25315 try { 25316 for (Field field : View.class.getDeclaredFields()) { 25317 final int modifiers = field.getModifiers(); 25318 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 25319 if (field.getType().equals(int.class)) { 25320 final int value = field.getInt(null); 25321 dumpFlag(found, field.getName(), value); 25322 } else if (field.getType().equals(int[].class)) { 25323 final int[] values = (int[]) field.get(null); 25324 for (int i = 0; i < values.length; i++) { 25325 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 25326 } 25327 } 25328 } 25329 } 25330 } catch (IllegalAccessException e) { 25331 throw new RuntimeException(e); 25332 } 25333 25334 final ArrayList<String> keys = Lists.newArrayList(); 25335 keys.addAll(found.keySet()); 25336 Collections.sort(keys); 25337 for (String key : keys) { 25338 Log.d(VIEW_LOG_TAG, found.get(key)); 25339 } 25340 } 25341 25342 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 25343 // Sort flags by prefix, then by bits, always keeping unique keys 25344 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 25345 final int prefix = name.indexOf('_'); 25346 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 25347 final String output = bits + " " + name; 25348 found.put(key, output); 25349 } 25350 25351 /** {@hide} */ 25352 public void encode(@NonNull ViewHierarchyEncoder stream) { 25353 stream.beginObject(this); 25354 encodeProperties(stream); 25355 stream.endObject(); 25356 } 25357 25358 /** {@hide} */ 25359 @CallSuper 25360 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 25361 Object resolveId = ViewDebug.resolveId(getContext(), mID); 25362 if (resolveId instanceof String) { 25363 stream.addProperty("id", (String) resolveId); 25364 } else { 25365 stream.addProperty("id", mID); 25366 } 25367 25368 stream.addProperty("misc:transformation.alpha", 25369 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 25370 stream.addProperty("misc:transitionName", getTransitionName()); 25371 25372 // layout 25373 stream.addProperty("layout:left", mLeft); 25374 stream.addProperty("layout:right", mRight); 25375 stream.addProperty("layout:top", mTop); 25376 stream.addProperty("layout:bottom", mBottom); 25377 stream.addProperty("layout:width", getWidth()); 25378 stream.addProperty("layout:height", getHeight()); 25379 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 25380 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 25381 stream.addProperty("layout:hasTransientState", hasTransientState()); 25382 stream.addProperty("layout:baseline", getBaseline()); 25383 25384 // layout params 25385 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 25386 if (layoutParams != null) { 25387 stream.addPropertyKey("layoutParams"); 25388 layoutParams.encode(stream); 25389 } 25390 25391 // scrolling 25392 stream.addProperty("scrolling:scrollX", mScrollX); 25393 stream.addProperty("scrolling:scrollY", mScrollY); 25394 25395 // padding 25396 stream.addProperty("padding:paddingLeft", mPaddingLeft); 25397 stream.addProperty("padding:paddingRight", mPaddingRight); 25398 stream.addProperty("padding:paddingTop", mPaddingTop); 25399 stream.addProperty("padding:paddingBottom", mPaddingBottom); 25400 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 25401 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 25402 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 25403 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 25404 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 25405 25406 // measurement 25407 stream.addProperty("measurement:minHeight", mMinHeight); 25408 stream.addProperty("measurement:minWidth", mMinWidth); 25409 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 25410 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 25411 25412 // drawing 25413 stream.addProperty("drawing:elevation", getElevation()); 25414 stream.addProperty("drawing:translationX", getTranslationX()); 25415 stream.addProperty("drawing:translationY", getTranslationY()); 25416 stream.addProperty("drawing:translationZ", getTranslationZ()); 25417 stream.addProperty("drawing:rotation", getRotation()); 25418 stream.addProperty("drawing:rotationX", getRotationX()); 25419 stream.addProperty("drawing:rotationY", getRotationY()); 25420 stream.addProperty("drawing:scaleX", getScaleX()); 25421 stream.addProperty("drawing:scaleY", getScaleY()); 25422 stream.addProperty("drawing:pivotX", getPivotX()); 25423 stream.addProperty("drawing:pivotY", getPivotY()); 25424 stream.addProperty("drawing:opaque", isOpaque()); 25425 stream.addProperty("drawing:alpha", getAlpha()); 25426 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 25427 stream.addProperty("drawing:shadow", hasShadow()); 25428 stream.addProperty("drawing:solidColor", getSolidColor()); 25429 stream.addProperty("drawing:layerType", mLayerType); 25430 stream.addProperty("drawing:willNotDraw", willNotDraw()); 25431 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 25432 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 25433 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 25434 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 25435 25436 // focus 25437 stream.addProperty("focus:hasFocus", hasFocus()); 25438 stream.addProperty("focus:isFocused", isFocused()); 25439 stream.addProperty("focus:isFocusable", isFocusable()); 25440 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 25441 25442 stream.addProperty("misc:clickable", isClickable()); 25443 stream.addProperty("misc:pressed", isPressed()); 25444 stream.addProperty("misc:selected", isSelected()); 25445 stream.addProperty("misc:touchMode", isInTouchMode()); 25446 stream.addProperty("misc:hovered", isHovered()); 25447 stream.addProperty("misc:activated", isActivated()); 25448 25449 stream.addProperty("misc:visibility", getVisibility()); 25450 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 25451 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 25452 25453 stream.addProperty("misc:enabled", isEnabled()); 25454 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 25455 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 25456 25457 // theme attributes 25458 Resources.Theme theme = getContext().getTheme(); 25459 if (theme != null) { 25460 stream.addPropertyKey("theme"); 25461 theme.encode(stream); 25462 } 25463 25464 // view attribute information 25465 int n = mAttributes != null ? mAttributes.length : 0; 25466 stream.addProperty("meta:__attrCount__", n/2); 25467 for (int i = 0; i < n; i += 2) { 25468 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 25469 } 25470 25471 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 25472 25473 // text 25474 stream.addProperty("text:textDirection", getTextDirection()); 25475 stream.addProperty("text:textAlignment", getTextAlignment()); 25476 25477 // accessibility 25478 CharSequence contentDescription = getContentDescription(); 25479 stream.addProperty("accessibility:contentDescription", 25480 contentDescription == null ? "" : contentDescription.toString()); 25481 stream.addProperty("accessibility:labelFor", getLabelFor()); 25482 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 25483 } 25484 25485 /** 25486 * Determine if this view is rendered on a round wearable device and is the main view 25487 * on the screen. 25488 */ 25489 boolean shouldDrawRoundScrollbar() { 25490 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 25491 return false; 25492 } 25493 25494 final View rootView = getRootView(); 25495 final WindowInsets insets = getRootWindowInsets(); 25496 25497 int height = getHeight(); 25498 int width = getWidth(); 25499 int displayHeight = rootView.getHeight(); 25500 int displayWidth = rootView.getWidth(); 25501 25502 if (height != displayHeight || width != displayWidth) { 25503 return false; 25504 } 25505 25506 getLocationInWindow(mAttachInfo.mTmpLocation); 25507 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 25508 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 25509 } 25510 25511 /** 25512 * Sets the tooltip text which will be displayed in a small popup next to the view. 25513 * <p> 25514 * The tooltip will be displayed: 25515 * <ul> 25516 * <li>On long click, unless is not handled otherwise (by OnLongClickListener or a context 25517 * menu). </li> 25518 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 25519 * </ul> 25520 * <p> 25521 * <strong>Note:</strong> Do not override this method, as it will have no 25522 * effect on the text displayed in the tooltip. 25523 * 25524 * @param tooltipText the tooltip text, or null if no tooltip is required 25525 * @see #getTooltipText() 25526 * @attr ref android.R.styleable#View_tooltipText 25527 */ 25528 public void setTooltipText(@Nullable CharSequence tooltipText) { 25529 if (TextUtils.isEmpty(tooltipText)) { 25530 setFlags(0, TOOLTIP); 25531 hideTooltip(); 25532 mTooltipInfo = null; 25533 } else { 25534 setFlags(TOOLTIP, TOOLTIP); 25535 if (mTooltipInfo == null) { 25536 mTooltipInfo = new TooltipInfo(); 25537 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 25538 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 25539 } 25540 mTooltipInfo.mTooltipText = tooltipText; 25541 if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) { 25542 mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText); 25543 } 25544 } 25545 } 25546 25547 /** 25548 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 25549 */ 25550 public void setTooltip(@Nullable CharSequence tooltipText) { 25551 setTooltipText(tooltipText); 25552 } 25553 25554 /** 25555 * Returns the view's tooltip text. 25556 * 25557 * <strong>Note:</strong> Do not override this method, as it will have no 25558 * effect on the text displayed in the tooltip. You must call 25559 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 25560 * 25561 * @return the tooltip text 25562 * @see #setTooltipText(CharSequence) 25563 * @attr ref android.R.styleable#View_tooltipText 25564 */ 25565 @Nullable 25566 public CharSequence getTooltipText() { 25567 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 25568 } 25569 25570 /** 25571 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 25572 */ 25573 @Nullable 25574 public CharSequence getTooltip() { 25575 return getTooltipText(); 25576 } 25577 25578 private boolean showTooltip(int x, int y, boolean fromLongClick) { 25579 if (mAttachInfo == null || mTooltipInfo == null) { 25580 return false; 25581 } 25582 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 25583 return false; 25584 } 25585 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 25586 return false; 25587 } 25588 hideTooltip(); 25589 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 25590 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 25591 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 25592 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 25593 mAttachInfo.mTooltipHost = this; 25594 return true; 25595 } 25596 25597 void hideTooltip() { 25598 if (mTooltipInfo == null) { 25599 return; 25600 } 25601 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 25602 if (mTooltipInfo.mTooltipPopup == null) { 25603 return; 25604 } 25605 mTooltipInfo.mTooltipPopup.hide(); 25606 mTooltipInfo.mTooltipPopup = null; 25607 mTooltipInfo.mTooltipFromLongClick = false; 25608 if (mAttachInfo != null) { 25609 mAttachInfo.mTooltipHost = null; 25610 } 25611 } 25612 25613 private boolean showLongClickTooltip(int x, int y) { 25614 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 25615 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 25616 return showTooltip(x, y, true); 25617 } 25618 25619 private void showHoverTooltip() { 25620 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 25621 } 25622 25623 boolean dispatchTooltipHoverEvent(MotionEvent event) { 25624 if (mTooltipInfo == null) { 25625 return false; 25626 } 25627 switch(event.getAction()) { 25628 case MotionEvent.ACTION_HOVER_MOVE: 25629 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 25630 break; 25631 } 25632 if (!mTooltipInfo.mTooltipFromLongClick) { 25633 if (mTooltipInfo.mTooltipPopup == null) { 25634 // Schedule showing the tooltip after a timeout. 25635 mTooltipInfo.mAnchorX = (int) event.getX(); 25636 mTooltipInfo.mAnchorY = (int) event.getY(); 25637 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 25638 postDelayed(mTooltipInfo.mShowTooltipRunnable, 25639 ViewConfiguration.getHoverTooltipShowTimeout()); 25640 } 25641 25642 // Hide hover-triggered tooltip after a period of inactivity. 25643 // Match the timeout used by NativeInputManager to hide the mouse pointer 25644 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 25645 final int timeout; 25646 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 25647 == SYSTEM_UI_FLAG_LOW_PROFILE) { 25648 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 25649 } else { 25650 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 25651 } 25652 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 25653 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 25654 } 25655 return true; 25656 25657 case MotionEvent.ACTION_HOVER_EXIT: 25658 if (!mTooltipInfo.mTooltipFromLongClick) { 25659 hideTooltip(); 25660 } 25661 break; 25662 } 25663 return false; 25664 } 25665 25666 void handleTooltipKey(KeyEvent event) { 25667 switch (event.getAction()) { 25668 case KeyEvent.ACTION_DOWN: 25669 if (event.getRepeatCount() == 0) { 25670 hideTooltip(); 25671 } 25672 break; 25673 25674 case KeyEvent.ACTION_UP: 25675 handleTooltipUp(); 25676 break; 25677 } 25678 } 25679 25680 private void handleTooltipUp() { 25681 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 25682 return; 25683 } 25684 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 25685 postDelayed(mTooltipInfo.mHideTooltipRunnable, 25686 ViewConfiguration.getLongPressTooltipHideTimeout()); 25687 } 25688 25689 private int getFocusableAttribute(TypedArray attributes) { 25690 TypedValue val = new TypedValue(); 25691 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 25692 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 25693 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 25694 } else { 25695 return val.data; 25696 } 25697 } else { 25698 return FOCUSABLE_AUTO; 25699 } 25700 } 25701 25702 /** 25703 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 25704 * is not showing. 25705 * @hide 25706 */ 25707 @TestApi 25708 public View getTooltipView() { 25709 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 25710 return null; 25711 } 25712 return mTooltipInfo.mTooltipPopup.getContentView(); 25713 } 25714} 25715