View.java revision 2f6fc72efcb67737f45edb881eb2aed120a1b0bf
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.view; 18 19import static java.lang.Math.max; 20 21import android.animation.AnimatorInflater; 22import android.animation.StateListAnimator; 23import android.annotation.CallSuper; 24import android.annotation.ColorInt; 25import android.annotation.DrawableRes; 26import android.annotation.FloatRange; 27import android.annotation.IdRes; 28import android.annotation.IntDef; 29import android.annotation.IntRange; 30import android.annotation.LayoutRes; 31import android.annotation.NonNull; 32import android.annotation.Nullable; 33import android.annotation.Size; 34import android.annotation.TestApi; 35import android.annotation.UiThread; 36import android.content.ClipData; 37import android.content.Context; 38import android.content.ContextWrapper; 39import android.content.Intent; 40import android.content.res.ColorStateList; 41import android.content.res.Configuration; 42import android.content.res.Resources; 43import android.content.res.TypedArray; 44import android.graphics.Bitmap; 45import android.graphics.Canvas; 46import android.graphics.Color; 47import android.graphics.Insets; 48import android.graphics.Interpolator; 49import android.graphics.LinearGradient; 50import android.graphics.Matrix; 51import android.graphics.Outline; 52import android.graphics.Paint; 53import android.graphics.PixelFormat; 54import android.graphics.Point; 55import android.graphics.PorterDuff; 56import android.graphics.PorterDuffXfermode; 57import android.graphics.Rect; 58import android.graphics.RectF; 59import android.graphics.Region; 60import android.graphics.Shader; 61import android.graphics.drawable.ColorDrawable; 62import android.graphics.drawable.Drawable; 63import android.hardware.display.DisplayManagerGlobal; 64import android.net.Uri; 65import android.os.Build; 66import android.os.Bundle; 67import android.os.Handler; 68import android.os.IBinder; 69import android.os.Message; 70import android.os.Parcel; 71import android.os.Parcelable; 72import android.os.RemoteException; 73import android.os.SystemClock; 74import android.os.SystemProperties; 75import android.os.Trace; 76import android.text.TextUtils; 77import android.util.AttributeSet; 78import android.util.FloatProperty; 79import android.util.LayoutDirection; 80import android.util.Log; 81import android.util.LongSparseLongArray; 82import android.util.Pools.SynchronizedPool; 83import android.util.Property; 84import android.util.SparseArray; 85import android.util.StateSet; 86import android.util.SuperNotCalledException; 87import android.util.TypedValue; 88import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 89import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 90import android.view.AccessibilityIterators.TextSegmentIterator; 91import android.view.AccessibilityIterators.WordTextSegmentIterator; 92import android.view.ContextMenu.ContextMenuInfo; 93import android.view.accessibility.AccessibilityEvent; 94import android.view.accessibility.AccessibilityEventSource; 95import android.view.accessibility.AccessibilityManager; 96import android.view.accessibility.AccessibilityNodeInfo; 97import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 98import android.view.accessibility.AccessibilityNodeProvider; 99import android.view.accessibility.AccessibilityWindowInfo; 100import android.view.animation.Animation; 101import android.view.animation.AnimationUtils; 102import android.view.animation.Transformation; 103import android.view.autofill.AutofillId; 104import android.view.autofill.AutofillManager; 105import android.view.autofill.AutofillValue; 106import android.view.inputmethod.EditorInfo; 107import android.view.inputmethod.InputConnection; 108import android.view.inputmethod.InputMethodManager; 109import android.widget.Checkable; 110import android.widget.FrameLayout; 111import android.widget.ScrollBarDrawable; 112 113import com.android.internal.R; 114import com.android.internal.view.TooltipPopup; 115import com.android.internal.view.menu.MenuBuilder; 116import com.android.internal.widget.ScrollBarUtils; 117 118import com.google.android.collect.Lists; 119import com.google.android.collect.Maps; 120 121import java.lang.annotation.Retention; 122import java.lang.annotation.RetentionPolicy; 123import java.lang.ref.WeakReference; 124import java.lang.reflect.Field; 125import java.lang.reflect.InvocationTargetException; 126import java.lang.reflect.Method; 127import java.lang.reflect.Modifier; 128import java.util.ArrayList; 129import java.util.Arrays; 130import java.util.Collection; 131import java.util.Collections; 132import java.util.HashMap; 133import java.util.List; 134import java.util.Locale; 135import java.util.Map; 136import java.util.concurrent.CopyOnWriteArrayList; 137import java.util.concurrent.atomic.AtomicInteger; 138import java.util.function.Predicate; 139 140/** 141 * <p> 142 * This class represents the basic building block for user interface components. A View 143 * occupies a rectangular area on the screen and is responsible for drawing and 144 * event handling. View is the base class for <em>widgets</em>, which are 145 * used to create interactive UI components (buttons, text fields, etc.). The 146 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 147 * are invisible containers that hold other Views (or other ViewGroups) and define 148 * their layout properties. 149 * </p> 150 * 151 * <div class="special reference"> 152 * <h3>Developer Guides</h3> 153 * <p>For information about using this class to develop your application's user interface, 154 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 155 * </div> 156 * 157 * <a name="Using"></a> 158 * <h3>Using Views</h3> 159 * <p> 160 * All of the views in a window are arranged in a single tree. You can add views 161 * either from code or by specifying a tree of views in one or more XML layout 162 * files. There are many specialized subclasses of views that act as controls or 163 * are capable of displaying text, images, or other content. 164 * </p> 165 * <p> 166 * Once you have created a tree of views, there are typically a few types of 167 * common operations you may wish to perform: 168 * <ul> 169 * <li><strong>Set properties:</strong> for example setting the text of a 170 * {@link android.widget.TextView}. The available properties and the methods 171 * that set them will vary among the different subclasses of views. Note that 172 * properties that are known at build time can be set in the XML layout 173 * files.</li> 174 * <li><strong>Set focus:</strong> The framework will handle moving focus in 175 * response to user input. To force focus to a specific view, call 176 * {@link #requestFocus}.</li> 177 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 178 * that will be notified when something interesting happens to the view. For 179 * example, all views will let you set a listener to be notified when the view 180 * gains or loses focus. You can register such a listener using 181 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 182 * Other view subclasses offer more specialized listeners. For example, a Button 183 * exposes a listener to notify clients when the button is clicked.</li> 184 * <li><strong>Set visibility:</strong> You can hide or show views using 185 * {@link #setVisibility(int)}.</li> 186 * </ul> 187 * </p> 188 * <p><em> 189 * Note: The Android framework is responsible for measuring, laying out and 190 * drawing views. You should not call methods that perform these actions on 191 * views yourself unless you are actually implementing a 192 * {@link android.view.ViewGroup}. 193 * </em></p> 194 * 195 * <a name="Lifecycle"></a> 196 * <h3>Implementing a Custom View</h3> 197 * 198 * <p> 199 * To implement a custom view, you will usually begin by providing overrides for 200 * some of the standard methods that the framework calls on all views. You do 201 * not need to override all of these methods. In fact, you can start by just 202 * overriding {@link #onDraw(android.graphics.Canvas)}. 203 * <table border="2" width="85%" align="center" cellpadding="5"> 204 * <thead> 205 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 206 * </thead> 207 * 208 * <tbody> 209 * <tr> 210 * <td rowspan="2">Creation</td> 211 * <td>Constructors</td> 212 * <td>There is a form of the constructor that are called when the view 213 * is created from code and a form that is called when the view is 214 * inflated from a layout file. The second form should parse and apply 215 * any attributes defined in the layout file. 216 * </td> 217 * </tr> 218 * <tr> 219 * <td><code>{@link #onFinishInflate()}</code></td> 220 * <td>Called after a view and all of its children has been inflated 221 * from XML.</td> 222 * </tr> 223 * 224 * <tr> 225 * <td rowspan="3">Layout</td> 226 * <td><code>{@link #onMeasure(int, int)}</code></td> 227 * <td>Called to determine the size requirements for this view and all 228 * of its children. 229 * </td> 230 * </tr> 231 * <tr> 232 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 233 * <td>Called when this view should assign a size and position to all 234 * of its children. 235 * </td> 236 * </tr> 237 * <tr> 238 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 239 * <td>Called when the size of this view has changed. 240 * </td> 241 * </tr> 242 * 243 * <tr> 244 * <td>Drawing</td> 245 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 246 * <td>Called when the view should render its content. 247 * </td> 248 * </tr> 249 * 250 * <tr> 251 * <td rowspan="4">Event processing</td> 252 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 253 * <td>Called when a new hardware key event occurs. 254 * </td> 255 * </tr> 256 * <tr> 257 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 258 * <td>Called when a hardware key up event occurs. 259 * </td> 260 * </tr> 261 * <tr> 262 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 263 * <td>Called when a trackball motion event occurs. 264 * </td> 265 * </tr> 266 * <tr> 267 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 268 * <td>Called when a touch screen motion event occurs. 269 * </td> 270 * </tr> 271 * 272 * <tr> 273 * <td rowspan="2">Focus</td> 274 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 275 * <td>Called when the view gains or loses focus. 276 * </td> 277 * </tr> 278 * 279 * <tr> 280 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 281 * <td>Called when the window containing the view gains or loses focus. 282 * </td> 283 * </tr> 284 * 285 * <tr> 286 * <td rowspan="3">Attaching</td> 287 * <td><code>{@link #onAttachedToWindow()}</code></td> 288 * <td>Called when the view is attached to a window. 289 * </td> 290 * </tr> 291 * 292 * <tr> 293 * <td><code>{@link #onDetachedFromWindow}</code></td> 294 * <td>Called when the view is detached from its window. 295 * </td> 296 * </tr> 297 * 298 * <tr> 299 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 300 * <td>Called when the visibility of the window containing the view 301 * has changed. 302 * </td> 303 * </tr> 304 * </tbody> 305 * 306 * </table> 307 * </p> 308 * 309 * <a name="IDs"></a> 310 * <h3>IDs</h3> 311 * Views may have an integer id associated with them. These ids are typically 312 * assigned in the layout XML files, and are used to find specific views within 313 * the view tree. A common pattern is to: 314 * <ul> 315 * <li>Define a Button in the layout file and assign it a unique ID. 316 * <pre> 317 * <Button 318 * android:id="@+id/my_button" 319 * android:layout_width="wrap_content" 320 * android:layout_height="wrap_content" 321 * android:text="@string/my_button_text"/> 322 * </pre></li> 323 * <li>From the onCreate method of an Activity, find the Button 324 * <pre class="prettyprint"> 325 * Button myButton = findViewById(R.id.my_button); 326 * </pre></li> 327 * </ul> 328 * <p> 329 * View IDs need not be unique throughout the tree, but it is good practice to 330 * ensure that they are at least unique within the part of the tree you are 331 * searching. 332 * </p> 333 * 334 * <a name="Position"></a> 335 * <h3>Position</h3> 336 * <p> 337 * The geometry of a view is that of a rectangle. A view has a location, 338 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 339 * two dimensions, expressed as a width and a height. The unit for location 340 * and dimensions is the pixel. 341 * </p> 342 * 343 * <p> 344 * It is possible to retrieve the location of a view by invoking the methods 345 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 346 * coordinate of the rectangle representing the view. The latter returns the 347 * top, or Y, coordinate of the rectangle representing the view. These methods 348 * both return the location of the view relative to its parent. For instance, 349 * when getLeft() returns 20, that means the view is located 20 pixels to the 350 * right of the left edge of its direct parent. 351 * </p> 352 * 353 * <p> 354 * In addition, several convenience methods are offered to avoid unnecessary 355 * computations, namely {@link #getRight()} and {@link #getBottom()}. 356 * These methods return the coordinates of the right and bottom edges of the 357 * rectangle representing the view. For instance, calling {@link #getRight()} 358 * is similar to the following computation: <code>getLeft() + getWidth()</code> 359 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 360 * </p> 361 * 362 * <a name="SizePaddingMargins"></a> 363 * <h3>Size, padding and margins</h3> 364 * <p> 365 * The size of a view is expressed with a width and a height. A view actually 366 * possess two pairs of width and height values. 367 * </p> 368 * 369 * <p> 370 * The first pair is known as <em>measured width</em> and 371 * <em>measured height</em>. These dimensions define how big a view wants to be 372 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 373 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 374 * and {@link #getMeasuredHeight()}. 375 * </p> 376 * 377 * <p> 378 * The second pair is simply known as <em>width</em> and <em>height</em>, or 379 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 380 * dimensions define the actual size of the view on screen, at drawing time and 381 * after layout. These values may, but do not have to, be different from the 382 * measured width and height. The width and height can be obtained by calling 383 * {@link #getWidth()} and {@link #getHeight()}. 384 * </p> 385 * 386 * <p> 387 * To measure its dimensions, a view takes into account its padding. The padding 388 * is expressed in pixels for the left, top, right and bottom parts of the view. 389 * Padding can be used to offset the content of the view by a specific amount of 390 * pixels. For instance, a left padding of 2 will push the view's content by 391 * 2 pixels to the right of the left edge. Padding can be set using the 392 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 393 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 394 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 395 * {@link #getPaddingEnd()}. 396 * </p> 397 * 398 * <p> 399 * Even though a view can define a padding, it does not provide any support for 400 * margins. However, view groups provide such a support. Refer to 401 * {@link android.view.ViewGroup} and 402 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 403 * </p> 404 * 405 * <a name="Layout"></a> 406 * <h3>Layout</h3> 407 * <p> 408 * Layout is a two pass process: a measure pass and a layout pass. The measuring 409 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 410 * of the view tree. Each view pushes dimension specifications down the tree 411 * during the recursion. At the end of the measure pass, every view has stored 412 * its measurements. The second pass happens in 413 * {@link #layout(int,int,int,int)} and is also top-down. During 414 * this pass each parent is responsible for positioning all of its children 415 * using the sizes computed in the measure pass. 416 * </p> 417 * 418 * <p> 419 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 420 * {@link #getMeasuredHeight()} values must be set, along with those for all of 421 * that view's descendants. A view's measured width and measured height values 422 * must respect the constraints imposed by the view's parents. This guarantees 423 * that at the end of the measure pass, all parents accept all of their 424 * children's measurements. A parent view may call measure() more than once on 425 * its children. For example, the parent may measure each child once with 426 * unspecified dimensions to find out how big they want to be, then call 427 * measure() on them again with actual numbers if the sum of all the children's 428 * unconstrained sizes is too big or too small. 429 * </p> 430 * 431 * <p> 432 * The measure pass uses two classes to communicate dimensions. The 433 * {@link MeasureSpec} class is used by views to tell their parents how they 434 * want to be measured and positioned. The base LayoutParams class just 435 * describes how big the view wants to be for both width and height. For each 436 * dimension, it can specify one of: 437 * <ul> 438 * <li> an exact number 439 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 440 * (minus padding) 441 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 442 * enclose its content (plus padding). 443 * </ul> 444 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 445 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 446 * an X and Y value. 447 * </p> 448 * 449 * <p> 450 * MeasureSpecs are used to push requirements down the tree from parent to 451 * child. A MeasureSpec can be in one of three modes: 452 * <ul> 453 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 454 * of a child view. For example, a LinearLayout may call measure() on its child 455 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 456 * tall the child view wants to be given a width of 240 pixels. 457 * <li>EXACTLY: This is used by the parent to impose an exact size on the 458 * child. The child must use this size, and guarantee that all of its 459 * descendants will fit within this size. 460 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 461 * child. The child must guarantee that it and all of its descendants will fit 462 * within this size. 463 * </ul> 464 * </p> 465 * 466 * <p> 467 * To initiate a layout, call {@link #requestLayout}. This method is typically 468 * called by a view on itself when it believes that is can no longer fit within 469 * its current bounds. 470 * </p> 471 * 472 * <a name="Drawing"></a> 473 * <h3>Drawing</h3> 474 * <p> 475 * Drawing is handled by walking the tree and recording the drawing commands of 476 * any View that needs to update. After this, the drawing commands of the 477 * entire tree are issued to screen, clipped to the newly damaged area. 478 * </p> 479 * 480 * <p> 481 * The tree is largely recorded and drawn in order, with parents drawn before 482 * (i.e., behind) their children, with siblings drawn in the order they appear 483 * in the tree. If you set a background drawable for a View, then the View will 484 * draw it before calling back to its <code>onDraw()</code> method. The child 485 * drawing order can be overridden with 486 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 487 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 488 * </p> 489 * 490 * <p> 491 * To force a view to draw, call {@link #invalidate()}. 492 * </p> 493 * 494 * <a name="EventHandlingThreading"></a> 495 * <h3>Event Handling and Threading</h3> 496 * <p> 497 * The basic cycle of a view is as follows: 498 * <ol> 499 * <li>An event comes in and is dispatched to the appropriate view. The view 500 * handles the event and notifies any listeners.</li> 501 * <li>If in the course of processing the event, the view's bounds may need 502 * to be changed, the view will call {@link #requestLayout()}.</li> 503 * <li>Similarly, if in the course of processing the event the view's appearance 504 * may need to be changed, the view will call {@link #invalidate()}.</li> 505 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 506 * the framework will take care of measuring, laying out, and drawing the tree 507 * as appropriate.</li> 508 * </ol> 509 * </p> 510 * 511 * <p><em>Note: The entire view tree is single threaded. You must always be on 512 * the UI thread when calling any method on any view.</em> 513 * If you are doing work on other threads and want to update the state of a view 514 * from that thread, you should use a {@link Handler}. 515 * </p> 516 * 517 * <a name="FocusHandling"></a> 518 * <h3>Focus Handling</h3> 519 * <p> 520 * The framework will handle routine focus movement in response to user input. 521 * This includes changing the focus as views are removed or hidden, or as new 522 * views become available. Views indicate their willingness to take focus 523 * through the {@link #isFocusable} method. To change whether a view can take 524 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 525 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 526 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 527 * </p> 528 * <p> 529 * Focus movement is based on an algorithm which finds the nearest neighbor in a 530 * given direction. In rare cases, the default algorithm may not match the 531 * intended behavior of the developer. In these situations, you can provide 532 * explicit overrides by using these XML attributes in the layout file: 533 * <pre> 534 * nextFocusDown 535 * nextFocusLeft 536 * nextFocusRight 537 * nextFocusUp 538 * </pre> 539 * </p> 540 * 541 * 542 * <p> 543 * To get a particular view to take focus, call {@link #requestFocus()}. 544 * </p> 545 * 546 * <a name="TouchMode"></a> 547 * <h3>Touch Mode</h3> 548 * <p> 549 * When a user is navigating a user interface via directional keys such as a D-pad, it is 550 * necessary to give focus to actionable items such as buttons so the user can see 551 * what will take input. If the device has touch capabilities, however, and the user 552 * begins interacting with the interface by touching it, it is no longer necessary to 553 * always highlight, or give focus to, a particular view. This motivates a mode 554 * for interaction named 'touch mode'. 555 * </p> 556 * <p> 557 * For a touch capable device, once the user touches the screen, the device 558 * will enter touch mode. From this point onward, only views for which 559 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 560 * Other views that are touchable, like buttons, will not take focus when touched; they will 561 * only fire the on click listeners. 562 * </p> 563 * <p> 564 * Any time a user hits a directional key, such as a D-pad direction, the view device will 565 * exit touch mode, and find a view to take focus, so that the user may resume interacting 566 * with the user interface without touching the screen again. 567 * </p> 568 * <p> 569 * The touch mode state is maintained across {@link android.app.Activity}s. Call 570 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 571 * </p> 572 * 573 * <a name="Scrolling"></a> 574 * <h3>Scrolling</h3> 575 * <p> 576 * The framework provides basic support for views that wish to internally 577 * scroll their content. This includes keeping track of the X and Y scroll 578 * offset as well as mechanisms for drawing scrollbars. See 579 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 580 * {@link #awakenScrollBars()} for more details. 581 * </p> 582 * 583 * <a name="Tags"></a> 584 * <h3>Tags</h3> 585 * <p> 586 * Unlike IDs, tags are not used to identify views. Tags are essentially an 587 * extra piece of information that can be associated with a view. They are most 588 * often used as a convenience to store data related to views in the views 589 * themselves rather than by putting them in a separate structure. 590 * </p> 591 * <p> 592 * Tags may be specified with character sequence values in layout XML as either 593 * a single tag using the {@link android.R.styleable#View_tag android:tag} 594 * attribute or multiple tags using the {@code <tag>} child element: 595 * <pre> 596 * <View ... 597 * android:tag="@string/mytag_value" /> 598 * <View ...> 599 * <tag android:id="@+id/mytag" 600 * android:value="@string/mytag_value" /> 601 * </View> 602 * </pre> 603 * </p> 604 * <p> 605 * Tags may also be specified with arbitrary objects from code using 606 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 607 * </p> 608 * 609 * <a name="Themes"></a> 610 * <h3>Themes</h3> 611 * <p> 612 * By default, Views are created using the theme of the Context object supplied 613 * to their constructor; however, a different theme may be specified by using 614 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 615 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 616 * code. 617 * </p> 618 * <p> 619 * When the {@link android.R.styleable#View_theme android:theme} attribute is 620 * used in XML, the specified theme is applied on top of the inflation 621 * context's theme (see {@link LayoutInflater}) and used for the view itself as 622 * well as any child elements. 623 * </p> 624 * <p> 625 * In the following example, both views will be created using the Material dark 626 * color scheme; however, because an overlay theme is used which only defines a 627 * subset of attributes, the value of 628 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 629 * the inflation context's theme (e.g. the Activity theme) will be preserved. 630 * <pre> 631 * <LinearLayout 632 * ... 633 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 634 * <View ...> 635 * </LinearLayout> 636 * </pre> 637 * </p> 638 * 639 * <a name="Properties"></a> 640 * <h3>Properties</h3> 641 * <p> 642 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 643 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 644 * available both in the {@link Property} form as well as in similarly-named setter/getter 645 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 646 * be used to set persistent state associated with these rendering-related properties on the view. 647 * The properties and methods can also be used in conjunction with 648 * {@link android.animation.Animator Animator}-based animations, described more in the 649 * <a href="#Animation">Animation</a> section. 650 * </p> 651 * 652 * <a name="Animation"></a> 653 * <h3>Animation</h3> 654 * <p> 655 * Starting with Android 3.0, the preferred way of animating views is to use the 656 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 657 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 658 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 659 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 660 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 661 * makes animating these View properties particularly easy and efficient. 662 * </p> 663 * <p> 664 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 665 * You can attach an {@link Animation} object to a view using 666 * {@link #setAnimation(Animation)} or 667 * {@link #startAnimation(Animation)}. The animation can alter the scale, 668 * rotation, translation and alpha of a view over time. If the animation is 669 * attached to a view that has children, the animation will affect the entire 670 * subtree rooted by that node. When an animation is started, the framework will 671 * take care of redrawing the appropriate views until the animation completes. 672 * </p> 673 * 674 * <a name="Security"></a> 675 * <h3>Security</h3> 676 * <p> 677 * Sometimes it is essential that an application be able to verify that an action 678 * is being performed with the full knowledge and consent of the user, such as 679 * granting a permission request, making a purchase or clicking on an advertisement. 680 * Unfortunately, a malicious application could try to spoof the user into 681 * performing these actions, unaware, by concealing the intended purpose of the view. 682 * As a remedy, the framework offers a touch filtering mechanism that can be used to 683 * improve the security of views that provide access to sensitive functionality. 684 * </p><p> 685 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 686 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 687 * will discard touches that are received whenever the view's window is obscured by 688 * another visible window. As a result, the view will not receive touches whenever a 689 * toast, dialog or other window appears above the view's window. 690 * </p><p> 691 * For more fine-grained control over security, consider overriding the 692 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 693 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 694 * </p> 695 * 696 * @attr ref android.R.styleable#View_alpha 697 * @attr ref android.R.styleable#View_background 698 * @attr ref android.R.styleable#View_clickable 699 * @attr ref android.R.styleable#View_contentDescription 700 * @attr ref android.R.styleable#View_drawingCacheQuality 701 * @attr ref android.R.styleable#View_duplicateParentState 702 * @attr ref android.R.styleable#View_id 703 * @attr ref android.R.styleable#View_requiresFadingEdge 704 * @attr ref android.R.styleable#View_fadeScrollbars 705 * @attr ref android.R.styleable#View_fadingEdgeLength 706 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 707 * @attr ref android.R.styleable#View_fitsSystemWindows 708 * @attr ref android.R.styleable#View_isScrollContainer 709 * @attr ref android.R.styleable#View_focusable 710 * @attr ref android.R.styleable#View_focusableInTouchMode 711 * @attr ref android.R.styleable#View_focusedByDefault 712 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 713 * @attr ref android.R.styleable#View_keepScreenOn 714 * @attr ref android.R.styleable#View_keyboardNavigationCluster 715 * @attr ref android.R.styleable#View_layerType 716 * @attr ref android.R.styleable#View_layoutDirection 717 * @attr ref android.R.styleable#View_longClickable 718 * @attr ref android.R.styleable#View_minHeight 719 * @attr ref android.R.styleable#View_minWidth 720 * @attr ref android.R.styleable#View_nextClusterForward 721 * @attr ref android.R.styleable#View_nextFocusDown 722 * @attr ref android.R.styleable#View_nextFocusLeft 723 * @attr ref android.R.styleable#View_nextFocusRight 724 * @attr ref android.R.styleable#View_nextFocusUp 725 * @attr ref android.R.styleable#View_onClick 726 * @attr ref android.R.styleable#View_padding 727 * @attr ref android.R.styleable#View_paddingBottom 728 * @attr ref android.R.styleable#View_paddingLeft 729 * @attr ref android.R.styleable#View_paddingRight 730 * @attr ref android.R.styleable#View_paddingTop 731 * @attr ref android.R.styleable#View_paddingStart 732 * @attr ref android.R.styleable#View_paddingEnd 733 * @attr ref android.R.styleable#View_saveEnabled 734 * @attr ref android.R.styleable#View_rotation 735 * @attr ref android.R.styleable#View_rotationX 736 * @attr ref android.R.styleable#View_rotationY 737 * @attr ref android.R.styleable#View_scaleX 738 * @attr ref android.R.styleable#View_scaleY 739 * @attr ref android.R.styleable#View_scrollX 740 * @attr ref android.R.styleable#View_scrollY 741 * @attr ref android.R.styleable#View_scrollbarSize 742 * @attr ref android.R.styleable#View_scrollbarStyle 743 * @attr ref android.R.styleable#View_scrollbars 744 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 745 * @attr ref android.R.styleable#View_scrollbarFadeDuration 746 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 747 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 748 * @attr ref android.R.styleable#View_scrollbarThumbVertical 749 * @attr ref android.R.styleable#View_scrollbarTrackVertical 750 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 751 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 752 * @attr ref android.R.styleable#View_stateListAnimator 753 * @attr ref android.R.styleable#View_transitionName 754 * @attr ref android.R.styleable#View_soundEffectsEnabled 755 * @attr ref android.R.styleable#View_tag 756 * @attr ref android.R.styleable#View_textAlignment 757 * @attr ref android.R.styleable#View_textDirection 758 * @attr ref android.R.styleable#View_transformPivotX 759 * @attr ref android.R.styleable#View_transformPivotY 760 * @attr ref android.R.styleable#View_translationX 761 * @attr ref android.R.styleable#View_translationY 762 * @attr ref android.R.styleable#View_translationZ 763 * @attr ref android.R.styleable#View_visibility 764 * @attr ref android.R.styleable#View_theme 765 * 766 * @see android.view.ViewGroup 767 */ 768@UiThread 769public class View implements Drawable.Callback, KeyEvent.Callback, 770 AccessibilityEventSource { 771 private static final boolean DBG = false; 772 773 /** @hide */ 774 public static boolean DEBUG_DRAW = false; 775 776 /** 777 * The logging tag used by this class with android.util.Log. 778 */ 779 protected static final String VIEW_LOG_TAG = "View"; 780 781 /** 782 * When set to true, apps will draw debugging information about their layouts. 783 * 784 * @hide 785 */ 786 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 787 788 /** 789 * When set to true, this view will save its attribute data. 790 * 791 * @hide 792 */ 793 public static boolean mDebugViewAttributes = false; 794 795 /** 796 * Used to mark a View that has no ID. 797 */ 798 public static final int NO_ID = -1; 799 800 /** 801 * Last ID that is given to Views that are no part of activities. 802 * 803 * {@hide} 804 */ 805 public static final int LAST_APP_ACCESSIBILITY_ID = Integer.MAX_VALUE / 2; 806 807 /** 808 * Attribute to find the autofilled highlight 809 * 810 * @see #getAutofilledDrawable() 811 */ 812 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 813 new int[]{android.R.attr.autofilledHighlight}; 814 815 /** 816 * Signals that compatibility booleans have been initialized according to 817 * target SDK versions. 818 */ 819 private static boolean sCompatibilityDone = false; 820 821 /** 822 * Use the old (broken) way of building MeasureSpecs. 823 */ 824 private static boolean sUseBrokenMakeMeasureSpec = false; 825 826 /** 827 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 828 */ 829 static boolean sUseZeroUnspecifiedMeasureSpec = false; 830 831 /** 832 * Ignore any optimizations using the measure cache. 833 */ 834 private static boolean sIgnoreMeasureCache = false; 835 836 /** 837 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 838 */ 839 private static boolean sAlwaysRemeasureExactly = false; 840 841 /** 842 * Relax constraints around whether setLayoutParams() must be called after 843 * modifying the layout params. 844 */ 845 private static boolean sLayoutParamsAlwaysChanged = false; 846 847 /** 848 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 849 * without throwing 850 */ 851 static boolean sTextureViewIgnoresDrawableSetters = false; 852 853 /** 854 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 855 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 856 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 857 * check is implemented for backwards compatibility. 858 * 859 * {@hide} 860 */ 861 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 862 863 /** 864 * Prior to N, when drag enters into child of a view that has already received an 865 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 866 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 867 * false from its event handler for these events. 868 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 869 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 870 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 871 */ 872 static boolean sCascadedDragDrop; 873 874 /** 875 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 876 * to determine things like whether or not to permit item click events. We can't break 877 * apps that do this just because more things (clickable things) are now auto-focusable 878 * and they would get different results, so give old behavior to old apps. 879 */ 880 static boolean sHasFocusableExcludeAutoFocusable; 881 882 /** 883 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 884 * made focusable by default. As a result, apps could (incorrectly) change the clickable 885 * setting of views off the UI thread. Now that clickable can effect the focusable state, 886 * changing the clickable attribute off the UI thread will cause an exception (since changing 887 * the focusable state checks). In order to prevent apps from crashing, we will handle this 888 * specific case and just not notify parents on new focusables resulting from marking views 889 * clickable from outside the UI thread. 890 */ 891 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 892 893 /** @hide */ 894 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 895 @Retention(RetentionPolicy.SOURCE) 896 public @interface Focusable {} 897 898 /** 899 * This view does not want keystrokes. 900 * <p> 901 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 902 * android:focusable}. 903 */ 904 public static final int NOT_FOCUSABLE = 0x00000000; 905 906 /** 907 * This view wants keystrokes. 908 * <p> 909 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 910 * android:focusable}. 911 */ 912 public static final int FOCUSABLE = 0x00000001; 913 914 /** 915 * This view determines focusability automatically. This is the default. 916 * <p> 917 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 918 * android:focusable}. 919 */ 920 public static final int FOCUSABLE_AUTO = 0x00000010; 921 922 /** 923 * Mask for use with setFlags indicating bits used for focus. 924 */ 925 private static final int FOCUSABLE_MASK = 0x00000011; 926 927 /** 928 * This view will adjust its padding to fit sytem windows (e.g. status bar) 929 */ 930 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 931 932 /** @hide */ 933 @IntDef({VISIBLE, INVISIBLE, GONE}) 934 @Retention(RetentionPolicy.SOURCE) 935 public @interface Visibility {} 936 937 /** 938 * This view is visible. 939 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 940 * android:visibility}. 941 */ 942 public static final int VISIBLE = 0x00000000; 943 944 /** 945 * This view is invisible, but it still takes up space for layout purposes. 946 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 947 * android:visibility}. 948 */ 949 public static final int INVISIBLE = 0x00000004; 950 951 /** 952 * This view is invisible, and it doesn't take any space for layout 953 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 954 * android:visibility}. 955 */ 956 public static final int GONE = 0x00000008; 957 958 /** 959 * Mask for use with setFlags indicating bits used for visibility. 960 * {@hide} 961 */ 962 static final int VISIBILITY_MASK = 0x0000000C; 963 964 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 965 966 /** 967 * Hint indicating that this view can be autofilled with an email address. 968 * 969 * <p>Can be used with either {@link #setAutofillHints(String[])} or 970 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 971 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 972 * 973 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 974 */ 975 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 976 977 /** 978 * Hint indicating that this view can be autofilled with a user's real name. 979 * 980 * <p>Can be used with either {@link #setAutofillHints(String[])} or 981 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 982 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 983 * 984 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 985 */ 986 public static final String AUTOFILL_HINT_NAME = "name"; 987 988 /** 989 * Hint indicating that this view can be autofilled with a username. 990 * 991 * <p>Can be used with either {@link #setAutofillHints(String[])} or 992 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 993 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 994 * 995 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 996 */ 997 public static final String AUTOFILL_HINT_USERNAME = "username"; 998 999 /** 1000 * Hint indicating that this view can be autofilled with a password. 1001 * 1002 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1003 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1004 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1005 * 1006 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1007 */ 1008 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1009 1010 /** 1011 * Hint indicating that this view can be autofilled with a phone number. 1012 * 1013 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1014 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1015 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1016 * 1017 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1018 */ 1019 public static final String AUTOFILL_HINT_PHONE = "phone"; 1020 1021 /** 1022 * Hint indicating that this view can be autofilled with a postal address. 1023 * 1024 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1025 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1026 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1027 * 1028 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1029 */ 1030 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1031 1032 /** 1033 * Hint indicating that this view can be autofilled with a postal code. 1034 * 1035 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1036 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1037 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1038 * 1039 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1040 */ 1041 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1042 1043 /** 1044 * Hint indicating that this view can be autofilled with a credit card number. 1045 * 1046 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1047 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1048 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1049 * 1050 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1051 */ 1052 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1053 1054 /** 1055 * Hint indicating that this view can be autofilled with a credit card security code. 1056 * 1057 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1058 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1059 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1060 * 1061 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1062 */ 1063 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1064 1065 /** 1066 * Hint indicating that this view can be autofilled with a credit card expiration date. 1067 * 1068 * <p>It should be used when the credit card expiration date is represented by just one view; 1069 * if it is represented by more than one (for example, one view for the month and another view 1070 * for the year), then each of these views should use the hint specific for the unit 1071 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1072 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1073 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1074 * 1075 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1076 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1077 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1078 * 1079 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1080 */ 1081 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1082 "creditCardExpirationDate"; 1083 1084 /** 1085 * Hint indicating that this view can be autofilled with a credit card expiration month. 1086 * 1087 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1088 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1089 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1090 * 1091 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1092 */ 1093 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1094 "creditCardExpirationMonth"; 1095 1096 /** 1097 * Hint indicating that this view can be autofilled with a credit card expiration year. 1098 * 1099 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1100 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1101 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1102 * 1103 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1104 */ 1105 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1106 "creditCardExpirationYear"; 1107 1108 /** 1109 * Hint indicating that this view can be autofilled with a credit card expiration day. 1110 * 1111 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1112 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1113 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1114 * 1115 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1116 */ 1117 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1118 1119 /** 1120 * Hints for the autofill services that describes the content of the view. 1121 */ 1122 private @Nullable String[] mAutofillHints; 1123 1124 /** 1125 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1126 */ 1127 private AutofillId mAutofillId; 1128 1129 /** @hide */ 1130 @IntDef({ 1131 AUTOFILL_TYPE_NONE, 1132 AUTOFILL_TYPE_TEXT, 1133 AUTOFILL_TYPE_TOGGLE, 1134 AUTOFILL_TYPE_LIST, 1135 AUTOFILL_TYPE_DATE 1136 }) 1137 @Retention(RetentionPolicy.SOURCE) 1138 public @interface AutofillType {} 1139 1140 /** 1141 * Autofill type for views that cannot be autofilled. 1142 * 1143 * <p>Typically used when the view is read-only; for example, a text label. 1144 * 1145 * @see #getAutofillType() 1146 */ 1147 public static final int AUTOFILL_TYPE_NONE = 0; 1148 1149 /** 1150 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1151 * 1152 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1153 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1154 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1155 * 1156 * @see #getAutofillType() 1157 */ 1158 public static final int AUTOFILL_TYPE_TEXT = 1; 1159 1160 /** 1161 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1162 * 1163 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1164 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1165 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1166 * 1167 * @see #getAutofillType() 1168 */ 1169 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1170 1171 /** 1172 * Autofill type for a selection list field, which is filled by an {@code int} 1173 * representing the element index inside the list (starting at {@code 0}). 1174 * 1175 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1176 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1177 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1178 * 1179 * <p>The available options in the selection list are typically provided by 1180 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1181 * 1182 * @see #getAutofillType() 1183 */ 1184 public static final int AUTOFILL_TYPE_LIST = 3; 1185 1186 1187 /** 1188 * Autofill type for a field that contains a date, which is represented by a long representing 1189 * the number of milliseconds since the standard base time known as "the epoch", namely 1190 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1191 * 1192 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1193 * {@link AutofillValue#forDate(long)}, and the values passed to 1194 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1195 * 1196 * @see #getAutofillType() 1197 */ 1198 public static final int AUTOFILL_TYPE_DATE = 4; 1199 1200 /** @hide */ 1201 @IntDef({ 1202 IMPORTANT_FOR_AUTOFILL_AUTO, 1203 IMPORTANT_FOR_AUTOFILL_YES, 1204 IMPORTANT_FOR_AUTOFILL_NO, 1205 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1206 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1207 }) 1208 @Retention(RetentionPolicy.SOURCE) 1209 public @interface AutofillImportance {} 1210 1211 /** 1212 * Automatically determine whether a view is important for autofill. 1213 * 1214 * @see #isImportantForAutofill() 1215 * @see #setImportantForAutofill(int) 1216 */ 1217 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1218 1219 /** 1220 * The view is important for autofill, and its children (if any) will be traversed. 1221 * 1222 * @see #isImportantForAutofill() 1223 * @see #setImportantForAutofill(int) 1224 */ 1225 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1226 1227 /** 1228 * The view is not important for autofill, but its children (if any) will be traversed. 1229 * 1230 * @see #isImportantForAutofill() 1231 * @see #setImportantForAutofill(int) 1232 */ 1233 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1234 1235 /** 1236 * The view is important for autofill, but its children (if any) will not be traversed. 1237 * 1238 * @see #isImportantForAutofill() 1239 * @see #setImportantForAutofill(int) 1240 */ 1241 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1242 1243 /** 1244 * The view is not important for autofill, and its children (if any) will not be traversed. 1245 * 1246 * @see #isImportantForAutofill() 1247 * @see #setImportantForAutofill(int) 1248 */ 1249 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1250 1251 /** @hide */ 1252 @IntDef( 1253 flag = true, 1254 value = {AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS}) 1255 @Retention(RetentionPolicy.SOURCE) 1256 public @interface AutofillFlags {} 1257 1258 /** 1259 * Flag requesting you to add views that are marked as not important for autofill 1260 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1261 */ 1262 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1263 1264 /** 1265 * This view is enabled. Interpretation varies by subclass. 1266 * Use with ENABLED_MASK when calling setFlags. 1267 * {@hide} 1268 */ 1269 static final int ENABLED = 0x00000000; 1270 1271 /** 1272 * This view is disabled. Interpretation varies by subclass. 1273 * Use with ENABLED_MASK when calling setFlags. 1274 * {@hide} 1275 */ 1276 static final int DISABLED = 0x00000020; 1277 1278 /** 1279 * Mask for use with setFlags indicating bits used for indicating whether 1280 * this view is enabled 1281 * {@hide} 1282 */ 1283 static final int ENABLED_MASK = 0x00000020; 1284 1285 /** 1286 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1287 * called and further optimizations will be performed. It is okay to have 1288 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1289 * {@hide} 1290 */ 1291 static final int WILL_NOT_DRAW = 0x00000080; 1292 1293 /** 1294 * Mask for use with setFlags indicating bits used for indicating whether 1295 * this view is will draw 1296 * {@hide} 1297 */ 1298 static final int DRAW_MASK = 0x00000080; 1299 1300 /** 1301 * <p>This view doesn't show scrollbars.</p> 1302 * {@hide} 1303 */ 1304 static final int SCROLLBARS_NONE = 0x00000000; 1305 1306 /** 1307 * <p>This view shows horizontal scrollbars.</p> 1308 * {@hide} 1309 */ 1310 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1311 1312 /** 1313 * <p>This view shows vertical scrollbars.</p> 1314 * {@hide} 1315 */ 1316 static final int SCROLLBARS_VERTICAL = 0x00000200; 1317 1318 /** 1319 * <p>Mask for use with setFlags indicating bits used for indicating which 1320 * scrollbars are enabled.</p> 1321 * {@hide} 1322 */ 1323 static final int SCROLLBARS_MASK = 0x00000300; 1324 1325 /** 1326 * Indicates that the view should filter touches when its window is obscured. 1327 * Refer to the class comments for more information about this security feature. 1328 * {@hide} 1329 */ 1330 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1331 1332 /** 1333 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1334 * that they are optional and should be skipped if the window has 1335 * requested system UI flags that ignore those insets for layout. 1336 */ 1337 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1338 1339 /** 1340 * <p>This view doesn't show fading edges.</p> 1341 * {@hide} 1342 */ 1343 static final int FADING_EDGE_NONE = 0x00000000; 1344 1345 /** 1346 * <p>This view shows horizontal fading edges.</p> 1347 * {@hide} 1348 */ 1349 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1350 1351 /** 1352 * <p>This view shows vertical fading edges.</p> 1353 * {@hide} 1354 */ 1355 static final int FADING_EDGE_VERTICAL = 0x00002000; 1356 1357 /** 1358 * <p>Mask for use with setFlags indicating bits used for indicating which 1359 * fading edges are enabled.</p> 1360 * {@hide} 1361 */ 1362 static final int FADING_EDGE_MASK = 0x00003000; 1363 1364 /** 1365 * <p>Indicates this view can be clicked. When clickable, a View reacts 1366 * to clicks by notifying the OnClickListener.<p> 1367 * {@hide} 1368 */ 1369 static final int CLICKABLE = 0x00004000; 1370 1371 /** 1372 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1373 * {@hide} 1374 */ 1375 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1376 1377 /** 1378 * <p>Indicates that no icicle should be saved for this view.<p> 1379 * {@hide} 1380 */ 1381 static final int SAVE_DISABLED = 0x000010000; 1382 1383 /** 1384 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1385 * property.</p> 1386 * {@hide} 1387 */ 1388 static final int SAVE_DISABLED_MASK = 0x000010000; 1389 1390 /** 1391 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1392 * {@hide} 1393 */ 1394 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1395 1396 /** 1397 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1398 * {@hide} 1399 */ 1400 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1401 1402 /** @hide */ 1403 @Retention(RetentionPolicy.SOURCE) 1404 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1405 public @interface DrawingCacheQuality {} 1406 1407 /** 1408 * <p>Enables low quality mode for the drawing cache.</p> 1409 */ 1410 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1411 1412 /** 1413 * <p>Enables high quality mode for the drawing cache.</p> 1414 */ 1415 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1416 1417 /** 1418 * <p>Enables automatic quality mode for the drawing cache.</p> 1419 */ 1420 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1421 1422 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1423 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1424 }; 1425 1426 /** 1427 * <p>Mask for use with setFlags indicating bits used for the cache 1428 * quality property.</p> 1429 * {@hide} 1430 */ 1431 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1432 1433 /** 1434 * <p> 1435 * Indicates this view can be long clicked. When long clickable, a View 1436 * reacts to long clicks by notifying the OnLongClickListener or showing a 1437 * context menu. 1438 * </p> 1439 * {@hide} 1440 */ 1441 static final int LONG_CLICKABLE = 0x00200000; 1442 1443 /** 1444 * <p>Indicates that this view gets its drawable states from its direct parent 1445 * and ignores its original internal states.</p> 1446 * 1447 * @hide 1448 */ 1449 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1450 1451 /** 1452 * <p> 1453 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1454 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1455 * OnContextClickListener. 1456 * </p> 1457 * {@hide} 1458 */ 1459 static final int CONTEXT_CLICKABLE = 0x00800000; 1460 1461 1462 /** @hide */ 1463 @IntDef({ 1464 SCROLLBARS_INSIDE_OVERLAY, 1465 SCROLLBARS_INSIDE_INSET, 1466 SCROLLBARS_OUTSIDE_OVERLAY, 1467 SCROLLBARS_OUTSIDE_INSET 1468 }) 1469 @Retention(RetentionPolicy.SOURCE) 1470 public @interface ScrollBarStyle {} 1471 1472 /** 1473 * The scrollbar style to display the scrollbars inside the content area, 1474 * without increasing the padding. The scrollbars will be overlaid with 1475 * translucency on the view's content. 1476 */ 1477 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1478 1479 /** 1480 * The scrollbar style to display the scrollbars inside the padded area, 1481 * increasing the padding of the view. The scrollbars will not overlap the 1482 * content area of the view. 1483 */ 1484 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1485 1486 /** 1487 * The scrollbar style to display the scrollbars at the edge of the view, 1488 * without increasing the padding. The scrollbars will be overlaid with 1489 * translucency. 1490 */ 1491 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1492 1493 /** 1494 * The scrollbar style to display the scrollbars at the edge of the view, 1495 * increasing the padding of the view. The scrollbars will only overlap the 1496 * background, if any. 1497 */ 1498 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1499 1500 /** 1501 * Mask to check if the scrollbar style is overlay or inset. 1502 * {@hide} 1503 */ 1504 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1505 1506 /** 1507 * Mask to check if the scrollbar style is inside or outside. 1508 * {@hide} 1509 */ 1510 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1511 1512 /** 1513 * Mask for scrollbar style. 1514 * {@hide} 1515 */ 1516 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1517 1518 /** 1519 * View flag indicating that the screen should remain on while the 1520 * window containing this view is visible to the user. This effectively 1521 * takes care of automatically setting the WindowManager's 1522 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1523 */ 1524 public static final int KEEP_SCREEN_ON = 0x04000000; 1525 1526 /** 1527 * View flag indicating whether this view should have sound effects enabled 1528 * for events such as clicking and touching. 1529 */ 1530 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1531 1532 /** 1533 * View flag indicating whether this view should have haptic feedback 1534 * enabled for events such as long presses. 1535 */ 1536 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1537 1538 /** 1539 * <p>Indicates that the view hierarchy should stop saving state when 1540 * it reaches this view. If state saving is initiated immediately at 1541 * the view, it will be allowed. 1542 * {@hide} 1543 */ 1544 static final int PARENT_SAVE_DISABLED = 0x20000000; 1545 1546 /** 1547 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1548 * {@hide} 1549 */ 1550 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1551 1552 private static Paint sDebugPaint; 1553 1554 /** 1555 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1556 * {@hide} 1557 */ 1558 static final int TOOLTIP = 0x40000000; 1559 1560 /** @hide */ 1561 @IntDef(flag = true, 1562 value = { 1563 FOCUSABLES_ALL, 1564 FOCUSABLES_TOUCH_MODE 1565 }) 1566 @Retention(RetentionPolicy.SOURCE) 1567 public @interface FocusableMode {} 1568 1569 /** 1570 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1571 * should add all focusable Views regardless if they are focusable in touch mode. 1572 */ 1573 public static final int FOCUSABLES_ALL = 0x00000000; 1574 1575 /** 1576 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1577 * should add only Views focusable in touch mode. 1578 */ 1579 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1580 1581 /** @hide */ 1582 @IntDef({ 1583 FOCUS_BACKWARD, 1584 FOCUS_FORWARD, 1585 FOCUS_LEFT, 1586 FOCUS_UP, 1587 FOCUS_RIGHT, 1588 FOCUS_DOWN 1589 }) 1590 @Retention(RetentionPolicy.SOURCE) 1591 public @interface FocusDirection {} 1592 1593 /** @hide */ 1594 @IntDef({ 1595 FOCUS_LEFT, 1596 FOCUS_UP, 1597 FOCUS_RIGHT, 1598 FOCUS_DOWN 1599 }) 1600 @Retention(RetentionPolicy.SOURCE) 1601 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1602 1603 /** 1604 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1605 * item. 1606 */ 1607 public static final int FOCUS_BACKWARD = 0x00000001; 1608 1609 /** 1610 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1611 * item. 1612 */ 1613 public static final int FOCUS_FORWARD = 0x00000002; 1614 1615 /** 1616 * Use with {@link #focusSearch(int)}. Move focus to the left. 1617 */ 1618 public static final int FOCUS_LEFT = 0x00000011; 1619 1620 /** 1621 * Use with {@link #focusSearch(int)}. Move focus up. 1622 */ 1623 public static final int FOCUS_UP = 0x00000021; 1624 1625 /** 1626 * Use with {@link #focusSearch(int)}. Move focus to the right. 1627 */ 1628 public static final int FOCUS_RIGHT = 0x00000042; 1629 1630 /** 1631 * Use with {@link #focusSearch(int)}. Move focus down. 1632 */ 1633 public static final int FOCUS_DOWN = 0x00000082; 1634 1635 /** 1636 * Bits of {@link #getMeasuredWidthAndState()} and 1637 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1638 */ 1639 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1640 1641 /** 1642 * Bits of {@link #getMeasuredWidthAndState()} and 1643 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1644 */ 1645 public static final int MEASURED_STATE_MASK = 0xff000000; 1646 1647 /** 1648 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1649 * for functions that combine both width and height into a single int, 1650 * such as {@link #getMeasuredState()} and the childState argument of 1651 * {@link #resolveSizeAndState(int, int, int)}. 1652 */ 1653 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1654 1655 /** 1656 * Bit of {@link #getMeasuredWidthAndState()} and 1657 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1658 * is smaller that the space the view would like to have. 1659 */ 1660 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1661 1662 /** 1663 * Base View state sets 1664 */ 1665 // Singles 1666 /** 1667 * Indicates the view has no states set. States are used with 1668 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1669 * view depending on its state. 1670 * 1671 * @see android.graphics.drawable.Drawable 1672 * @see #getDrawableState() 1673 */ 1674 protected static final int[] EMPTY_STATE_SET; 1675 /** 1676 * Indicates the view is enabled. States are used with 1677 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1678 * view depending on its state. 1679 * 1680 * @see android.graphics.drawable.Drawable 1681 * @see #getDrawableState() 1682 */ 1683 protected static final int[] ENABLED_STATE_SET; 1684 /** 1685 * Indicates the view is focused. States are used with 1686 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1687 * view depending on its state. 1688 * 1689 * @see android.graphics.drawable.Drawable 1690 * @see #getDrawableState() 1691 */ 1692 protected static final int[] FOCUSED_STATE_SET; 1693 /** 1694 * Indicates the view is selected. States are used with 1695 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1696 * view depending on its state. 1697 * 1698 * @see android.graphics.drawable.Drawable 1699 * @see #getDrawableState() 1700 */ 1701 protected static final int[] SELECTED_STATE_SET; 1702 /** 1703 * Indicates the view is pressed. States are used with 1704 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1705 * view depending on its state. 1706 * 1707 * @see android.graphics.drawable.Drawable 1708 * @see #getDrawableState() 1709 */ 1710 protected static final int[] PRESSED_STATE_SET; 1711 /** 1712 * Indicates the view's window has focus. States are used with 1713 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1714 * view depending on its state. 1715 * 1716 * @see android.graphics.drawable.Drawable 1717 * @see #getDrawableState() 1718 */ 1719 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1720 // Doubles 1721 /** 1722 * Indicates the view is enabled and has the focus. 1723 * 1724 * @see #ENABLED_STATE_SET 1725 * @see #FOCUSED_STATE_SET 1726 */ 1727 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1728 /** 1729 * Indicates the view is enabled and selected. 1730 * 1731 * @see #ENABLED_STATE_SET 1732 * @see #SELECTED_STATE_SET 1733 */ 1734 protected static final int[] ENABLED_SELECTED_STATE_SET; 1735 /** 1736 * Indicates the view is enabled and that its window has focus. 1737 * 1738 * @see #ENABLED_STATE_SET 1739 * @see #WINDOW_FOCUSED_STATE_SET 1740 */ 1741 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1742 /** 1743 * Indicates the view is focused and selected. 1744 * 1745 * @see #FOCUSED_STATE_SET 1746 * @see #SELECTED_STATE_SET 1747 */ 1748 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1749 /** 1750 * Indicates the view has the focus and that its window has the focus. 1751 * 1752 * @see #FOCUSED_STATE_SET 1753 * @see #WINDOW_FOCUSED_STATE_SET 1754 */ 1755 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1756 /** 1757 * Indicates the view is selected and that its window has the focus. 1758 * 1759 * @see #SELECTED_STATE_SET 1760 * @see #WINDOW_FOCUSED_STATE_SET 1761 */ 1762 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1763 // Triples 1764 /** 1765 * Indicates the view is enabled, focused and selected. 1766 * 1767 * @see #ENABLED_STATE_SET 1768 * @see #FOCUSED_STATE_SET 1769 * @see #SELECTED_STATE_SET 1770 */ 1771 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1772 /** 1773 * Indicates the view is enabled, focused and its window has the focus. 1774 * 1775 * @see #ENABLED_STATE_SET 1776 * @see #FOCUSED_STATE_SET 1777 * @see #WINDOW_FOCUSED_STATE_SET 1778 */ 1779 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1780 /** 1781 * Indicates the view is enabled, selected and its window has the focus. 1782 * 1783 * @see #ENABLED_STATE_SET 1784 * @see #SELECTED_STATE_SET 1785 * @see #WINDOW_FOCUSED_STATE_SET 1786 */ 1787 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1788 /** 1789 * Indicates the view is focused, selected and its window has the focus. 1790 * 1791 * @see #FOCUSED_STATE_SET 1792 * @see #SELECTED_STATE_SET 1793 * @see #WINDOW_FOCUSED_STATE_SET 1794 */ 1795 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1796 /** 1797 * Indicates the view is enabled, focused, selected and its window 1798 * has the focus. 1799 * 1800 * @see #ENABLED_STATE_SET 1801 * @see #FOCUSED_STATE_SET 1802 * @see #SELECTED_STATE_SET 1803 * @see #WINDOW_FOCUSED_STATE_SET 1804 */ 1805 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1806 /** 1807 * Indicates the view is pressed and its window has the focus. 1808 * 1809 * @see #PRESSED_STATE_SET 1810 * @see #WINDOW_FOCUSED_STATE_SET 1811 */ 1812 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1813 /** 1814 * Indicates the view is pressed and selected. 1815 * 1816 * @see #PRESSED_STATE_SET 1817 * @see #SELECTED_STATE_SET 1818 */ 1819 protected static final int[] PRESSED_SELECTED_STATE_SET; 1820 /** 1821 * Indicates the view is pressed, selected and its window has the focus. 1822 * 1823 * @see #PRESSED_STATE_SET 1824 * @see #SELECTED_STATE_SET 1825 * @see #WINDOW_FOCUSED_STATE_SET 1826 */ 1827 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1828 /** 1829 * Indicates the view is pressed and focused. 1830 * 1831 * @see #PRESSED_STATE_SET 1832 * @see #FOCUSED_STATE_SET 1833 */ 1834 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1835 /** 1836 * Indicates the view is pressed, focused and its window has the focus. 1837 * 1838 * @see #PRESSED_STATE_SET 1839 * @see #FOCUSED_STATE_SET 1840 * @see #WINDOW_FOCUSED_STATE_SET 1841 */ 1842 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1843 /** 1844 * Indicates the view is pressed, focused and selected. 1845 * 1846 * @see #PRESSED_STATE_SET 1847 * @see #SELECTED_STATE_SET 1848 * @see #FOCUSED_STATE_SET 1849 */ 1850 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1851 /** 1852 * Indicates the view is pressed, focused, selected and its window has the focus. 1853 * 1854 * @see #PRESSED_STATE_SET 1855 * @see #FOCUSED_STATE_SET 1856 * @see #SELECTED_STATE_SET 1857 * @see #WINDOW_FOCUSED_STATE_SET 1858 */ 1859 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1860 /** 1861 * Indicates the view is pressed and enabled. 1862 * 1863 * @see #PRESSED_STATE_SET 1864 * @see #ENABLED_STATE_SET 1865 */ 1866 protected static final int[] PRESSED_ENABLED_STATE_SET; 1867 /** 1868 * Indicates the view is pressed, enabled and its window has the focus. 1869 * 1870 * @see #PRESSED_STATE_SET 1871 * @see #ENABLED_STATE_SET 1872 * @see #WINDOW_FOCUSED_STATE_SET 1873 */ 1874 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1875 /** 1876 * Indicates the view is pressed, enabled and selected. 1877 * 1878 * @see #PRESSED_STATE_SET 1879 * @see #ENABLED_STATE_SET 1880 * @see #SELECTED_STATE_SET 1881 */ 1882 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1883 /** 1884 * Indicates the view is pressed, enabled, selected and its window has the 1885 * focus. 1886 * 1887 * @see #PRESSED_STATE_SET 1888 * @see #ENABLED_STATE_SET 1889 * @see #SELECTED_STATE_SET 1890 * @see #WINDOW_FOCUSED_STATE_SET 1891 */ 1892 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1893 /** 1894 * Indicates the view is pressed, enabled and focused. 1895 * 1896 * @see #PRESSED_STATE_SET 1897 * @see #ENABLED_STATE_SET 1898 * @see #FOCUSED_STATE_SET 1899 */ 1900 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1901 /** 1902 * Indicates the view is pressed, enabled, focused and its window has the 1903 * focus. 1904 * 1905 * @see #PRESSED_STATE_SET 1906 * @see #ENABLED_STATE_SET 1907 * @see #FOCUSED_STATE_SET 1908 * @see #WINDOW_FOCUSED_STATE_SET 1909 */ 1910 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1911 /** 1912 * Indicates the view is pressed, enabled, focused and selected. 1913 * 1914 * @see #PRESSED_STATE_SET 1915 * @see #ENABLED_STATE_SET 1916 * @see #SELECTED_STATE_SET 1917 * @see #FOCUSED_STATE_SET 1918 */ 1919 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1920 /** 1921 * Indicates the view is pressed, enabled, focused, selected and its window 1922 * has the focus. 1923 * 1924 * @see #PRESSED_STATE_SET 1925 * @see #ENABLED_STATE_SET 1926 * @see #SELECTED_STATE_SET 1927 * @see #FOCUSED_STATE_SET 1928 * @see #WINDOW_FOCUSED_STATE_SET 1929 */ 1930 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1931 1932 static { 1933 EMPTY_STATE_SET = StateSet.get(0); 1934 1935 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1936 1937 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1938 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1939 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1940 1941 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1942 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1943 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1944 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1945 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1946 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1947 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1948 | StateSet.VIEW_STATE_FOCUSED); 1949 1950 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1951 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1952 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1953 ENABLED_SELECTED_STATE_SET = StateSet.get( 1954 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1955 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1956 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1957 | StateSet.VIEW_STATE_ENABLED); 1958 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1959 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1960 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1961 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1962 | StateSet.VIEW_STATE_ENABLED); 1963 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1964 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1965 | StateSet.VIEW_STATE_ENABLED); 1966 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1967 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1968 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1969 1970 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1971 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1972 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1973 PRESSED_SELECTED_STATE_SET = StateSet.get( 1974 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1975 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1976 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1977 | StateSet.VIEW_STATE_PRESSED); 1978 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1979 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1980 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1981 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1982 | StateSet.VIEW_STATE_PRESSED); 1983 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1984 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1985 | StateSet.VIEW_STATE_PRESSED); 1986 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1987 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1988 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1989 PRESSED_ENABLED_STATE_SET = StateSet.get( 1990 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1991 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1992 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1993 | StateSet.VIEW_STATE_PRESSED); 1994 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1995 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1996 | StateSet.VIEW_STATE_PRESSED); 1997 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1998 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1999 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2000 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2001 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2002 | StateSet.VIEW_STATE_PRESSED); 2003 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2004 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2005 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2006 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2007 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2008 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2009 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2010 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2011 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2012 | StateSet.VIEW_STATE_PRESSED); 2013 } 2014 2015 /** 2016 * Accessibility event types that are dispatched for text population. 2017 */ 2018 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2019 AccessibilityEvent.TYPE_VIEW_CLICKED 2020 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2021 | AccessibilityEvent.TYPE_VIEW_SELECTED 2022 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2023 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2024 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2025 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2026 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2027 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2028 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2029 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2030 2031 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2032 2033 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2034 2035 /** 2036 * Temporary Rect currently for use in setBackground(). This will probably 2037 * be extended in the future to hold our own class with more than just 2038 * a Rect. :) 2039 */ 2040 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 2041 2042 /** 2043 * Map used to store views' tags. 2044 */ 2045 private SparseArray<Object> mKeyedTags; 2046 2047 /** 2048 * The animation currently associated with this view. 2049 * @hide 2050 */ 2051 protected Animation mCurrentAnimation = null; 2052 2053 /** 2054 * Width as measured during measure pass. 2055 * {@hide} 2056 */ 2057 @ViewDebug.ExportedProperty(category = "measurement") 2058 int mMeasuredWidth; 2059 2060 /** 2061 * Height as measured during measure pass. 2062 * {@hide} 2063 */ 2064 @ViewDebug.ExportedProperty(category = "measurement") 2065 int mMeasuredHeight; 2066 2067 /** 2068 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2069 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2070 * its display list. This flag, used only when hw accelerated, allows us to clear the 2071 * flag while retaining this information until it's needed (at getDisplayList() time and 2072 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2073 * 2074 * {@hide} 2075 */ 2076 boolean mRecreateDisplayList = false; 2077 2078 /** 2079 * The view's identifier. 2080 * {@hide} 2081 * 2082 * @see #setId(int) 2083 * @see #getId() 2084 */ 2085 @IdRes 2086 @ViewDebug.ExportedProperty(resolveId = true) 2087 int mID = NO_ID; 2088 2089 /** The ID of this view for accessibility and autofill purposes. 2090 * <ul> 2091 * <li>== {@link #NO_ID}: ID has not been assigned yet 2092 * <li>≤ {@link #LAST_APP_ACCESSIBILITY_ID}: View is not part of a activity. The ID is 2093 * unique in the process. This might change 2094 * over activity lifecycle events. 2095 * <li>> {@link #LAST_APP_ACCESSIBILITY_ID}: View is part of a activity. The ID is 2096 * unique in the activity. This stays the same 2097 * over activity lifecycle events. 2098 */ 2099 private int mAccessibilityViewId = NO_ID; 2100 2101 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2102 2103 SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent; 2104 2105 /** 2106 * The view's tag. 2107 * {@hide} 2108 * 2109 * @see #setTag(Object) 2110 * @see #getTag() 2111 */ 2112 protected Object mTag = null; 2113 2114 // for mPrivateFlags: 2115 /** {@hide} */ 2116 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2117 /** {@hide} */ 2118 static final int PFLAG_FOCUSED = 0x00000002; 2119 /** {@hide} */ 2120 static final int PFLAG_SELECTED = 0x00000004; 2121 /** {@hide} */ 2122 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2123 /** {@hide} */ 2124 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2125 /** {@hide} */ 2126 static final int PFLAG_DRAWN = 0x00000020; 2127 /** 2128 * When this flag is set, this view is running an animation on behalf of its 2129 * children and should therefore not cancel invalidate requests, even if they 2130 * lie outside of this view's bounds. 2131 * 2132 * {@hide} 2133 */ 2134 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2135 /** {@hide} */ 2136 static final int PFLAG_SKIP_DRAW = 0x00000080; 2137 /** {@hide} */ 2138 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2139 /** {@hide} */ 2140 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2141 /** {@hide} */ 2142 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2143 /** {@hide} */ 2144 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2145 /** {@hide} */ 2146 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2147 2148 private static final int PFLAG_PRESSED = 0x00004000; 2149 2150 /** {@hide} */ 2151 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2152 /** 2153 * Flag used to indicate that this view should be drawn once more (and only once 2154 * more) after its animation has completed. 2155 * {@hide} 2156 */ 2157 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2158 2159 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2160 2161 /** 2162 * Indicates that the View returned true when onSetAlpha() was called and that 2163 * the alpha must be restored. 2164 * {@hide} 2165 */ 2166 static final int PFLAG_ALPHA_SET = 0x00040000; 2167 2168 /** 2169 * Set by {@link #setScrollContainer(boolean)}. 2170 */ 2171 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2172 2173 /** 2174 * Set by {@link #setScrollContainer(boolean)}. 2175 */ 2176 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2177 2178 /** 2179 * View flag indicating whether this view was invalidated (fully or partially.) 2180 * 2181 * @hide 2182 */ 2183 static final int PFLAG_DIRTY = 0x00200000; 2184 2185 /** 2186 * View flag indicating whether this view was invalidated by an opaque 2187 * invalidate request. 2188 * 2189 * @hide 2190 */ 2191 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 2192 2193 /** 2194 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 2195 * 2196 * @hide 2197 */ 2198 static final int PFLAG_DIRTY_MASK = 0x00600000; 2199 2200 /** 2201 * Indicates whether the background is opaque. 2202 * 2203 * @hide 2204 */ 2205 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2206 2207 /** 2208 * Indicates whether the scrollbars are opaque. 2209 * 2210 * @hide 2211 */ 2212 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2213 2214 /** 2215 * Indicates whether the view is opaque. 2216 * 2217 * @hide 2218 */ 2219 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2220 2221 /** 2222 * Indicates a prepressed state; 2223 * the short time between ACTION_DOWN and recognizing 2224 * a 'real' press. Prepressed is used to recognize quick taps 2225 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2226 * 2227 * @hide 2228 */ 2229 private static final int PFLAG_PREPRESSED = 0x02000000; 2230 2231 /** 2232 * Indicates whether the view is temporarily detached. 2233 * 2234 * @hide 2235 */ 2236 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2237 2238 /** 2239 * Indicates that we should awaken scroll bars once attached 2240 * 2241 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2242 * during window attachment and it is no longer needed. Feel free to repurpose it. 2243 * 2244 * @hide 2245 */ 2246 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2247 2248 /** 2249 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2250 * @hide 2251 */ 2252 private static final int PFLAG_HOVERED = 0x10000000; 2253 2254 /** 2255 * no longer needed, should be reused 2256 */ 2257 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 2258 2259 /** {@hide} */ 2260 static final int PFLAG_ACTIVATED = 0x40000000; 2261 2262 /** 2263 * Indicates that this view was specifically invalidated, not just dirtied because some 2264 * child view was invalidated. The flag is used to determine when we need to recreate 2265 * a view's display list (as opposed to just returning a reference to its existing 2266 * display list). 2267 * 2268 * @hide 2269 */ 2270 static final int PFLAG_INVALIDATED = 0x80000000; 2271 2272 /** 2273 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2274 * 2275 * |-------|-------|-------|-------| 2276 * 1 PFLAG2_DRAG_CAN_ACCEPT 2277 * 1 PFLAG2_DRAG_HOVERED 2278 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2279 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2280 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2281 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2282 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2283 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2284 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2285 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2286 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2287 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2288 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2289 * 111 PFLAG2_TEXT_DIRECTION_MASK 2290 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2291 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2292 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2293 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2294 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2295 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2296 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2297 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2298 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2299 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2300 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2301 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2302 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2303 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2304 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2305 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2306 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2307 * 1 PFLAG2_VIEW_QUICK_REJECTED 2308 * 1 PFLAG2_PADDING_RESOLVED 2309 * 1 PFLAG2_DRAWABLE_RESOLVED 2310 * 1 PFLAG2_HAS_TRANSIENT_STATE 2311 * |-------|-------|-------|-------| 2312 */ 2313 2314 /** 2315 * Indicates that this view has reported that it can accept the current drag's content. 2316 * Cleared when the drag operation concludes. 2317 * @hide 2318 */ 2319 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2320 2321 /** 2322 * Indicates that this view is currently directly under the drag location in a 2323 * drag-and-drop operation involving content that it can accept. Cleared when 2324 * the drag exits the view, or when the drag operation concludes. 2325 * @hide 2326 */ 2327 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2328 2329 /** @hide */ 2330 @IntDef({ 2331 LAYOUT_DIRECTION_LTR, 2332 LAYOUT_DIRECTION_RTL, 2333 LAYOUT_DIRECTION_INHERIT, 2334 LAYOUT_DIRECTION_LOCALE 2335 }) 2336 @Retention(RetentionPolicy.SOURCE) 2337 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2338 public @interface LayoutDir {} 2339 2340 /** @hide */ 2341 @IntDef({ 2342 LAYOUT_DIRECTION_LTR, 2343 LAYOUT_DIRECTION_RTL 2344 }) 2345 @Retention(RetentionPolicy.SOURCE) 2346 public @interface ResolvedLayoutDir {} 2347 2348 /** 2349 * A flag to indicate that the layout direction of this view has not been defined yet. 2350 * @hide 2351 */ 2352 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2353 2354 /** 2355 * Horizontal layout direction of this view is from Left to Right. 2356 * Use with {@link #setLayoutDirection}. 2357 */ 2358 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2359 2360 /** 2361 * Horizontal layout direction of this view is from Right to Left. 2362 * Use with {@link #setLayoutDirection}. 2363 */ 2364 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2365 2366 /** 2367 * Horizontal layout direction of this view is inherited from its parent. 2368 * Use with {@link #setLayoutDirection}. 2369 */ 2370 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2371 2372 /** 2373 * Horizontal layout direction of this view is from deduced from the default language 2374 * script for the locale. Use with {@link #setLayoutDirection}. 2375 */ 2376 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2377 2378 /** 2379 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2380 * @hide 2381 */ 2382 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2383 2384 /** 2385 * Mask for use with private flags indicating bits used for horizontal layout direction. 2386 * @hide 2387 */ 2388 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2389 2390 /** 2391 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2392 * right-to-left direction. 2393 * @hide 2394 */ 2395 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2396 2397 /** 2398 * Indicates whether the view horizontal layout direction has been resolved. 2399 * @hide 2400 */ 2401 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2402 2403 /** 2404 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2405 * @hide 2406 */ 2407 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2408 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2409 2410 /* 2411 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2412 * flag value. 2413 * @hide 2414 */ 2415 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2416 LAYOUT_DIRECTION_LTR, 2417 LAYOUT_DIRECTION_RTL, 2418 LAYOUT_DIRECTION_INHERIT, 2419 LAYOUT_DIRECTION_LOCALE 2420 }; 2421 2422 /** 2423 * Default horizontal layout direction. 2424 */ 2425 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2426 2427 /** 2428 * Default horizontal layout direction. 2429 * @hide 2430 */ 2431 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2432 2433 /** 2434 * Text direction is inherited through {@link ViewGroup} 2435 */ 2436 public static final int TEXT_DIRECTION_INHERIT = 0; 2437 2438 /** 2439 * Text direction is using "first strong algorithm". The first strong directional character 2440 * determines the paragraph direction. If there is no strong directional character, the 2441 * paragraph direction is the view's resolved layout direction. 2442 */ 2443 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2444 2445 /** 2446 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2447 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2448 * If there are neither, the paragraph direction is the view's resolved layout direction. 2449 */ 2450 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2451 2452 /** 2453 * Text direction is forced to LTR. 2454 */ 2455 public static final int TEXT_DIRECTION_LTR = 3; 2456 2457 /** 2458 * Text direction is forced to RTL. 2459 */ 2460 public static final int TEXT_DIRECTION_RTL = 4; 2461 2462 /** 2463 * Text direction is coming from the system Locale. 2464 */ 2465 public static final int TEXT_DIRECTION_LOCALE = 5; 2466 2467 /** 2468 * Text direction is using "first strong algorithm". The first strong directional character 2469 * determines the paragraph direction. If there is no strong directional character, the 2470 * paragraph direction is LTR. 2471 */ 2472 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2473 2474 /** 2475 * Text direction is using "first strong algorithm". The first strong directional character 2476 * determines the paragraph direction. If there is no strong directional character, the 2477 * paragraph direction is RTL. 2478 */ 2479 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2480 2481 /** 2482 * Default text direction is inherited 2483 */ 2484 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2485 2486 /** 2487 * Default resolved text direction 2488 * @hide 2489 */ 2490 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2491 2492 /** 2493 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2494 * @hide 2495 */ 2496 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2497 2498 /** 2499 * Mask for use with private flags indicating bits used for text direction. 2500 * @hide 2501 */ 2502 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2503 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2504 2505 /** 2506 * Array of text direction flags for mapping attribute "textDirection" to correct 2507 * flag value. 2508 * @hide 2509 */ 2510 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2511 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2512 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2513 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2514 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2515 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2516 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2517 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2518 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2519 }; 2520 2521 /** 2522 * Indicates whether the view text direction has been resolved. 2523 * @hide 2524 */ 2525 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2526 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2527 2528 /** 2529 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2530 * @hide 2531 */ 2532 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2533 2534 /** 2535 * Mask for use with private flags indicating bits used for resolved text direction. 2536 * @hide 2537 */ 2538 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2539 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2540 2541 /** 2542 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2543 * @hide 2544 */ 2545 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2546 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2547 2548 /** @hide */ 2549 @IntDef({ 2550 TEXT_ALIGNMENT_INHERIT, 2551 TEXT_ALIGNMENT_GRAVITY, 2552 TEXT_ALIGNMENT_CENTER, 2553 TEXT_ALIGNMENT_TEXT_START, 2554 TEXT_ALIGNMENT_TEXT_END, 2555 TEXT_ALIGNMENT_VIEW_START, 2556 TEXT_ALIGNMENT_VIEW_END 2557 }) 2558 @Retention(RetentionPolicy.SOURCE) 2559 public @interface TextAlignment {} 2560 2561 /** 2562 * Default text alignment. The text alignment of this View is inherited from its parent. 2563 * Use with {@link #setTextAlignment(int)} 2564 */ 2565 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2566 2567 /** 2568 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2569 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2570 * 2571 * Use with {@link #setTextAlignment(int)} 2572 */ 2573 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2574 2575 /** 2576 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2577 * 2578 * Use with {@link #setTextAlignment(int)} 2579 */ 2580 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2581 2582 /** 2583 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2584 * 2585 * Use with {@link #setTextAlignment(int)} 2586 */ 2587 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2588 2589 /** 2590 * Center the paragraph, e.g. ALIGN_CENTER. 2591 * 2592 * Use with {@link #setTextAlignment(int)} 2593 */ 2594 public static final int TEXT_ALIGNMENT_CENTER = 4; 2595 2596 /** 2597 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2598 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2599 * 2600 * Use with {@link #setTextAlignment(int)} 2601 */ 2602 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2603 2604 /** 2605 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2606 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2607 * 2608 * Use with {@link #setTextAlignment(int)} 2609 */ 2610 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2611 2612 /** 2613 * Default text alignment is inherited 2614 */ 2615 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2616 2617 /** 2618 * Default resolved text alignment 2619 * @hide 2620 */ 2621 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2622 2623 /** 2624 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2625 * @hide 2626 */ 2627 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2628 2629 /** 2630 * Mask for use with private flags indicating bits used for text alignment. 2631 * @hide 2632 */ 2633 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2634 2635 /** 2636 * Array of text direction flags for mapping attribute "textAlignment" to correct 2637 * flag value. 2638 * @hide 2639 */ 2640 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2641 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2642 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2643 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2644 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2645 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2646 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2647 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2648 }; 2649 2650 /** 2651 * Indicates whether the view text alignment has been resolved. 2652 * @hide 2653 */ 2654 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2655 2656 /** 2657 * Bit shift to get the resolved text alignment. 2658 * @hide 2659 */ 2660 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2661 2662 /** 2663 * Mask for use with private flags indicating bits used for text alignment. 2664 * @hide 2665 */ 2666 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2667 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2668 2669 /** 2670 * Indicates whether if the view text alignment has been resolved to gravity 2671 */ 2672 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2673 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2674 2675 // Accessiblity constants for mPrivateFlags2 2676 2677 /** 2678 * Shift for the bits in {@link #mPrivateFlags2} related to the 2679 * "importantForAccessibility" attribute. 2680 */ 2681 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2682 2683 /** 2684 * Automatically determine whether a view is important for accessibility. 2685 */ 2686 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2687 2688 /** 2689 * The view is important for accessibility. 2690 */ 2691 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2692 2693 /** 2694 * The view is not important for accessibility. 2695 */ 2696 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2697 2698 /** 2699 * The view is not important for accessibility, nor are any of its 2700 * descendant views. 2701 */ 2702 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2703 2704 /** 2705 * The default whether the view is important for accessibility. 2706 */ 2707 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2708 2709 /** 2710 * Mask for obtaining the bits which specify how to determine 2711 * whether a view is important for accessibility. 2712 */ 2713 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2714 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2715 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2716 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2717 2718 /** 2719 * Shift for the bits in {@link #mPrivateFlags2} related to the 2720 * "accessibilityLiveRegion" attribute. 2721 */ 2722 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2723 2724 /** 2725 * Live region mode specifying that accessibility services should not 2726 * automatically announce changes to this view. This is the default live 2727 * region mode for most views. 2728 * <p> 2729 * Use with {@link #setAccessibilityLiveRegion(int)}. 2730 */ 2731 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2732 2733 /** 2734 * Live region mode specifying that accessibility services should announce 2735 * changes to this view. 2736 * <p> 2737 * Use with {@link #setAccessibilityLiveRegion(int)}. 2738 */ 2739 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2740 2741 /** 2742 * Live region mode specifying that accessibility services should interrupt 2743 * ongoing speech to immediately announce changes to this view. 2744 * <p> 2745 * Use with {@link #setAccessibilityLiveRegion(int)}. 2746 */ 2747 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2748 2749 /** 2750 * The default whether the view is important for accessibility. 2751 */ 2752 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2753 2754 /** 2755 * Mask for obtaining the bits which specify a view's accessibility live 2756 * region mode. 2757 */ 2758 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2759 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2760 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2761 2762 /** 2763 * Flag indicating whether a view has accessibility focus. 2764 */ 2765 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2766 2767 /** 2768 * Flag whether the accessibility state of the subtree rooted at this view changed. 2769 */ 2770 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2771 2772 /** 2773 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2774 * is used to check whether later changes to the view's transform should invalidate the 2775 * view to force the quickReject test to run again. 2776 */ 2777 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2778 2779 /** 2780 * Flag indicating that start/end padding has been resolved into left/right padding 2781 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2782 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2783 * during measurement. In some special cases this is required such as when an adapter-based 2784 * view measures prospective children without attaching them to a window. 2785 */ 2786 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2787 2788 /** 2789 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2790 */ 2791 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2792 2793 /** 2794 * Indicates that the view is tracking some sort of transient state 2795 * that the app should not need to be aware of, but that the framework 2796 * should take special care to preserve. 2797 */ 2798 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2799 2800 /** 2801 * Group of bits indicating that RTL properties resolution is done. 2802 */ 2803 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2804 PFLAG2_TEXT_DIRECTION_RESOLVED | 2805 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2806 PFLAG2_PADDING_RESOLVED | 2807 PFLAG2_DRAWABLE_RESOLVED; 2808 2809 // There are a couple of flags left in mPrivateFlags2 2810 2811 /* End of masks for mPrivateFlags2 */ 2812 2813 /** 2814 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2815 * 2816 * |-------|-------|-------|-------| 2817 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2818 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2819 * 1 PFLAG3_IS_LAID_OUT 2820 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2821 * 1 PFLAG3_CALLED_SUPER 2822 * 1 PFLAG3_APPLYING_INSETS 2823 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2824 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2825 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2826 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2827 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2828 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2829 * 1 PFLAG3_SCROLL_INDICATOR_START 2830 * 1 PFLAG3_SCROLL_INDICATOR_END 2831 * 1 PFLAG3_ASSIST_BLOCKED 2832 * 1 PFLAG3_CLUSTER 2833 * 1 PFLAG3_IS_AUTOFILLED 2834 * 1 PFLAG3_FINGER_DOWN 2835 * 1 PFLAG3_FOCUSED_BY_DEFAULT 2836 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 2837 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2838 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2839 * 1 PFLAG3_TEMPORARY_DETACH 2840 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2841 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 2842 * |-------|-------|-------|-------| 2843 */ 2844 2845 /** 2846 * Flag indicating that view has a transform animation set on it. This is used to track whether 2847 * an animation is cleared between successive frames, in order to tell the associated 2848 * DisplayList to clear its animation matrix. 2849 */ 2850 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2851 2852 /** 2853 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2854 * animation is cleared between successive frames, in order to tell the associated 2855 * DisplayList to restore its alpha value. 2856 */ 2857 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2858 2859 /** 2860 * Flag indicating that the view has been through at least one layout since it 2861 * was last attached to a window. 2862 */ 2863 static final int PFLAG3_IS_LAID_OUT = 0x4; 2864 2865 /** 2866 * Flag indicating that a call to measure() was skipped and should be done 2867 * instead when layout() is invoked. 2868 */ 2869 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2870 2871 /** 2872 * Flag indicating that an overridden method correctly called down to 2873 * the superclass implementation as required by the API spec. 2874 */ 2875 static final int PFLAG3_CALLED_SUPER = 0x10; 2876 2877 /** 2878 * Flag indicating that we're in the process of applying window insets. 2879 */ 2880 static final int PFLAG3_APPLYING_INSETS = 0x20; 2881 2882 /** 2883 * Flag indicating that we're in the process of fitting system windows using the old method. 2884 */ 2885 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2886 2887 /** 2888 * Flag indicating that nested scrolling is enabled for this view. 2889 * The view will optionally cooperate with views up its parent chain to allow for 2890 * integrated nested scrolling along the same axis. 2891 */ 2892 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2893 2894 /** 2895 * Flag indicating that the bottom scroll indicator should be displayed 2896 * when this view can scroll up. 2897 */ 2898 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2899 2900 /** 2901 * Flag indicating that the bottom scroll indicator should be displayed 2902 * when this view can scroll down. 2903 */ 2904 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2905 2906 /** 2907 * Flag indicating that the left scroll indicator should be displayed 2908 * when this view can scroll left. 2909 */ 2910 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2911 2912 /** 2913 * Flag indicating that the right scroll indicator should be displayed 2914 * when this view can scroll right. 2915 */ 2916 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2917 2918 /** 2919 * Flag indicating that the start scroll indicator should be displayed 2920 * when this view can scroll in the start direction. 2921 */ 2922 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2923 2924 /** 2925 * Flag indicating that the end scroll indicator should be displayed 2926 * when this view can scroll in the end direction. 2927 */ 2928 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2929 2930 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2931 2932 static final int SCROLL_INDICATORS_NONE = 0x0000; 2933 2934 /** 2935 * Mask for use with setFlags indicating bits used for indicating which 2936 * scroll indicators are enabled. 2937 */ 2938 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2939 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2940 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2941 | PFLAG3_SCROLL_INDICATOR_END; 2942 2943 /** 2944 * Left-shift required to translate between public scroll indicator flags 2945 * and internal PFLAGS3 flags. When used as a right-shift, translates 2946 * PFLAGS3 flags to public flags. 2947 */ 2948 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2949 2950 /** @hide */ 2951 @Retention(RetentionPolicy.SOURCE) 2952 @IntDef(flag = true, 2953 value = { 2954 SCROLL_INDICATOR_TOP, 2955 SCROLL_INDICATOR_BOTTOM, 2956 SCROLL_INDICATOR_LEFT, 2957 SCROLL_INDICATOR_RIGHT, 2958 SCROLL_INDICATOR_START, 2959 SCROLL_INDICATOR_END, 2960 }) 2961 public @interface ScrollIndicators {} 2962 2963 /** 2964 * Scroll indicator direction for the top edge of the view. 2965 * 2966 * @see #setScrollIndicators(int) 2967 * @see #setScrollIndicators(int, int) 2968 * @see #getScrollIndicators() 2969 */ 2970 public static final int SCROLL_INDICATOR_TOP = 2971 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2972 2973 /** 2974 * Scroll indicator direction for the bottom edge of the view. 2975 * 2976 * @see #setScrollIndicators(int) 2977 * @see #setScrollIndicators(int, int) 2978 * @see #getScrollIndicators() 2979 */ 2980 public static final int SCROLL_INDICATOR_BOTTOM = 2981 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2982 2983 /** 2984 * Scroll indicator direction for the left edge of the view. 2985 * 2986 * @see #setScrollIndicators(int) 2987 * @see #setScrollIndicators(int, int) 2988 * @see #getScrollIndicators() 2989 */ 2990 public static final int SCROLL_INDICATOR_LEFT = 2991 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2992 2993 /** 2994 * Scroll indicator direction for the right edge of the view. 2995 * 2996 * @see #setScrollIndicators(int) 2997 * @see #setScrollIndicators(int, int) 2998 * @see #getScrollIndicators() 2999 */ 3000 public static final int SCROLL_INDICATOR_RIGHT = 3001 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3002 3003 /** 3004 * Scroll indicator direction for the starting edge of the view. 3005 * <p> 3006 * Resolved according to the view's layout direction, see 3007 * {@link #getLayoutDirection()} for more information. 3008 * 3009 * @see #setScrollIndicators(int) 3010 * @see #setScrollIndicators(int, int) 3011 * @see #getScrollIndicators() 3012 */ 3013 public static final int SCROLL_INDICATOR_START = 3014 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3015 3016 /** 3017 * Scroll indicator direction for the ending edge of the view. 3018 * <p> 3019 * Resolved according to the view's layout direction, see 3020 * {@link #getLayoutDirection()} for more information. 3021 * 3022 * @see #setScrollIndicators(int) 3023 * @see #setScrollIndicators(int, int) 3024 * @see #getScrollIndicators() 3025 */ 3026 public static final int SCROLL_INDICATOR_END = 3027 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3028 3029 /** 3030 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3031 * into this view.<p> 3032 */ 3033 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3034 3035 /** 3036 * Flag indicating that the view is a root of a keyboard navigation cluster. 3037 * 3038 * @see #isKeyboardNavigationCluster() 3039 * @see #setKeyboardNavigationCluster(boolean) 3040 */ 3041 private static final int PFLAG3_CLUSTER = 0x8000; 3042 3043 /** 3044 * Flag indicating that the view is autofilled 3045 * 3046 * @see #isAutofilled() 3047 * @see #setAutofilled(boolean) 3048 */ 3049 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3050 3051 /** 3052 * Indicates that the user is currently touching the screen. 3053 * Currently used for the tooltip positioning only. 3054 */ 3055 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3056 3057 /** 3058 * Flag indicating that this view is the default-focus view. 3059 * 3060 * @see #isFocusedByDefault() 3061 * @see #setFocusedByDefault(boolean) 3062 */ 3063 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3064 3065 /** 3066 * Shift for the bits in {@link #mPrivateFlags3} related to the 3067 * "importantForAutofill" attribute. 3068 */ 3069 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3070 3071 /** 3072 * Mask for obtaining the bits which specify how to determine 3073 * whether a view is important for autofill. 3074 */ 3075 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3076 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3077 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3078 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3079 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3080 3081 /** 3082 * Whether this view has rendered elements that overlap (see {@link 3083 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3084 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3085 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3086 * determined by whatever {@link #hasOverlappingRendering()} returns. 3087 */ 3088 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3089 3090 /** 3091 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3092 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3093 */ 3094 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3095 3096 /** 3097 * Flag indicating that the view is temporarily detached from the parent view. 3098 * 3099 * @see #onStartTemporaryDetach() 3100 * @see #onFinishTemporaryDetach() 3101 */ 3102 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3103 3104 /** 3105 * Flag indicating that the view does not wish to be revealed within its parent 3106 * hierarchy when it gains focus. Expressed in the negative since the historical 3107 * default behavior is to reveal on focus; this flag suppresses that behavior. 3108 * 3109 * @see #setRevealOnFocusHint(boolean) 3110 * @see #getRevealOnFocusHint() 3111 */ 3112 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3113 3114 /** 3115 * Flag indicating that when layout is completed we should notify 3116 * that the view was entered for autofill purposes. To minimize 3117 * showing autofill for views not visible to the user we evaluate 3118 * user visibility which cannot be done until the view is laid out. 3119 */ 3120 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3121 3122 /* End of masks for mPrivateFlags3 */ 3123 3124 /** 3125 * Always allow a user to over-scroll this view, provided it is a 3126 * view that can scroll. 3127 * 3128 * @see #getOverScrollMode() 3129 * @see #setOverScrollMode(int) 3130 */ 3131 public static final int OVER_SCROLL_ALWAYS = 0; 3132 3133 /** 3134 * Allow a user to over-scroll this view only if the content is large 3135 * enough to meaningfully scroll, provided it is a view that can scroll. 3136 * 3137 * @see #getOverScrollMode() 3138 * @see #setOverScrollMode(int) 3139 */ 3140 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3141 3142 /** 3143 * Never allow a user to over-scroll this view. 3144 * 3145 * @see #getOverScrollMode() 3146 * @see #setOverScrollMode(int) 3147 */ 3148 public static final int OVER_SCROLL_NEVER = 2; 3149 3150 /** 3151 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3152 * requested the system UI (status bar) to be visible (the default). 3153 * 3154 * @see #setSystemUiVisibility(int) 3155 */ 3156 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3157 3158 /** 3159 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3160 * system UI to enter an unobtrusive "low profile" mode. 3161 * 3162 * <p>This is for use in games, book readers, video players, or any other 3163 * "immersive" application where the usual system chrome is deemed too distracting. 3164 * 3165 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3166 * 3167 * @see #setSystemUiVisibility(int) 3168 */ 3169 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3170 3171 /** 3172 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3173 * system navigation be temporarily hidden. 3174 * 3175 * <p>This is an even less obtrusive state than that called for by 3176 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3177 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3178 * those to disappear. This is useful (in conjunction with the 3179 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3180 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3181 * window flags) for displaying content using every last pixel on the display. 3182 * 3183 * <p>There is a limitation: because navigation controls are so important, the least user 3184 * interaction will cause them to reappear immediately. When this happens, both 3185 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3186 * so that both elements reappear at the same time. 3187 * 3188 * @see #setSystemUiVisibility(int) 3189 */ 3190 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3191 3192 /** 3193 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3194 * into the normal fullscreen mode so that its content can take over the screen 3195 * while still allowing the user to interact with the application. 3196 * 3197 * <p>This has the same visual effect as 3198 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3199 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3200 * meaning that non-critical screen decorations (such as the status bar) will be 3201 * hidden while the user is in the View's window, focusing the experience on 3202 * that content. Unlike the window flag, if you are using ActionBar in 3203 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3204 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3205 * hide the action bar. 3206 * 3207 * <p>This approach to going fullscreen is best used over the window flag when 3208 * it is a transient state -- that is, the application does this at certain 3209 * points in its user interaction where it wants to allow the user to focus 3210 * on content, but not as a continuous state. For situations where the application 3211 * would like to simply stay full screen the entire time (such as a game that 3212 * wants to take over the screen), the 3213 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3214 * is usually a better approach. The state set here will be removed by the system 3215 * in various situations (such as the user moving to another application) like 3216 * the other system UI states. 3217 * 3218 * <p>When using this flag, the application should provide some easy facility 3219 * for the user to go out of it. A common example would be in an e-book 3220 * reader, where tapping on the screen brings back whatever screen and UI 3221 * decorations that had been hidden while the user was immersed in reading 3222 * the book. 3223 * 3224 * @see #setSystemUiVisibility(int) 3225 */ 3226 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3227 3228 /** 3229 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3230 * flags, we would like a stable view of the content insets given to 3231 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3232 * will always represent the worst case that the application can expect 3233 * as a continuous state. In the stock Android UI this is the space for 3234 * the system bar, nav bar, and status bar, but not more transient elements 3235 * such as an input method. 3236 * 3237 * The stable layout your UI sees is based on the system UI modes you can 3238 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3239 * then you will get a stable layout for changes of the 3240 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3241 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3242 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3243 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3244 * with a stable layout. (Note that you should avoid using 3245 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3246 * 3247 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3248 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3249 * then a hidden status bar will be considered a "stable" state for purposes 3250 * here. This allows your UI to continually hide the status bar, while still 3251 * using the system UI flags to hide the action bar while still retaining 3252 * a stable layout. Note that changing the window fullscreen flag will never 3253 * provide a stable layout for a clean transition. 3254 * 3255 * <p>If you are using ActionBar in 3256 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3257 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3258 * insets it adds to those given to the application. 3259 */ 3260 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3261 3262 /** 3263 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3264 * to be laid out as if it has requested 3265 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3266 * allows it to avoid artifacts when switching in and out of that mode, at 3267 * the expense that some of its user interface may be covered by screen 3268 * decorations when they are shown. You can perform layout of your inner 3269 * UI elements to account for the navigation system UI through the 3270 * {@link #fitSystemWindows(Rect)} method. 3271 */ 3272 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3273 3274 /** 3275 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3276 * to be laid out as if it has requested 3277 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3278 * allows it to avoid artifacts when switching in and out of that mode, at 3279 * the expense that some of its user interface may be covered by screen 3280 * decorations when they are shown. You can perform layout of your inner 3281 * UI elements to account for non-fullscreen system UI through the 3282 * {@link #fitSystemWindows(Rect)} method. 3283 */ 3284 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3285 3286 /** 3287 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3288 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3289 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3290 * user interaction. 3291 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3292 * has an effect when used in combination with that flag.</p> 3293 */ 3294 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3295 3296 /** 3297 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3298 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3299 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3300 * experience while also hiding the system bars. If this flag is not set, 3301 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3302 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3303 * if the user swipes from the top of the screen. 3304 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3305 * system gestures, such as swiping from the top of the screen. These transient system bars 3306 * will overlay app’s content, may have some degree of transparency, and will automatically 3307 * hide after a short timeout. 3308 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3309 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3310 * with one or both of those flags.</p> 3311 */ 3312 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3313 3314 /** 3315 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3316 * is compatible with light status bar backgrounds. 3317 * 3318 * <p>For this to take effect, the window must request 3319 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3320 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3321 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3322 * FLAG_TRANSLUCENT_STATUS}. 3323 * 3324 * @see android.R.attr#windowLightStatusBar 3325 */ 3326 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3327 3328 /** 3329 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3330 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3331 */ 3332 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3333 3334 /** 3335 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3336 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3337 */ 3338 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3339 3340 /** 3341 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3342 * that is compatible with light navigation bar backgrounds. 3343 * 3344 * <p>For this to take effect, the window must request 3345 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3346 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3347 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3348 * FLAG_TRANSLUCENT_NAVIGATION}. 3349 */ 3350 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3351 3352 /** 3353 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3354 */ 3355 @Deprecated 3356 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3357 3358 /** 3359 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3360 */ 3361 @Deprecated 3362 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3363 3364 /** 3365 * @hide 3366 * 3367 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3368 * out of the public fields to keep the undefined bits out of the developer's way. 3369 * 3370 * Flag to make the status bar not expandable. Unless you also 3371 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3372 */ 3373 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3374 3375 /** 3376 * @hide 3377 * 3378 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3379 * out of the public fields to keep the undefined bits out of the developer's way. 3380 * 3381 * Flag to hide notification icons and scrolling ticker text. 3382 */ 3383 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3384 3385 /** 3386 * @hide 3387 * 3388 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3389 * out of the public fields to keep the undefined bits out of the developer's way. 3390 * 3391 * Flag to disable incoming notification alerts. This will not block 3392 * icons, but it will block sound, vibrating and other visual or aural notifications. 3393 */ 3394 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3395 3396 /** 3397 * @hide 3398 * 3399 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3400 * out of the public fields to keep the undefined bits out of the developer's way. 3401 * 3402 * Flag to hide only the scrolling ticker. Note that 3403 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3404 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3405 */ 3406 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3407 3408 /** 3409 * @hide 3410 * 3411 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3412 * out of the public fields to keep the undefined bits out of the developer's way. 3413 * 3414 * Flag to hide the center system info area. 3415 */ 3416 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3417 3418 /** 3419 * @hide 3420 * 3421 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3422 * out of the public fields to keep the undefined bits out of the developer's way. 3423 * 3424 * Flag to hide only the home button. Don't use this 3425 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3426 */ 3427 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3428 3429 /** 3430 * @hide 3431 * 3432 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3433 * out of the public fields to keep the undefined bits out of the developer's way. 3434 * 3435 * Flag to hide only the back button. Don't use this 3436 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3437 */ 3438 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3439 3440 /** 3441 * @hide 3442 * 3443 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3444 * out of the public fields to keep the undefined bits out of the developer's way. 3445 * 3446 * Flag to hide only the clock. You might use this if your activity has 3447 * its own clock making the status bar's clock redundant. 3448 */ 3449 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3450 3451 /** 3452 * @hide 3453 * 3454 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3455 * out of the public fields to keep the undefined bits out of the developer's way. 3456 * 3457 * Flag to hide only the recent apps button. Don't use this 3458 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3459 */ 3460 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3461 3462 /** 3463 * @hide 3464 * 3465 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3466 * out of the public fields to keep the undefined bits out of the developer's way. 3467 * 3468 * Flag to disable the global search gesture. Don't use this 3469 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3470 */ 3471 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3472 3473 /** 3474 * @hide 3475 * 3476 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3477 * out of the public fields to keep the undefined bits out of the developer's way. 3478 * 3479 * Flag to specify that the status bar is displayed in transient mode. 3480 */ 3481 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3482 3483 /** 3484 * @hide 3485 * 3486 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3487 * out of the public fields to keep the undefined bits out of the developer's way. 3488 * 3489 * Flag to specify that the navigation bar is displayed in transient mode. 3490 */ 3491 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3492 3493 /** 3494 * @hide 3495 * 3496 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3497 * out of the public fields to keep the undefined bits out of the developer's way. 3498 * 3499 * Flag to specify that the hidden status bar would like to be shown. 3500 */ 3501 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3502 3503 /** 3504 * @hide 3505 * 3506 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3507 * out of the public fields to keep the undefined bits out of the developer's way. 3508 * 3509 * Flag to specify that the hidden navigation bar would like to be shown. 3510 */ 3511 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3512 3513 /** 3514 * @hide 3515 * 3516 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3517 * out of the public fields to keep the undefined bits out of the developer's way. 3518 * 3519 * Flag to specify that the status bar is displayed in translucent mode. 3520 */ 3521 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3522 3523 /** 3524 * @hide 3525 * 3526 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3527 * out of the public fields to keep the undefined bits out of the developer's way. 3528 * 3529 * Flag to specify that the navigation bar is displayed in translucent mode. 3530 */ 3531 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3532 3533 /** 3534 * @hide 3535 * 3536 * Makes navigation bar transparent (but not the status bar). 3537 */ 3538 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3539 3540 /** 3541 * @hide 3542 * 3543 * Makes status bar transparent (but not the navigation bar). 3544 */ 3545 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3546 3547 /** 3548 * @hide 3549 * 3550 * Makes both status bar and navigation bar transparent. 3551 */ 3552 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3553 | STATUS_BAR_TRANSPARENT; 3554 3555 /** 3556 * @hide 3557 */ 3558 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3559 3560 /** 3561 * These are the system UI flags that can be cleared by events outside 3562 * of an application. Currently this is just the ability to tap on the 3563 * screen while hiding the navigation bar to have it return. 3564 * @hide 3565 */ 3566 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3567 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3568 | SYSTEM_UI_FLAG_FULLSCREEN; 3569 3570 /** 3571 * Flags that can impact the layout in relation to system UI. 3572 */ 3573 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3574 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3575 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3576 3577 /** @hide */ 3578 @IntDef(flag = true, 3579 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3580 @Retention(RetentionPolicy.SOURCE) 3581 public @interface FindViewFlags {} 3582 3583 /** 3584 * Find views that render the specified text. 3585 * 3586 * @see #findViewsWithText(ArrayList, CharSequence, int) 3587 */ 3588 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3589 3590 /** 3591 * Find find views that contain the specified content description. 3592 * 3593 * @see #findViewsWithText(ArrayList, CharSequence, int) 3594 */ 3595 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3596 3597 /** 3598 * Find views that contain {@link AccessibilityNodeProvider}. Such 3599 * a View is a root of virtual view hierarchy and may contain the searched 3600 * text. If this flag is set Views with providers are automatically 3601 * added and it is a responsibility of the client to call the APIs of 3602 * the provider to determine whether the virtual tree rooted at this View 3603 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3604 * representing the virtual views with this text. 3605 * 3606 * @see #findViewsWithText(ArrayList, CharSequence, int) 3607 * 3608 * @hide 3609 */ 3610 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3611 3612 /** 3613 * The undefined cursor position. 3614 * 3615 * @hide 3616 */ 3617 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3618 3619 /** 3620 * Indicates that the screen has changed state and is now off. 3621 * 3622 * @see #onScreenStateChanged(int) 3623 */ 3624 public static final int SCREEN_STATE_OFF = 0x0; 3625 3626 /** 3627 * Indicates that the screen has changed state and is now on. 3628 * 3629 * @see #onScreenStateChanged(int) 3630 */ 3631 public static final int SCREEN_STATE_ON = 0x1; 3632 3633 /** 3634 * Indicates no axis of view scrolling. 3635 */ 3636 public static final int SCROLL_AXIS_NONE = 0; 3637 3638 /** 3639 * Indicates scrolling along the horizontal axis. 3640 */ 3641 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3642 3643 /** 3644 * Indicates scrolling along the vertical axis. 3645 */ 3646 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3647 3648 /** 3649 * Controls the over-scroll mode for this view. 3650 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3651 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3652 * and {@link #OVER_SCROLL_NEVER}. 3653 */ 3654 private int mOverScrollMode; 3655 3656 /** 3657 * The parent this view is attached to. 3658 * {@hide} 3659 * 3660 * @see #getParent() 3661 */ 3662 protected ViewParent mParent; 3663 3664 /** 3665 * {@hide} 3666 */ 3667 AttachInfo mAttachInfo; 3668 3669 /** 3670 * {@hide} 3671 */ 3672 @ViewDebug.ExportedProperty(flagMapping = { 3673 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3674 name = "FORCE_LAYOUT"), 3675 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3676 name = "LAYOUT_REQUIRED"), 3677 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3678 name = "DRAWING_CACHE_INVALID", outputIf = false), 3679 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3680 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3681 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3682 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3683 }, formatToHexString = true) 3684 3685 /* @hide */ 3686 public int mPrivateFlags; 3687 int mPrivateFlags2; 3688 int mPrivateFlags3; 3689 3690 /** 3691 * This view's request for the visibility of the status bar. 3692 * @hide 3693 */ 3694 @ViewDebug.ExportedProperty(flagMapping = { 3695 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3696 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3697 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3698 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3699 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3700 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3701 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3702 equals = SYSTEM_UI_FLAG_VISIBLE, 3703 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3704 }, formatToHexString = true) 3705 int mSystemUiVisibility; 3706 3707 /** 3708 * Reference count for transient state. 3709 * @see #setHasTransientState(boolean) 3710 */ 3711 int mTransientStateCount = 0; 3712 3713 /** 3714 * Count of how many windows this view has been attached to. 3715 */ 3716 int mWindowAttachCount; 3717 3718 /** 3719 * The layout parameters associated with this view and used by the parent 3720 * {@link android.view.ViewGroup} to determine how this view should be 3721 * laid out. 3722 * {@hide} 3723 */ 3724 protected ViewGroup.LayoutParams mLayoutParams; 3725 3726 /** 3727 * The view flags hold various views states. 3728 * {@hide} 3729 */ 3730 @ViewDebug.ExportedProperty(formatToHexString = true) 3731 int mViewFlags; 3732 3733 static class TransformationInfo { 3734 /** 3735 * The transform matrix for the View. This transform is calculated internally 3736 * based on the translation, rotation, and scale properties. 3737 * 3738 * Do *not* use this variable directly; instead call getMatrix(), which will 3739 * load the value from the View's RenderNode. 3740 */ 3741 private final Matrix mMatrix = new Matrix(); 3742 3743 /** 3744 * The inverse transform matrix for the View. This transform is calculated 3745 * internally based on the translation, rotation, and scale properties. 3746 * 3747 * Do *not* use this variable directly; instead call getInverseMatrix(), 3748 * which will load the value from the View's RenderNode. 3749 */ 3750 private Matrix mInverseMatrix; 3751 3752 /** 3753 * The opacity of the View. This is a value from 0 to 1, where 0 means 3754 * completely transparent and 1 means completely opaque. 3755 */ 3756 @ViewDebug.ExportedProperty 3757 float mAlpha = 1f; 3758 3759 /** 3760 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3761 * property only used by transitions, which is composited with the other alpha 3762 * values to calculate the final visual alpha value. 3763 */ 3764 float mTransitionAlpha = 1f; 3765 } 3766 3767 /** @hide */ 3768 public TransformationInfo mTransformationInfo; 3769 3770 /** 3771 * Current clip bounds. to which all drawing of this view are constrained. 3772 */ 3773 Rect mClipBounds = null; 3774 3775 private boolean mLastIsOpaque; 3776 3777 /** 3778 * The distance in pixels from the left edge of this view's parent 3779 * to the left edge of this view. 3780 * {@hide} 3781 */ 3782 @ViewDebug.ExportedProperty(category = "layout") 3783 protected int mLeft; 3784 /** 3785 * The distance in pixels from the left edge of this view's parent 3786 * to the right edge of this view. 3787 * {@hide} 3788 */ 3789 @ViewDebug.ExportedProperty(category = "layout") 3790 protected int mRight; 3791 /** 3792 * The distance in pixels from the top edge of this view's parent 3793 * to the top edge of this view. 3794 * {@hide} 3795 */ 3796 @ViewDebug.ExportedProperty(category = "layout") 3797 protected int mTop; 3798 /** 3799 * The distance in pixels from the top edge of this view's parent 3800 * to the bottom edge of this view. 3801 * {@hide} 3802 */ 3803 @ViewDebug.ExportedProperty(category = "layout") 3804 protected int mBottom; 3805 3806 /** 3807 * The offset, in pixels, by which the content of this view is scrolled 3808 * horizontally. 3809 * {@hide} 3810 */ 3811 @ViewDebug.ExportedProperty(category = "scrolling") 3812 protected int mScrollX; 3813 /** 3814 * The offset, in pixels, by which the content of this view is scrolled 3815 * vertically. 3816 * {@hide} 3817 */ 3818 @ViewDebug.ExportedProperty(category = "scrolling") 3819 protected int mScrollY; 3820 3821 /** 3822 * The left padding in pixels, that is the distance in pixels between the 3823 * left edge of this view and the left edge of its content. 3824 * {@hide} 3825 */ 3826 @ViewDebug.ExportedProperty(category = "padding") 3827 protected int mPaddingLeft = 0; 3828 /** 3829 * The right padding in pixels, that is the distance in pixels between the 3830 * right edge of this view and the right edge of its content. 3831 * {@hide} 3832 */ 3833 @ViewDebug.ExportedProperty(category = "padding") 3834 protected int mPaddingRight = 0; 3835 /** 3836 * The top padding in pixels, that is the distance in pixels between the 3837 * top edge of this view and the top edge of its content. 3838 * {@hide} 3839 */ 3840 @ViewDebug.ExportedProperty(category = "padding") 3841 protected int mPaddingTop; 3842 /** 3843 * The bottom padding in pixels, that is the distance in pixels between the 3844 * bottom edge of this view and the bottom edge of its content. 3845 * {@hide} 3846 */ 3847 @ViewDebug.ExportedProperty(category = "padding") 3848 protected int mPaddingBottom; 3849 3850 /** 3851 * The layout insets in pixels, that is the distance in pixels between the 3852 * visible edges of this view its bounds. 3853 */ 3854 private Insets mLayoutInsets; 3855 3856 /** 3857 * Briefly describes the view and is primarily used for accessibility support. 3858 */ 3859 private CharSequence mContentDescription; 3860 3861 /** 3862 * Specifies the id of a view for which this view serves as a label for 3863 * accessibility purposes. 3864 */ 3865 private int mLabelForId = View.NO_ID; 3866 3867 /** 3868 * Predicate for matching labeled view id with its label for 3869 * accessibility purposes. 3870 */ 3871 private MatchLabelForPredicate mMatchLabelForPredicate; 3872 3873 /** 3874 * Specifies a view before which this one is visited in accessibility traversal. 3875 */ 3876 private int mAccessibilityTraversalBeforeId = NO_ID; 3877 3878 /** 3879 * Specifies a view after which this one is visited in accessibility traversal. 3880 */ 3881 private int mAccessibilityTraversalAfterId = NO_ID; 3882 3883 /** 3884 * Predicate for matching a view by its id. 3885 */ 3886 private MatchIdPredicate mMatchIdPredicate; 3887 3888 /** 3889 * Cache the paddingRight set by the user to append to the scrollbar's size. 3890 * 3891 * @hide 3892 */ 3893 @ViewDebug.ExportedProperty(category = "padding") 3894 protected int mUserPaddingRight; 3895 3896 /** 3897 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3898 * 3899 * @hide 3900 */ 3901 @ViewDebug.ExportedProperty(category = "padding") 3902 protected int mUserPaddingBottom; 3903 3904 /** 3905 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3906 * 3907 * @hide 3908 */ 3909 @ViewDebug.ExportedProperty(category = "padding") 3910 protected int mUserPaddingLeft; 3911 3912 /** 3913 * Cache the paddingStart set by the user to append to the scrollbar's size. 3914 * 3915 */ 3916 @ViewDebug.ExportedProperty(category = "padding") 3917 int mUserPaddingStart; 3918 3919 /** 3920 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3921 * 3922 */ 3923 @ViewDebug.ExportedProperty(category = "padding") 3924 int mUserPaddingEnd; 3925 3926 /** 3927 * Cache initial left padding. 3928 * 3929 * @hide 3930 */ 3931 int mUserPaddingLeftInitial; 3932 3933 /** 3934 * Cache initial right padding. 3935 * 3936 * @hide 3937 */ 3938 int mUserPaddingRightInitial; 3939 3940 /** 3941 * Default undefined padding 3942 */ 3943 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3944 3945 /** 3946 * Cache if a left padding has been defined 3947 */ 3948 private boolean mLeftPaddingDefined = false; 3949 3950 /** 3951 * Cache if a right padding has been defined 3952 */ 3953 private boolean mRightPaddingDefined = false; 3954 3955 /** 3956 * @hide 3957 */ 3958 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3959 /** 3960 * @hide 3961 */ 3962 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3963 3964 private LongSparseLongArray mMeasureCache; 3965 3966 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3967 private Drawable mBackground; 3968 private TintInfo mBackgroundTint; 3969 3970 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3971 private ForegroundInfo mForegroundInfo; 3972 3973 private Drawable mScrollIndicatorDrawable; 3974 3975 /** 3976 * RenderNode used for backgrounds. 3977 * <p> 3978 * When non-null and valid, this is expected to contain an up-to-date copy 3979 * of the background drawable. It is cleared on temporary detach, and reset 3980 * on cleanup. 3981 */ 3982 private RenderNode mBackgroundRenderNode; 3983 3984 private int mBackgroundResource; 3985 private boolean mBackgroundSizeChanged; 3986 3987 /** The default focus highlight. 3988 * @see #mDefaultFocusHighlightEnabled 3989 * @see Drawable#hasFocusStateSpecified() 3990 */ 3991 private Drawable mDefaultFocusHighlight; 3992 private Drawable mDefaultFocusHighlightCache; 3993 private boolean mDefaultFocusHighlightSizeChanged; 3994 /** 3995 * True if the default focus highlight is needed on the target device. 3996 */ 3997 private static boolean sUseDefaultFocusHighlight; 3998 3999 private String mTransitionName; 4000 4001 static class TintInfo { 4002 ColorStateList mTintList; 4003 PorterDuff.Mode mTintMode; 4004 boolean mHasTintMode; 4005 boolean mHasTintList; 4006 } 4007 4008 private static class ForegroundInfo { 4009 private Drawable mDrawable; 4010 private TintInfo mTintInfo; 4011 private int mGravity = Gravity.FILL; 4012 private boolean mInsidePadding = true; 4013 private boolean mBoundsChanged = true; 4014 private final Rect mSelfBounds = new Rect(); 4015 private final Rect mOverlayBounds = new Rect(); 4016 } 4017 4018 static class ListenerInfo { 4019 /** 4020 * Listener used to dispatch focus change events. 4021 * This field should be made private, so it is hidden from the SDK. 4022 * {@hide} 4023 */ 4024 protected OnFocusChangeListener mOnFocusChangeListener; 4025 4026 /** 4027 * Listeners for layout change events. 4028 */ 4029 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4030 4031 protected OnScrollChangeListener mOnScrollChangeListener; 4032 4033 /** 4034 * Listeners for attach events. 4035 */ 4036 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4037 4038 /** 4039 * Listener used to dispatch click events. 4040 * This field should be made private, so it is hidden from the SDK. 4041 * {@hide} 4042 */ 4043 public OnClickListener mOnClickListener; 4044 4045 /** 4046 * Listener used to dispatch long click events. 4047 * This field should be made private, so it is hidden from the SDK. 4048 * {@hide} 4049 */ 4050 protected OnLongClickListener mOnLongClickListener; 4051 4052 /** 4053 * Listener used to dispatch context click events. This field should be made private, so it 4054 * is hidden from the SDK. 4055 * {@hide} 4056 */ 4057 protected OnContextClickListener mOnContextClickListener; 4058 4059 /** 4060 * Listener used to build the context menu. 4061 * This field should be made private, so it is hidden from the SDK. 4062 * {@hide} 4063 */ 4064 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4065 4066 private OnKeyListener mOnKeyListener; 4067 4068 private OnTouchListener mOnTouchListener; 4069 4070 private OnHoverListener mOnHoverListener; 4071 4072 private OnGenericMotionListener mOnGenericMotionListener; 4073 4074 private OnDragListener mOnDragListener; 4075 4076 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4077 4078 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4079 4080 OnCapturedPointerListener mOnCapturedPointerListener; 4081 } 4082 4083 ListenerInfo mListenerInfo; 4084 4085 private static class TooltipInfo { 4086 /** 4087 * Text to be displayed in a tooltip popup. 4088 */ 4089 @Nullable 4090 CharSequence mTooltipText; 4091 4092 /** 4093 * View-relative position of the tooltip anchor point. 4094 */ 4095 int mAnchorX; 4096 int mAnchorY; 4097 4098 /** 4099 * The tooltip popup. 4100 */ 4101 @Nullable 4102 TooltipPopup mTooltipPopup; 4103 4104 /** 4105 * Set to true if the tooltip was shown as a result of a long click. 4106 */ 4107 boolean mTooltipFromLongClick; 4108 4109 /** 4110 * Keep these Runnables so that they can be used to reschedule. 4111 */ 4112 Runnable mShowTooltipRunnable; 4113 Runnable mHideTooltipRunnable; 4114 } 4115 4116 TooltipInfo mTooltipInfo; 4117 4118 // Temporary values used to hold (x,y) coordinates when delegating from the 4119 // two-arg performLongClick() method to the legacy no-arg version. 4120 private float mLongClickX = Float.NaN; 4121 private float mLongClickY = Float.NaN; 4122 4123 /** 4124 * The application environment this view lives in. 4125 * This field should be made private, so it is hidden from the SDK. 4126 * {@hide} 4127 */ 4128 @ViewDebug.ExportedProperty(deepExport = true) 4129 protected Context mContext; 4130 4131 private final Resources mResources; 4132 4133 private ScrollabilityCache mScrollCache; 4134 4135 private int[] mDrawableState = null; 4136 4137 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4138 4139 /** 4140 * Animator that automatically runs based on state changes. 4141 */ 4142 private StateListAnimator mStateListAnimator; 4143 4144 /** 4145 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4146 * the user may specify which view to go to next. 4147 */ 4148 private int mNextFocusLeftId = View.NO_ID; 4149 4150 /** 4151 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4152 * the user may specify which view to go to next. 4153 */ 4154 private int mNextFocusRightId = View.NO_ID; 4155 4156 /** 4157 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4158 * the user may specify which view to go to next. 4159 */ 4160 private int mNextFocusUpId = View.NO_ID; 4161 4162 /** 4163 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4164 * the user may specify which view to go to next. 4165 */ 4166 private int mNextFocusDownId = View.NO_ID; 4167 4168 /** 4169 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4170 * the user may specify which view to go to next. 4171 */ 4172 int mNextFocusForwardId = View.NO_ID; 4173 4174 /** 4175 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4176 * 4177 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4178 */ 4179 int mNextClusterForwardId = View.NO_ID; 4180 4181 /** 4182 * Whether this View should use a default focus highlight when it gets focused but doesn't 4183 * have {@link android.R.attr#state_focused} defined in its background. 4184 */ 4185 boolean mDefaultFocusHighlightEnabled = true; 4186 4187 private CheckForLongPress mPendingCheckForLongPress; 4188 private CheckForTap mPendingCheckForTap = null; 4189 private PerformClick mPerformClick; 4190 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4191 4192 private UnsetPressedState mUnsetPressedState; 4193 4194 /** 4195 * Whether the long press's action has been invoked. The tap's action is invoked on the 4196 * up event while a long press is invoked as soon as the long press duration is reached, so 4197 * a long press could be performed before the tap is checked, in which case the tap's action 4198 * should not be invoked. 4199 */ 4200 private boolean mHasPerformedLongPress; 4201 4202 /** 4203 * Whether a context click button is currently pressed down. This is true when the stylus is 4204 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4205 * pressed. This is false once the button is released or if the stylus has been lifted. 4206 */ 4207 private boolean mInContextButtonPress; 4208 4209 /** 4210 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4211 * true after a stylus button press has occured, when the next up event should not be recognized 4212 * as a tap. 4213 */ 4214 private boolean mIgnoreNextUpEvent; 4215 4216 /** 4217 * The minimum height of the view. We'll try our best to have the height 4218 * of this view to at least this amount. 4219 */ 4220 @ViewDebug.ExportedProperty(category = "measurement") 4221 private int mMinHeight; 4222 4223 /** 4224 * The minimum width of the view. We'll try our best to have the width 4225 * of this view to at least this amount. 4226 */ 4227 @ViewDebug.ExportedProperty(category = "measurement") 4228 private int mMinWidth; 4229 4230 /** 4231 * The delegate to handle touch events that are physically in this view 4232 * but should be handled by another view. 4233 */ 4234 private TouchDelegate mTouchDelegate = null; 4235 4236 /** 4237 * Solid color to use as a background when creating the drawing cache. Enables 4238 * the cache to use 16 bit bitmaps instead of 32 bit. 4239 */ 4240 private int mDrawingCacheBackgroundColor = 0; 4241 4242 /** 4243 * Special tree observer used when mAttachInfo is null. 4244 */ 4245 private ViewTreeObserver mFloatingTreeObserver; 4246 4247 /** 4248 * Cache the touch slop from the context that created the view. 4249 */ 4250 private int mTouchSlop; 4251 4252 /** 4253 * Object that handles automatic animation of view properties. 4254 */ 4255 private ViewPropertyAnimator mAnimator = null; 4256 4257 /** 4258 * List of registered FrameMetricsObservers. 4259 */ 4260 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4261 4262 /** 4263 * Flag indicating that a drag can cross window boundaries. When 4264 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4265 * with this flag set, all visible applications with targetSdkVersion >= 4266 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4267 * in the drag operation and receive the dragged content. 4268 * 4269 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4270 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 4271 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 4272 */ 4273 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 4274 4275 /** 4276 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4277 * request read access to the content URI(s) contained in the {@link ClipData} object. 4278 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 4279 */ 4280 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 4281 4282 /** 4283 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4284 * request write access to the content URI(s) contained in the {@link ClipData} object. 4285 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 4286 */ 4287 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 4288 4289 /** 4290 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4291 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 4292 * reboots until explicitly revoked with 4293 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 4294 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 4295 */ 4296 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 4297 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 4298 4299 /** 4300 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4301 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 4302 * match against the original granted URI. 4303 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 4304 */ 4305 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 4306 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 4307 4308 /** 4309 * Flag indicating that the drag shadow will be opaque. When 4310 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4311 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 4312 */ 4313 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 4314 4315 /** 4316 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 4317 */ 4318 private float mVerticalScrollFactor; 4319 4320 /** 4321 * Position of the vertical scroll bar. 4322 */ 4323 private int mVerticalScrollbarPosition; 4324 4325 /** 4326 * Position the scroll bar at the default position as determined by the system. 4327 */ 4328 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 4329 4330 /** 4331 * Position the scroll bar along the left edge. 4332 */ 4333 public static final int SCROLLBAR_POSITION_LEFT = 1; 4334 4335 /** 4336 * Position the scroll bar along the right edge. 4337 */ 4338 public static final int SCROLLBAR_POSITION_RIGHT = 2; 4339 4340 /** 4341 * Indicates that the view does not have a layer. 4342 * 4343 * @see #getLayerType() 4344 * @see #setLayerType(int, android.graphics.Paint) 4345 * @see #LAYER_TYPE_SOFTWARE 4346 * @see #LAYER_TYPE_HARDWARE 4347 */ 4348 public static final int LAYER_TYPE_NONE = 0; 4349 4350 /** 4351 * <p>Indicates that the view has a software layer. A software layer is backed 4352 * by a bitmap and causes the view to be rendered using Android's software 4353 * rendering pipeline, even if hardware acceleration is enabled.</p> 4354 * 4355 * <p>Software layers have various usages:</p> 4356 * <p>When the application is not using hardware acceleration, a software layer 4357 * is useful to apply a specific color filter and/or blending mode and/or 4358 * translucency to a view and all its children.</p> 4359 * <p>When the application is using hardware acceleration, a software layer 4360 * is useful to render drawing primitives not supported by the hardware 4361 * accelerated pipeline. It can also be used to cache a complex view tree 4362 * into a texture and reduce the complexity of drawing operations. For instance, 4363 * when animating a complex view tree with a translation, a software layer can 4364 * be used to render the view tree only once.</p> 4365 * <p>Software layers should be avoided when the affected view tree updates 4366 * often. Every update will require to re-render the software layer, which can 4367 * potentially be slow (particularly when hardware acceleration is turned on 4368 * since the layer will have to be uploaded into a hardware texture after every 4369 * update.)</p> 4370 * 4371 * @see #getLayerType() 4372 * @see #setLayerType(int, android.graphics.Paint) 4373 * @see #LAYER_TYPE_NONE 4374 * @see #LAYER_TYPE_HARDWARE 4375 */ 4376 public static final int LAYER_TYPE_SOFTWARE = 1; 4377 4378 /** 4379 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4380 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4381 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4382 * rendering pipeline, but only if hardware acceleration is turned on for the 4383 * view hierarchy. When hardware acceleration is turned off, hardware layers 4384 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4385 * 4386 * <p>A hardware layer is useful to apply a specific color filter and/or 4387 * blending mode and/or translucency to a view and all its children.</p> 4388 * <p>A hardware layer can be used to cache a complex view tree into a 4389 * texture and reduce the complexity of drawing operations. For instance, 4390 * when animating a complex view tree with a translation, a hardware layer can 4391 * be used to render the view tree only once.</p> 4392 * <p>A hardware layer can also be used to increase the rendering quality when 4393 * rotation transformations are applied on a view. It can also be used to 4394 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4395 * 4396 * @see #getLayerType() 4397 * @see #setLayerType(int, android.graphics.Paint) 4398 * @see #LAYER_TYPE_NONE 4399 * @see #LAYER_TYPE_SOFTWARE 4400 */ 4401 public static final int LAYER_TYPE_HARDWARE = 2; 4402 4403 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4404 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4405 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4406 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4407 }) 4408 int mLayerType = LAYER_TYPE_NONE; 4409 Paint mLayerPaint; 4410 4411 /** 4412 * Set to true when drawing cache is enabled and cannot be created. 4413 * 4414 * @hide 4415 */ 4416 public boolean mCachingFailed; 4417 private Bitmap mDrawingCache; 4418 private Bitmap mUnscaledDrawingCache; 4419 4420 /** 4421 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4422 * <p> 4423 * When non-null and valid, this is expected to contain an up-to-date copy 4424 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4425 * cleanup. 4426 */ 4427 final RenderNode mRenderNode; 4428 4429 /** 4430 * Set to true when the view is sending hover accessibility events because it 4431 * is the innermost hovered view. 4432 */ 4433 private boolean mSendingHoverAccessibilityEvents; 4434 4435 /** 4436 * Delegate for injecting accessibility functionality. 4437 */ 4438 AccessibilityDelegate mAccessibilityDelegate; 4439 4440 /** 4441 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4442 * and add/remove objects to/from the overlay directly through the Overlay methods. 4443 */ 4444 ViewOverlay mOverlay; 4445 4446 /** 4447 * The currently active parent view for receiving delegated nested scrolling events. 4448 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4449 * by {@link #stopNestedScroll()} at the same point where we clear 4450 * requestDisallowInterceptTouchEvent. 4451 */ 4452 private ViewParent mNestedScrollingParent; 4453 4454 /** 4455 * Consistency verifier for debugging purposes. 4456 * @hide 4457 */ 4458 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4459 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4460 new InputEventConsistencyVerifier(this, 0) : null; 4461 4462 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4463 4464 private int[] mTempNestedScrollConsumed; 4465 4466 /** 4467 * An overlay is going to draw this View instead of being drawn as part of this 4468 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4469 * when this view is invalidated. 4470 */ 4471 GhostView mGhostView; 4472 4473 /** 4474 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4475 * @hide 4476 */ 4477 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4478 public String[] mAttributes; 4479 4480 /** 4481 * Maps a Resource id to its name. 4482 */ 4483 private static SparseArray<String> mAttributeMap; 4484 4485 /** 4486 * Queue of pending runnables. Used to postpone calls to post() until this 4487 * view is attached and has a handler. 4488 */ 4489 private HandlerActionQueue mRunQueue; 4490 4491 /** 4492 * The pointer icon when the mouse hovers on this view. The default is null. 4493 */ 4494 private PointerIcon mPointerIcon; 4495 4496 /** 4497 * @hide 4498 */ 4499 String mStartActivityRequestWho; 4500 4501 @Nullable 4502 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4503 4504 /** Used to delay visibility updates sent to the autofill manager */ 4505 private Handler mVisibilityChangeForAutofillHandler; 4506 4507 /** 4508 * Simple constructor to use when creating a view from code. 4509 * 4510 * @param context The Context the view is running in, through which it can 4511 * access the current theme, resources, etc. 4512 */ 4513 public View(Context context) { 4514 mContext = context; 4515 mResources = context != null ? context.getResources() : null; 4516 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 4517 // Set some flags defaults 4518 mPrivateFlags2 = 4519 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4520 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4521 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4522 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4523 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4524 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4525 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4526 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4527 mUserPaddingStart = UNDEFINED_PADDING; 4528 mUserPaddingEnd = UNDEFINED_PADDING; 4529 mRenderNode = RenderNode.create(getClass().getName(), this); 4530 4531 if (!sCompatibilityDone && context != null) { 4532 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4533 4534 // Older apps may need this compatibility hack for measurement. 4535 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 4536 4537 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4538 // of whether a layout was requested on that View. 4539 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 4540 4541 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 4542 Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O; 4543 4544 // In M and newer, our widgets can pass a "hint" value in the size 4545 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4546 // know what the expected parent size is going to be, so e.g. list items can size 4547 // themselves at 1/3 the size of their container. It breaks older apps though, 4548 // specifically apps that use some popular open source libraries. 4549 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 4550 4551 // Old versions of the platform would give different results from 4552 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4553 // modes, so we always need to run an additional EXACTLY pass. 4554 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 4555 4556 // Prior to N, layout params could change without requiring a 4557 // subsequent call to setLayoutParams() and they would usually 4558 // work. Partial layout breaks this assumption. 4559 sLayoutParamsAlwaysChanged = targetSdkVersion <= Build.VERSION_CODES.M; 4560 4561 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4562 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4563 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 4564 4565 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4566 // in apps so we target check it to avoid breaking existing apps. 4567 sPreserveMarginParamsInLayoutParamConversion = 4568 targetSdkVersion >= Build.VERSION_CODES.N; 4569 4570 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 4571 4572 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 4573 4574 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 4575 4576 sUseDefaultFocusHighlight = context.getResources().getBoolean( 4577 com.android.internal.R.bool.config_useDefaultFocusHighlight); 4578 4579 sCompatibilityDone = true; 4580 } 4581 } 4582 4583 /** 4584 * Constructor that is called when inflating a view from XML. This is called 4585 * when a view is being constructed from an XML file, supplying attributes 4586 * that were specified in the XML file. This version uses a default style of 4587 * 0, so the only attribute values applied are those in the Context's Theme 4588 * and the given AttributeSet. 4589 * 4590 * <p> 4591 * The method onFinishInflate() will be called after all children have been 4592 * added. 4593 * 4594 * @param context The Context the view is running in, through which it can 4595 * access the current theme, resources, etc. 4596 * @param attrs The attributes of the XML tag that is inflating the view. 4597 * @see #View(Context, AttributeSet, int) 4598 */ 4599 public View(Context context, @Nullable AttributeSet attrs) { 4600 this(context, attrs, 0); 4601 } 4602 4603 /** 4604 * Perform inflation from XML and apply a class-specific base style from a 4605 * theme attribute. This constructor of View allows subclasses to use their 4606 * own base style when they are inflating. For example, a Button class's 4607 * constructor would call this version of the super class constructor and 4608 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4609 * allows the theme's button style to modify all of the base view attributes 4610 * (in particular its background) as well as the Button class's attributes. 4611 * 4612 * @param context The Context the view is running in, through which it can 4613 * access the current theme, resources, etc. 4614 * @param attrs The attributes of the XML tag that is inflating the view. 4615 * @param defStyleAttr An attribute in the current theme that contains a 4616 * reference to a style resource that supplies default values for 4617 * the view. Can be 0 to not look for defaults. 4618 * @see #View(Context, AttributeSet) 4619 */ 4620 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4621 this(context, attrs, defStyleAttr, 0); 4622 } 4623 4624 /** 4625 * Perform inflation from XML and apply a class-specific base style from a 4626 * theme attribute or style resource. This constructor of View allows 4627 * subclasses to use their own base style when they are inflating. 4628 * <p> 4629 * When determining the final value of a particular attribute, there are 4630 * four inputs that come into play: 4631 * <ol> 4632 * <li>Any attribute values in the given AttributeSet. 4633 * <li>The style resource specified in the AttributeSet (named "style"). 4634 * <li>The default style specified by <var>defStyleAttr</var>. 4635 * <li>The default style specified by <var>defStyleRes</var>. 4636 * <li>The base values in this theme. 4637 * </ol> 4638 * <p> 4639 * Each of these inputs is considered in-order, with the first listed taking 4640 * precedence over the following ones. In other words, if in the 4641 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4642 * , then the button's text will <em>always</em> be black, regardless of 4643 * what is specified in any of the styles. 4644 * 4645 * @param context The Context the view is running in, through which it can 4646 * access the current theme, resources, etc. 4647 * @param attrs The attributes of the XML tag that is inflating the view. 4648 * @param defStyleAttr An attribute in the current theme that contains a 4649 * reference to a style resource that supplies default values for 4650 * the view. Can be 0 to not look for defaults. 4651 * @param defStyleRes A resource identifier of a style resource that 4652 * supplies default values for the view, used only if 4653 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4654 * to not look for defaults. 4655 * @see #View(Context, AttributeSet, int) 4656 */ 4657 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4658 this(context); 4659 4660 final TypedArray a = context.obtainStyledAttributes( 4661 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4662 4663 if (mDebugViewAttributes) { 4664 saveAttributeData(attrs, a); 4665 } 4666 4667 Drawable background = null; 4668 4669 int leftPadding = -1; 4670 int topPadding = -1; 4671 int rightPadding = -1; 4672 int bottomPadding = -1; 4673 int startPadding = UNDEFINED_PADDING; 4674 int endPadding = UNDEFINED_PADDING; 4675 4676 int padding = -1; 4677 int paddingHorizontal = -1; 4678 int paddingVertical = -1; 4679 4680 int viewFlagValues = 0; 4681 int viewFlagMasks = 0; 4682 4683 boolean setScrollContainer = false; 4684 4685 int x = 0; 4686 int y = 0; 4687 4688 float tx = 0; 4689 float ty = 0; 4690 float tz = 0; 4691 float elevation = 0; 4692 float rotation = 0; 4693 float rotationX = 0; 4694 float rotationY = 0; 4695 float sx = 1f; 4696 float sy = 1f; 4697 boolean transformSet = false; 4698 4699 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4700 int overScrollMode = mOverScrollMode; 4701 boolean initializeScrollbars = false; 4702 boolean initializeScrollIndicators = false; 4703 4704 boolean startPaddingDefined = false; 4705 boolean endPaddingDefined = false; 4706 boolean leftPaddingDefined = false; 4707 boolean rightPaddingDefined = false; 4708 4709 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4710 4711 // Set default values. 4712 viewFlagValues |= FOCUSABLE_AUTO; 4713 viewFlagMasks |= FOCUSABLE_AUTO; 4714 4715 final int N = a.getIndexCount(); 4716 for (int i = 0; i < N; i++) { 4717 int attr = a.getIndex(i); 4718 switch (attr) { 4719 case com.android.internal.R.styleable.View_background: 4720 background = a.getDrawable(attr); 4721 break; 4722 case com.android.internal.R.styleable.View_padding: 4723 padding = a.getDimensionPixelSize(attr, -1); 4724 mUserPaddingLeftInitial = padding; 4725 mUserPaddingRightInitial = padding; 4726 leftPaddingDefined = true; 4727 rightPaddingDefined = true; 4728 break; 4729 case com.android.internal.R.styleable.View_paddingHorizontal: 4730 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4731 mUserPaddingLeftInitial = paddingHorizontal; 4732 mUserPaddingRightInitial = paddingHorizontal; 4733 leftPaddingDefined = true; 4734 rightPaddingDefined = true; 4735 break; 4736 case com.android.internal.R.styleable.View_paddingVertical: 4737 paddingVertical = a.getDimensionPixelSize(attr, -1); 4738 break; 4739 case com.android.internal.R.styleable.View_paddingLeft: 4740 leftPadding = a.getDimensionPixelSize(attr, -1); 4741 mUserPaddingLeftInitial = leftPadding; 4742 leftPaddingDefined = true; 4743 break; 4744 case com.android.internal.R.styleable.View_paddingTop: 4745 topPadding = a.getDimensionPixelSize(attr, -1); 4746 break; 4747 case com.android.internal.R.styleable.View_paddingRight: 4748 rightPadding = a.getDimensionPixelSize(attr, -1); 4749 mUserPaddingRightInitial = rightPadding; 4750 rightPaddingDefined = true; 4751 break; 4752 case com.android.internal.R.styleable.View_paddingBottom: 4753 bottomPadding = a.getDimensionPixelSize(attr, -1); 4754 break; 4755 case com.android.internal.R.styleable.View_paddingStart: 4756 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4757 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4758 break; 4759 case com.android.internal.R.styleable.View_paddingEnd: 4760 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4761 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4762 break; 4763 case com.android.internal.R.styleable.View_scrollX: 4764 x = a.getDimensionPixelOffset(attr, 0); 4765 break; 4766 case com.android.internal.R.styleable.View_scrollY: 4767 y = a.getDimensionPixelOffset(attr, 0); 4768 break; 4769 case com.android.internal.R.styleable.View_alpha: 4770 setAlpha(a.getFloat(attr, 1f)); 4771 break; 4772 case com.android.internal.R.styleable.View_transformPivotX: 4773 setPivotX(a.getDimension(attr, 0)); 4774 break; 4775 case com.android.internal.R.styleable.View_transformPivotY: 4776 setPivotY(a.getDimension(attr, 0)); 4777 break; 4778 case com.android.internal.R.styleable.View_translationX: 4779 tx = a.getDimension(attr, 0); 4780 transformSet = true; 4781 break; 4782 case com.android.internal.R.styleable.View_translationY: 4783 ty = a.getDimension(attr, 0); 4784 transformSet = true; 4785 break; 4786 case com.android.internal.R.styleable.View_translationZ: 4787 tz = a.getDimension(attr, 0); 4788 transformSet = true; 4789 break; 4790 case com.android.internal.R.styleable.View_elevation: 4791 elevation = a.getDimension(attr, 0); 4792 transformSet = true; 4793 break; 4794 case com.android.internal.R.styleable.View_rotation: 4795 rotation = a.getFloat(attr, 0); 4796 transformSet = true; 4797 break; 4798 case com.android.internal.R.styleable.View_rotationX: 4799 rotationX = a.getFloat(attr, 0); 4800 transformSet = true; 4801 break; 4802 case com.android.internal.R.styleable.View_rotationY: 4803 rotationY = a.getFloat(attr, 0); 4804 transformSet = true; 4805 break; 4806 case com.android.internal.R.styleable.View_scaleX: 4807 sx = a.getFloat(attr, 1f); 4808 transformSet = true; 4809 break; 4810 case com.android.internal.R.styleable.View_scaleY: 4811 sy = a.getFloat(attr, 1f); 4812 transformSet = true; 4813 break; 4814 case com.android.internal.R.styleable.View_id: 4815 mID = a.getResourceId(attr, NO_ID); 4816 break; 4817 case com.android.internal.R.styleable.View_tag: 4818 mTag = a.getText(attr); 4819 break; 4820 case com.android.internal.R.styleable.View_fitsSystemWindows: 4821 if (a.getBoolean(attr, false)) { 4822 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4823 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4824 } 4825 break; 4826 case com.android.internal.R.styleable.View_focusable: 4827 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 4828 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 4829 viewFlagMasks |= FOCUSABLE_MASK; 4830 } 4831 break; 4832 case com.android.internal.R.styleable.View_focusableInTouchMode: 4833 if (a.getBoolean(attr, false)) { 4834 // unset auto focus since focusableInTouchMode implies explicit focusable 4835 viewFlagValues &= ~FOCUSABLE_AUTO; 4836 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4837 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4838 } 4839 break; 4840 case com.android.internal.R.styleable.View_clickable: 4841 if (a.getBoolean(attr, false)) { 4842 viewFlagValues |= CLICKABLE; 4843 viewFlagMasks |= CLICKABLE; 4844 } 4845 break; 4846 case com.android.internal.R.styleable.View_longClickable: 4847 if (a.getBoolean(attr, false)) { 4848 viewFlagValues |= LONG_CLICKABLE; 4849 viewFlagMasks |= LONG_CLICKABLE; 4850 } 4851 break; 4852 case com.android.internal.R.styleable.View_contextClickable: 4853 if (a.getBoolean(attr, false)) { 4854 viewFlagValues |= CONTEXT_CLICKABLE; 4855 viewFlagMasks |= CONTEXT_CLICKABLE; 4856 } 4857 break; 4858 case com.android.internal.R.styleable.View_saveEnabled: 4859 if (!a.getBoolean(attr, true)) { 4860 viewFlagValues |= SAVE_DISABLED; 4861 viewFlagMasks |= SAVE_DISABLED_MASK; 4862 } 4863 break; 4864 case com.android.internal.R.styleable.View_duplicateParentState: 4865 if (a.getBoolean(attr, false)) { 4866 viewFlagValues |= DUPLICATE_PARENT_STATE; 4867 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4868 } 4869 break; 4870 case com.android.internal.R.styleable.View_visibility: 4871 final int visibility = a.getInt(attr, 0); 4872 if (visibility != 0) { 4873 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4874 viewFlagMasks |= VISIBILITY_MASK; 4875 } 4876 break; 4877 case com.android.internal.R.styleable.View_layoutDirection: 4878 // Clear any layout direction flags (included resolved bits) already set 4879 mPrivateFlags2 &= 4880 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4881 // Set the layout direction flags depending on the value of the attribute 4882 final int layoutDirection = a.getInt(attr, -1); 4883 final int value = (layoutDirection != -1) ? 4884 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4885 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4886 break; 4887 case com.android.internal.R.styleable.View_drawingCacheQuality: 4888 final int cacheQuality = a.getInt(attr, 0); 4889 if (cacheQuality != 0) { 4890 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4891 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4892 } 4893 break; 4894 case com.android.internal.R.styleable.View_contentDescription: 4895 setContentDescription(a.getString(attr)); 4896 break; 4897 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4898 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4899 break; 4900 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4901 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4902 break; 4903 case com.android.internal.R.styleable.View_labelFor: 4904 setLabelFor(a.getResourceId(attr, NO_ID)); 4905 break; 4906 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4907 if (!a.getBoolean(attr, true)) { 4908 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4909 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4910 } 4911 break; 4912 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4913 if (!a.getBoolean(attr, true)) { 4914 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4915 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4916 } 4917 break; 4918 case R.styleable.View_scrollbars: 4919 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4920 if (scrollbars != SCROLLBARS_NONE) { 4921 viewFlagValues |= scrollbars; 4922 viewFlagMasks |= SCROLLBARS_MASK; 4923 initializeScrollbars = true; 4924 } 4925 break; 4926 //noinspection deprecation 4927 case R.styleable.View_fadingEdge: 4928 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 4929 // Ignore the attribute starting with ICS 4930 break; 4931 } 4932 // With builds < ICS, fall through and apply fading edges 4933 case R.styleable.View_requiresFadingEdge: 4934 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4935 if (fadingEdge != FADING_EDGE_NONE) { 4936 viewFlagValues |= fadingEdge; 4937 viewFlagMasks |= FADING_EDGE_MASK; 4938 initializeFadingEdgeInternal(a); 4939 } 4940 break; 4941 case R.styleable.View_scrollbarStyle: 4942 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4943 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4944 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4945 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4946 } 4947 break; 4948 case R.styleable.View_isScrollContainer: 4949 setScrollContainer = true; 4950 if (a.getBoolean(attr, false)) { 4951 setScrollContainer(true); 4952 } 4953 break; 4954 case com.android.internal.R.styleable.View_keepScreenOn: 4955 if (a.getBoolean(attr, false)) { 4956 viewFlagValues |= KEEP_SCREEN_ON; 4957 viewFlagMasks |= KEEP_SCREEN_ON; 4958 } 4959 break; 4960 case R.styleable.View_filterTouchesWhenObscured: 4961 if (a.getBoolean(attr, false)) { 4962 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4963 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4964 } 4965 break; 4966 case R.styleable.View_nextFocusLeft: 4967 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4968 break; 4969 case R.styleable.View_nextFocusRight: 4970 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4971 break; 4972 case R.styleable.View_nextFocusUp: 4973 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4974 break; 4975 case R.styleable.View_nextFocusDown: 4976 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4977 break; 4978 case R.styleable.View_nextFocusForward: 4979 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4980 break; 4981 case R.styleable.View_nextClusterForward: 4982 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 4983 break; 4984 case R.styleable.View_minWidth: 4985 mMinWidth = a.getDimensionPixelSize(attr, 0); 4986 break; 4987 case R.styleable.View_minHeight: 4988 mMinHeight = a.getDimensionPixelSize(attr, 0); 4989 break; 4990 case R.styleable.View_onClick: 4991 if (context.isRestricted()) { 4992 throw new IllegalStateException("The android:onClick attribute cannot " 4993 + "be used within a restricted context"); 4994 } 4995 4996 final String handlerName = a.getString(attr); 4997 if (handlerName != null) { 4998 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 4999 } 5000 break; 5001 case R.styleable.View_overScrollMode: 5002 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5003 break; 5004 case R.styleable.View_verticalScrollbarPosition: 5005 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5006 break; 5007 case R.styleable.View_layerType: 5008 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5009 break; 5010 case R.styleable.View_textDirection: 5011 // Clear any text direction flag already set 5012 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5013 // Set the text direction flags depending on the value of the attribute 5014 final int textDirection = a.getInt(attr, -1); 5015 if (textDirection != -1) { 5016 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5017 } 5018 break; 5019 case R.styleable.View_textAlignment: 5020 // Clear any text alignment flag already set 5021 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5022 // Set the text alignment flag depending on the value of the attribute 5023 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5024 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5025 break; 5026 case R.styleable.View_importantForAccessibility: 5027 setImportantForAccessibility(a.getInt(attr, 5028 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5029 break; 5030 case R.styleable.View_accessibilityLiveRegion: 5031 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5032 break; 5033 case R.styleable.View_transitionName: 5034 setTransitionName(a.getString(attr)); 5035 break; 5036 case R.styleable.View_nestedScrollingEnabled: 5037 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5038 break; 5039 case R.styleable.View_stateListAnimator: 5040 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5041 a.getResourceId(attr, 0))); 5042 break; 5043 case R.styleable.View_backgroundTint: 5044 // This will get applied later during setBackground(). 5045 if (mBackgroundTint == null) { 5046 mBackgroundTint = new TintInfo(); 5047 } 5048 mBackgroundTint.mTintList = a.getColorStateList( 5049 R.styleable.View_backgroundTint); 5050 mBackgroundTint.mHasTintList = true; 5051 break; 5052 case R.styleable.View_backgroundTintMode: 5053 // This will get applied later during setBackground(). 5054 if (mBackgroundTint == null) { 5055 mBackgroundTint = new TintInfo(); 5056 } 5057 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 5058 R.styleable.View_backgroundTintMode, -1), null); 5059 mBackgroundTint.mHasTintMode = true; 5060 break; 5061 case R.styleable.View_outlineProvider: 5062 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5063 PROVIDER_BACKGROUND)); 5064 break; 5065 case R.styleable.View_foreground: 5066 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5067 setForeground(a.getDrawable(attr)); 5068 } 5069 break; 5070 case R.styleable.View_foregroundGravity: 5071 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5072 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5073 } 5074 break; 5075 case R.styleable.View_foregroundTintMode: 5076 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5077 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 5078 } 5079 break; 5080 case R.styleable.View_foregroundTint: 5081 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5082 setForegroundTintList(a.getColorStateList(attr)); 5083 } 5084 break; 5085 case R.styleable.View_foregroundInsidePadding: 5086 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5087 if (mForegroundInfo == null) { 5088 mForegroundInfo = new ForegroundInfo(); 5089 } 5090 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5091 mForegroundInfo.mInsidePadding); 5092 } 5093 break; 5094 case R.styleable.View_scrollIndicators: 5095 final int scrollIndicators = 5096 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5097 & SCROLL_INDICATORS_PFLAG3_MASK; 5098 if (scrollIndicators != 0) { 5099 mPrivateFlags3 |= scrollIndicators; 5100 initializeScrollIndicators = true; 5101 } 5102 break; 5103 case R.styleable.View_pointerIcon: 5104 final int resourceId = a.getResourceId(attr, 0); 5105 if (resourceId != 0) { 5106 setPointerIcon(PointerIcon.load( 5107 context.getResources(), resourceId)); 5108 } else { 5109 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5110 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5111 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5112 } 5113 } 5114 break; 5115 case R.styleable.View_forceHasOverlappingRendering: 5116 if (a.peekValue(attr) != null) { 5117 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5118 } 5119 break; 5120 case R.styleable.View_tooltipText: 5121 setTooltipText(a.getText(attr)); 5122 break; 5123 case R.styleable.View_keyboardNavigationCluster: 5124 if (a.peekValue(attr) != null) { 5125 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5126 } 5127 break; 5128 case R.styleable.View_focusedByDefault: 5129 if (a.peekValue(attr) != null) { 5130 setFocusedByDefault(a.getBoolean(attr, true)); 5131 } 5132 break; 5133 case R.styleable.View_autofillHints: 5134 if (a.peekValue(attr) != null) { 5135 CharSequence[] rawHints = null; 5136 String rawString = null; 5137 5138 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5139 int resId = a.getResourceId(attr, 0); 5140 5141 try { 5142 rawHints = a.getTextArray(attr); 5143 } catch (Resources.NotFoundException e) { 5144 rawString = getResources().getString(resId); 5145 } 5146 } else { 5147 rawString = a.getString(attr); 5148 } 5149 5150 if (rawHints == null) { 5151 if (rawString == null) { 5152 throw new IllegalArgumentException( 5153 "Could not resolve autofillHints"); 5154 } else { 5155 rawHints = rawString.split(","); 5156 } 5157 } 5158 5159 String[] hints = new String[rawHints.length]; 5160 5161 int numHints = rawHints.length; 5162 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5163 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5164 } 5165 setAutofillHints(hints); 5166 } 5167 break; 5168 case R.styleable.View_importantForAutofill: 5169 if (a.peekValue(attr) != null) { 5170 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5171 } 5172 break; 5173 case R.styleable.View_defaultFocusHighlightEnabled: 5174 if (a.peekValue(attr) != null) { 5175 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 5176 } 5177 break; 5178 } 5179 } 5180 5181 setOverScrollMode(overScrollMode); 5182 5183 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 5184 // the resolved layout direction). Those cached values will be used later during padding 5185 // resolution. 5186 mUserPaddingStart = startPadding; 5187 mUserPaddingEnd = endPadding; 5188 5189 if (background != null) { 5190 setBackground(background); 5191 } 5192 5193 // setBackground above will record that padding is currently provided by the background. 5194 // If we have padding specified via xml, record that here instead and use it. 5195 mLeftPaddingDefined = leftPaddingDefined; 5196 mRightPaddingDefined = rightPaddingDefined; 5197 5198 if (padding >= 0) { 5199 leftPadding = padding; 5200 topPadding = padding; 5201 rightPadding = padding; 5202 bottomPadding = padding; 5203 mUserPaddingLeftInitial = padding; 5204 mUserPaddingRightInitial = padding; 5205 } else { 5206 if (paddingHorizontal >= 0) { 5207 leftPadding = paddingHorizontal; 5208 rightPadding = paddingHorizontal; 5209 mUserPaddingLeftInitial = paddingHorizontal; 5210 mUserPaddingRightInitial = paddingHorizontal; 5211 } 5212 if (paddingVertical >= 0) { 5213 topPadding = paddingVertical; 5214 bottomPadding = paddingVertical; 5215 } 5216 } 5217 5218 if (isRtlCompatibilityMode()) { 5219 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 5220 // left / right padding are used if defined (meaning here nothing to do). If they are not 5221 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 5222 // start / end and resolve them as left / right (layout direction is not taken into account). 5223 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5224 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5225 // defined. 5226 if (!mLeftPaddingDefined && startPaddingDefined) { 5227 leftPadding = startPadding; 5228 } 5229 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 5230 if (!mRightPaddingDefined && endPaddingDefined) { 5231 rightPadding = endPadding; 5232 } 5233 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 5234 } else { 5235 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 5236 // values defined. Otherwise, left /right values are used. 5237 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5238 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5239 // defined. 5240 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 5241 5242 if (mLeftPaddingDefined && !hasRelativePadding) { 5243 mUserPaddingLeftInitial = leftPadding; 5244 } 5245 if (mRightPaddingDefined && !hasRelativePadding) { 5246 mUserPaddingRightInitial = rightPadding; 5247 } 5248 } 5249 5250 internalSetPadding( 5251 mUserPaddingLeftInitial, 5252 topPadding >= 0 ? topPadding : mPaddingTop, 5253 mUserPaddingRightInitial, 5254 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 5255 5256 if (viewFlagMasks != 0) { 5257 setFlags(viewFlagValues, viewFlagMasks); 5258 } 5259 5260 if (initializeScrollbars) { 5261 initializeScrollbarsInternal(a); 5262 } 5263 5264 if (initializeScrollIndicators) { 5265 initializeScrollIndicatorsInternal(); 5266 } 5267 5268 a.recycle(); 5269 5270 // Needs to be called after mViewFlags is set 5271 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5272 recomputePadding(); 5273 } 5274 5275 if (x != 0 || y != 0) { 5276 scrollTo(x, y); 5277 } 5278 5279 if (transformSet) { 5280 setTranslationX(tx); 5281 setTranslationY(ty); 5282 setTranslationZ(tz); 5283 setElevation(elevation); 5284 setRotation(rotation); 5285 setRotationX(rotationX); 5286 setRotationY(rotationY); 5287 setScaleX(sx); 5288 setScaleY(sy); 5289 } 5290 5291 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 5292 setScrollContainer(true); 5293 } 5294 5295 computeOpaqueFlags(); 5296 } 5297 5298 /** 5299 * An implementation of OnClickListener that attempts to lazily load a 5300 * named click handling method from a parent or ancestor context. 5301 */ 5302 private static class DeclaredOnClickListener implements OnClickListener { 5303 private final View mHostView; 5304 private final String mMethodName; 5305 5306 private Method mResolvedMethod; 5307 private Context mResolvedContext; 5308 5309 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 5310 mHostView = hostView; 5311 mMethodName = methodName; 5312 } 5313 5314 @Override 5315 public void onClick(@NonNull View v) { 5316 if (mResolvedMethod == null) { 5317 resolveMethod(mHostView.getContext(), mMethodName); 5318 } 5319 5320 try { 5321 mResolvedMethod.invoke(mResolvedContext, v); 5322 } catch (IllegalAccessException e) { 5323 throw new IllegalStateException( 5324 "Could not execute non-public method for android:onClick", e); 5325 } catch (InvocationTargetException e) { 5326 throw new IllegalStateException( 5327 "Could not execute method for android:onClick", e); 5328 } 5329 } 5330 5331 @NonNull 5332 private void resolveMethod(@Nullable Context context, @NonNull String name) { 5333 while (context != null) { 5334 try { 5335 if (!context.isRestricted()) { 5336 final Method method = context.getClass().getMethod(mMethodName, View.class); 5337 if (method != null) { 5338 mResolvedMethod = method; 5339 mResolvedContext = context; 5340 return; 5341 } 5342 } 5343 } catch (NoSuchMethodException e) { 5344 // Failed to find method, keep searching up the hierarchy. 5345 } 5346 5347 if (context instanceof ContextWrapper) { 5348 context = ((ContextWrapper) context).getBaseContext(); 5349 } else { 5350 // Can't search up the hierarchy, null out and fail. 5351 context = null; 5352 } 5353 } 5354 5355 final int id = mHostView.getId(); 5356 final String idText = id == NO_ID ? "" : " with id '" 5357 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 5358 throw new IllegalStateException("Could not find method " + mMethodName 5359 + "(View) in a parent or ancestor Context for android:onClick " 5360 + "attribute defined on view " + mHostView.getClass() + idText); 5361 } 5362 } 5363 5364 /** 5365 * Non-public constructor for use in testing 5366 */ 5367 View() { 5368 mResources = null; 5369 mRenderNode = RenderNode.create(getClass().getName(), this); 5370 } 5371 5372 final boolean debugDraw() { 5373 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 5374 } 5375 5376 private static SparseArray<String> getAttributeMap() { 5377 if (mAttributeMap == null) { 5378 mAttributeMap = new SparseArray<>(); 5379 } 5380 return mAttributeMap; 5381 } 5382 5383 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 5384 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 5385 final int indexCount = t.getIndexCount(); 5386 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 5387 5388 int i = 0; 5389 5390 // Store raw XML attributes. 5391 for (int j = 0; j < attrsCount; ++j) { 5392 attributes[i] = attrs.getAttributeName(j); 5393 attributes[i + 1] = attrs.getAttributeValue(j); 5394 i += 2; 5395 } 5396 5397 // Store resolved styleable attributes. 5398 final Resources res = t.getResources(); 5399 final SparseArray<String> attributeMap = getAttributeMap(); 5400 for (int j = 0; j < indexCount; ++j) { 5401 final int index = t.getIndex(j); 5402 if (!t.hasValueOrEmpty(index)) { 5403 // Value is undefined. Skip it. 5404 continue; 5405 } 5406 5407 final int resourceId = t.getResourceId(index, 0); 5408 if (resourceId == 0) { 5409 // Value is not a reference. Skip it. 5410 continue; 5411 } 5412 5413 String resourceName = attributeMap.get(resourceId); 5414 if (resourceName == null) { 5415 try { 5416 resourceName = res.getResourceName(resourceId); 5417 } catch (Resources.NotFoundException e) { 5418 resourceName = "0x" + Integer.toHexString(resourceId); 5419 } 5420 attributeMap.put(resourceId, resourceName); 5421 } 5422 5423 attributes[i] = resourceName; 5424 attributes[i + 1] = t.getString(index); 5425 i += 2; 5426 } 5427 5428 // Trim to fit contents. 5429 final String[] trimmed = new String[i]; 5430 System.arraycopy(attributes, 0, trimmed, 0, i); 5431 mAttributes = trimmed; 5432 } 5433 5434 public String toString() { 5435 StringBuilder out = new StringBuilder(128); 5436 out.append(getClass().getName()); 5437 out.append('{'); 5438 out.append(Integer.toHexString(System.identityHashCode(this))); 5439 out.append(' '); 5440 switch (mViewFlags&VISIBILITY_MASK) { 5441 case VISIBLE: out.append('V'); break; 5442 case INVISIBLE: out.append('I'); break; 5443 case GONE: out.append('G'); break; 5444 default: out.append('.'); break; 5445 } 5446 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 5447 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5448 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5449 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5450 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5451 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5452 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5453 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5454 out.append(' '); 5455 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5456 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5457 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5458 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5459 out.append('p'); 5460 } else { 5461 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5462 } 5463 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5464 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5465 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5466 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5467 out.append(' '); 5468 out.append(mLeft); 5469 out.append(','); 5470 out.append(mTop); 5471 out.append('-'); 5472 out.append(mRight); 5473 out.append(','); 5474 out.append(mBottom); 5475 final int id = getId(); 5476 if (id != NO_ID) { 5477 out.append(" #"); 5478 out.append(Integer.toHexString(id)); 5479 final Resources r = mResources; 5480 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5481 try { 5482 String pkgname; 5483 switch (id&0xff000000) { 5484 case 0x7f000000: 5485 pkgname="app"; 5486 break; 5487 case 0x01000000: 5488 pkgname="android"; 5489 break; 5490 default: 5491 pkgname = r.getResourcePackageName(id); 5492 break; 5493 } 5494 String typename = r.getResourceTypeName(id); 5495 String entryname = r.getResourceEntryName(id); 5496 out.append(" "); 5497 out.append(pkgname); 5498 out.append(":"); 5499 out.append(typename); 5500 out.append("/"); 5501 out.append(entryname); 5502 } catch (Resources.NotFoundException e) { 5503 } 5504 } 5505 } 5506 out.append("}"); 5507 return out.toString(); 5508 } 5509 5510 /** 5511 * <p> 5512 * Initializes the fading edges from a given set of styled attributes. This 5513 * method should be called by subclasses that need fading edges and when an 5514 * instance of these subclasses is created programmatically rather than 5515 * being inflated from XML. This method is automatically called when the XML 5516 * is inflated. 5517 * </p> 5518 * 5519 * @param a the styled attributes set to initialize the fading edges from 5520 * 5521 * @removed 5522 */ 5523 protected void initializeFadingEdge(TypedArray a) { 5524 // This method probably shouldn't have been included in the SDK to begin with. 5525 // It relies on 'a' having been initialized using an attribute filter array that is 5526 // not publicly available to the SDK. The old method has been renamed 5527 // to initializeFadingEdgeInternal and hidden for framework use only; 5528 // this one initializes using defaults to make it safe to call for apps. 5529 5530 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5531 5532 initializeFadingEdgeInternal(arr); 5533 5534 arr.recycle(); 5535 } 5536 5537 /** 5538 * <p> 5539 * Initializes the fading edges from a given set of styled attributes. This 5540 * method should be called by subclasses that need fading edges and when an 5541 * instance of these subclasses is created programmatically rather than 5542 * being inflated from XML. This method is automatically called when the XML 5543 * is inflated. 5544 * </p> 5545 * 5546 * @param a the styled attributes set to initialize the fading edges from 5547 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5548 */ 5549 protected void initializeFadingEdgeInternal(TypedArray a) { 5550 initScrollCache(); 5551 5552 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5553 R.styleable.View_fadingEdgeLength, 5554 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5555 } 5556 5557 /** 5558 * Returns the size of the vertical faded edges used to indicate that more 5559 * content in this view is visible. 5560 * 5561 * @return The size in pixels of the vertical faded edge or 0 if vertical 5562 * faded edges are not enabled for this view. 5563 * @attr ref android.R.styleable#View_fadingEdgeLength 5564 */ 5565 public int getVerticalFadingEdgeLength() { 5566 if (isVerticalFadingEdgeEnabled()) { 5567 ScrollabilityCache cache = mScrollCache; 5568 if (cache != null) { 5569 return cache.fadingEdgeLength; 5570 } 5571 } 5572 return 0; 5573 } 5574 5575 /** 5576 * Set the size of the faded edge used to indicate that more content in this 5577 * view is available. Will not change whether the fading edge is enabled; use 5578 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5579 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5580 * for the vertical or horizontal fading edges. 5581 * 5582 * @param length The size in pixels of the faded edge used to indicate that more 5583 * content in this view is visible. 5584 */ 5585 public void setFadingEdgeLength(int length) { 5586 initScrollCache(); 5587 mScrollCache.fadingEdgeLength = length; 5588 } 5589 5590 /** 5591 * Returns the size of the horizontal faded edges used to indicate that more 5592 * content in this view is visible. 5593 * 5594 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5595 * faded edges are not enabled for this view. 5596 * @attr ref android.R.styleable#View_fadingEdgeLength 5597 */ 5598 public int getHorizontalFadingEdgeLength() { 5599 if (isHorizontalFadingEdgeEnabled()) { 5600 ScrollabilityCache cache = mScrollCache; 5601 if (cache != null) { 5602 return cache.fadingEdgeLength; 5603 } 5604 } 5605 return 0; 5606 } 5607 5608 /** 5609 * Returns the width of the vertical scrollbar. 5610 * 5611 * @return The width in pixels of the vertical scrollbar or 0 if there 5612 * is no vertical scrollbar. 5613 */ 5614 public int getVerticalScrollbarWidth() { 5615 ScrollabilityCache cache = mScrollCache; 5616 if (cache != null) { 5617 ScrollBarDrawable scrollBar = cache.scrollBar; 5618 if (scrollBar != null) { 5619 int size = scrollBar.getSize(true); 5620 if (size <= 0) { 5621 size = cache.scrollBarSize; 5622 } 5623 return size; 5624 } 5625 return 0; 5626 } 5627 return 0; 5628 } 5629 5630 /** 5631 * Returns the height of the horizontal scrollbar. 5632 * 5633 * @return The height in pixels of the horizontal scrollbar or 0 if 5634 * there is no horizontal scrollbar. 5635 */ 5636 protected int getHorizontalScrollbarHeight() { 5637 ScrollabilityCache cache = mScrollCache; 5638 if (cache != null) { 5639 ScrollBarDrawable scrollBar = cache.scrollBar; 5640 if (scrollBar != null) { 5641 int size = scrollBar.getSize(false); 5642 if (size <= 0) { 5643 size = cache.scrollBarSize; 5644 } 5645 return size; 5646 } 5647 return 0; 5648 } 5649 return 0; 5650 } 5651 5652 /** 5653 * <p> 5654 * Initializes the scrollbars from a given set of styled attributes. This 5655 * method should be called by subclasses that need scrollbars and when an 5656 * instance of these subclasses is created programmatically rather than 5657 * being inflated from XML. This method is automatically called when the XML 5658 * is inflated. 5659 * </p> 5660 * 5661 * @param a the styled attributes set to initialize the scrollbars from 5662 * 5663 * @removed 5664 */ 5665 protected void initializeScrollbars(TypedArray a) { 5666 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5667 // using the View filter array which is not available to the SDK. As such, internal 5668 // framework usage now uses initializeScrollbarsInternal and we grab a default 5669 // TypedArray with the right filter instead here. 5670 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5671 5672 initializeScrollbarsInternal(arr); 5673 5674 // We ignored the method parameter. Recycle the one we actually did use. 5675 arr.recycle(); 5676 } 5677 5678 /** 5679 * <p> 5680 * Initializes the scrollbars from a given set of styled attributes. This 5681 * method should be called by subclasses that need scrollbars and when an 5682 * instance of these subclasses is created programmatically rather than 5683 * being inflated from XML. This method is automatically called when the XML 5684 * is inflated. 5685 * </p> 5686 * 5687 * @param a the styled attributes set to initialize the scrollbars from 5688 * @hide 5689 */ 5690 protected void initializeScrollbarsInternal(TypedArray a) { 5691 initScrollCache(); 5692 5693 final ScrollabilityCache scrollabilityCache = mScrollCache; 5694 5695 if (scrollabilityCache.scrollBar == null) { 5696 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5697 scrollabilityCache.scrollBar.setState(getDrawableState()); 5698 scrollabilityCache.scrollBar.setCallback(this); 5699 } 5700 5701 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5702 5703 if (!fadeScrollbars) { 5704 scrollabilityCache.state = ScrollabilityCache.ON; 5705 } 5706 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5707 5708 5709 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5710 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5711 .getScrollBarFadeDuration()); 5712 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5713 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5714 ViewConfiguration.getScrollDefaultDelay()); 5715 5716 5717 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5718 com.android.internal.R.styleable.View_scrollbarSize, 5719 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5720 5721 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5722 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5723 5724 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5725 if (thumb != null) { 5726 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5727 } 5728 5729 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5730 false); 5731 if (alwaysDraw) { 5732 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5733 } 5734 5735 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5736 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5737 5738 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5739 if (thumb != null) { 5740 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5741 } 5742 5743 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5744 false); 5745 if (alwaysDraw) { 5746 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5747 } 5748 5749 // Apply layout direction to the new Drawables if needed 5750 final int layoutDirection = getLayoutDirection(); 5751 if (track != null) { 5752 track.setLayoutDirection(layoutDirection); 5753 } 5754 if (thumb != null) { 5755 thumb.setLayoutDirection(layoutDirection); 5756 } 5757 5758 // Re-apply user/background padding so that scrollbar(s) get added 5759 resolvePadding(); 5760 } 5761 5762 private void initializeScrollIndicatorsInternal() { 5763 // Some day maybe we'll break this into top/left/start/etc. and let the 5764 // client control it. Until then, you can have any scroll indicator you 5765 // want as long as it's a 1dp foreground-colored rectangle. 5766 if (mScrollIndicatorDrawable == null) { 5767 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5768 } 5769 } 5770 5771 /** 5772 * <p> 5773 * Initalizes the scrollability cache if necessary. 5774 * </p> 5775 */ 5776 private void initScrollCache() { 5777 if (mScrollCache == null) { 5778 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5779 } 5780 } 5781 5782 private ScrollabilityCache getScrollCache() { 5783 initScrollCache(); 5784 return mScrollCache; 5785 } 5786 5787 /** 5788 * Set the position of the vertical scroll bar. Should be one of 5789 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5790 * {@link #SCROLLBAR_POSITION_RIGHT}. 5791 * 5792 * @param position Where the vertical scroll bar should be positioned. 5793 */ 5794 public void setVerticalScrollbarPosition(int position) { 5795 if (mVerticalScrollbarPosition != position) { 5796 mVerticalScrollbarPosition = position; 5797 computeOpaqueFlags(); 5798 resolvePadding(); 5799 } 5800 } 5801 5802 /** 5803 * @return The position where the vertical scroll bar will show, if applicable. 5804 * @see #setVerticalScrollbarPosition(int) 5805 */ 5806 public int getVerticalScrollbarPosition() { 5807 return mVerticalScrollbarPosition; 5808 } 5809 5810 boolean isOnScrollbar(float x, float y) { 5811 if (mScrollCache == null) { 5812 return false; 5813 } 5814 x += getScrollX(); 5815 y += getScrollY(); 5816 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5817 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5818 getVerticalScrollBarBounds(null, touchBounds); 5819 if (touchBounds.contains((int) x, (int) y)) { 5820 return true; 5821 } 5822 } 5823 if (isHorizontalScrollBarEnabled()) { 5824 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5825 getHorizontalScrollBarBounds(null, touchBounds); 5826 if (touchBounds.contains((int) x, (int) y)) { 5827 return true; 5828 } 5829 } 5830 return false; 5831 } 5832 5833 boolean isOnScrollbarThumb(float x, float y) { 5834 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5835 } 5836 5837 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5838 if (mScrollCache == null) { 5839 return false; 5840 } 5841 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5842 x += getScrollX(); 5843 y += getScrollY(); 5844 final Rect bounds = mScrollCache.mScrollBarBounds; 5845 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5846 getVerticalScrollBarBounds(bounds, touchBounds); 5847 final int range = computeVerticalScrollRange(); 5848 final int offset = computeVerticalScrollOffset(); 5849 final int extent = computeVerticalScrollExtent(); 5850 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5851 extent, range); 5852 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5853 extent, range, offset); 5854 final int thumbTop = bounds.top + thumbOffset; 5855 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5856 if (x >= touchBounds.left && x <= touchBounds.right 5857 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 5858 return true; 5859 } 5860 } 5861 return false; 5862 } 5863 5864 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5865 if (mScrollCache == null) { 5866 return false; 5867 } 5868 if (isHorizontalScrollBarEnabled()) { 5869 x += getScrollX(); 5870 y += getScrollY(); 5871 final Rect bounds = mScrollCache.mScrollBarBounds; 5872 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5873 getHorizontalScrollBarBounds(bounds, touchBounds); 5874 final int range = computeHorizontalScrollRange(); 5875 final int offset = computeHorizontalScrollOffset(); 5876 final int extent = computeHorizontalScrollExtent(); 5877 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5878 extent, range); 5879 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5880 extent, range, offset); 5881 final int thumbLeft = bounds.left + thumbOffset; 5882 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5883 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 5884 && y >= touchBounds.top && y <= touchBounds.bottom) { 5885 return true; 5886 } 5887 } 5888 return false; 5889 } 5890 5891 boolean isDraggingScrollBar() { 5892 return mScrollCache != null 5893 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5894 } 5895 5896 /** 5897 * Sets the state of all scroll indicators. 5898 * <p> 5899 * See {@link #setScrollIndicators(int, int)} for usage information. 5900 * 5901 * @param indicators a bitmask of indicators that should be enabled, or 5902 * {@code 0} to disable all indicators 5903 * @see #setScrollIndicators(int, int) 5904 * @see #getScrollIndicators() 5905 * @attr ref android.R.styleable#View_scrollIndicators 5906 */ 5907 public void setScrollIndicators(@ScrollIndicators int indicators) { 5908 setScrollIndicators(indicators, 5909 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5910 } 5911 5912 /** 5913 * Sets the state of the scroll indicators specified by the mask. To change 5914 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5915 * <p> 5916 * When a scroll indicator is enabled, it will be displayed if the view 5917 * can scroll in the direction of the indicator. 5918 * <p> 5919 * Multiple indicator types may be enabled or disabled by passing the 5920 * logical OR of the desired types. If multiple types are specified, they 5921 * will all be set to the same enabled state. 5922 * <p> 5923 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5924 * 5925 * @param indicators the indicator direction, or the logical OR of multiple 5926 * indicator directions. One or more of: 5927 * <ul> 5928 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5929 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5930 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5931 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5932 * <li>{@link #SCROLL_INDICATOR_START}</li> 5933 * <li>{@link #SCROLL_INDICATOR_END}</li> 5934 * </ul> 5935 * @see #setScrollIndicators(int) 5936 * @see #getScrollIndicators() 5937 * @attr ref android.R.styleable#View_scrollIndicators 5938 */ 5939 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5940 // Shift and sanitize mask. 5941 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5942 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5943 5944 // Shift and mask indicators. 5945 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5946 indicators &= mask; 5947 5948 // Merge with non-masked flags. 5949 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5950 5951 if (mPrivateFlags3 != updatedFlags) { 5952 mPrivateFlags3 = updatedFlags; 5953 5954 if (indicators != 0) { 5955 initializeScrollIndicatorsInternal(); 5956 } 5957 invalidate(); 5958 } 5959 } 5960 5961 /** 5962 * Returns a bitmask representing the enabled scroll indicators. 5963 * <p> 5964 * For example, if the top and left scroll indicators are enabled and all 5965 * other indicators are disabled, the return value will be 5966 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5967 * <p> 5968 * To check whether the bottom scroll indicator is enabled, use the value 5969 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5970 * 5971 * @return a bitmask representing the enabled scroll indicators 5972 */ 5973 @ScrollIndicators 5974 public int getScrollIndicators() { 5975 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5976 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5977 } 5978 5979 ListenerInfo getListenerInfo() { 5980 if (mListenerInfo != null) { 5981 return mListenerInfo; 5982 } 5983 mListenerInfo = new ListenerInfo(); 5984 return mListenerInfo; 5985 } 5986 5987 /** 5988 * Register a callback to be invoked when the scroll X or Y positions of 5989 * this view change. 5990 * <p> 5991 * <b>Note:</b> Some views handle scrolling independently from View and may 5992 * have their own separate listeners for scroll-type events. For example, 5993 * {@link android.widget.ListView ListView} allows clients to register an 5994 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 5995 * to listen for changes in list scroll position. 5996 * 5997 * @param l The listener to notify when the scroll X or Y position changes. 5998 * @see android.view.View#getScrollX() 5999 * @see android.view.View#getScrollY() 6000 */ 6001 public void setOnScrollChangeListener(OnScrollChangeListener l) { 6002 getListenerInfo().mOnScrollChangeListener = l; 6003 } 6004 6005 /** 6006 * Register a callback to be invoked when focus of this view changed. 6007 * 6008 * @param l The callback that will run. 6009 */ 6010 public void setOnFocusChangeListener(OnFocusChangeListener l) { 6011 getListenerInfo().mOnFocusChangeListener = l; 6012 } 6013 6014 /** 6015 * Add a listener that will be called when the bounds of the view change due to 6016 * layout processing. 6017 * 6018 * @param listener The listener that will be called when layout bounds change. 6019 */ 6020 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 6021 ListenerInfo li = getListenerInfo(); 6022 if (li.mOnLayoutChangeListeners == null) { 6023 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 6024 } 6025 if (!li.mOnLayoutChangeListeners.contains(listener)) { 6026 li.mOnLayoutChangeListeners.add(listener); 6027 } 6028 } 6029 6030 /** 6031 * Remove a listener for layout changes. 6032 * 6033 * @param listener The listener for layout bounds change. 6034 */ 6035 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 6036 ListenerInfo li = mListenerInfo; 6037 if (li == null || li.mOnLayoutChangeListeners == null) { 6038 return; 6039 } 6040 li.mOnLayoutChangeListeners.remove(listener); 6041 } 6042 6043 /** 6044 * Add a listener for attach state changes. 6045 * 6046 * This listener will be called whenever this view is attached or detached 6047 * from a window. Remove the listener using 6048 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 6049 * 6050 * @param listener Listener to attach 6051 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 6052 */ 6053 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6054 ListenerInfo li = getListenerInfo(); 6055 if (li.mOnAttachStateChangeListeners == null) { 6056 li.mOnAttachStateChangeListeners 6057 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 6058 } 6059 li.mOnAttachStateChangeListeners.add(listener); 6060 } 6061 6062 /** 6063 * Remove a listener for attach state changes. The listener will receive no further 6064 * notification of window attach/detach events. 6065 * 6066 * @param listener Listener to remove 6067 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 6068 */ 6069 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6070 ListenerInfo li = mListenerInfo; 6071 if (li == null || li.mOnAttachStateChangeListeners == null) { 6072 return; 6073 } 6074 li.mOnAttachStateChangeListeners.remove(listener); 6075 } 6076 6077 /** 6078 * Returns the focus-change callback registered for this view. 6079 * 6080 * @return The callback, or null if one is not registered. 6081 */ 6082 public OnFocusChangeListener getOnFocusChangeListener() { 6083 ListenerInfo li = mListenerInfo; 6084 return li != null ? li.mOnFocusChangeListener : null; 6085 } 6086 6087 /** 6088 * Register a callback to be invoked when this view is clicked. If this view is not 6089 * clickable, it becomes clickable. 6090 * 6091 * @param l The callback that will run 6092 * 6093 * @see #setClickable(boolean) 6094 */ 6095 public void setOnClickListener(@Nullable OnClickListener l) { 6096 if (!isClickable()) { 6097 setClickable(true); 6098 } 6099 getListenerInfo().mOnClickListener = l; 6100 } 6101 6102 /** 6103 * Return whether this view has an attached OnClickListener. Returns 6104 * true if there is a listener, false if there is none. 6105 */ 6106 public boolean hasOnClickListeners() { 6107 ListenerInfo li = mListenerInfo; 6108 return (li != null && li.mOnClickListener != null); 6109 } 6110 6111 /** 6112 * Register a callback to be invoked when this view is clicked and held. If this view is not 6113 * long clickable, it becomes long clickable. 6114 * 6115 * @param l The callback that will run 6116 * 6117 * @see #setLongClickable(boolean) 6118 */ 6119 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 6120 if (!isLongClickable()) { 6121 setLongClickable(true); 6122 } 6123 getListenerInfo().mOnLongClickListener = l; 6124 } 6125 6126 /** 6127 * Register a callback to be invoked when this view is context clicked. If the view is not 6128 * context clickable, it becomes context clickable. 6129 * 6130 * @param l The callback that will run 6131 * @see #setContextClickable(boolean) 6132 */ 6133 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 6134 if (!isContextClickable()) { 6135 setContextClickable(true); 6136 } 6137 getListenerInfo().mOnContextClickListener = l; 6138 } 6139 6140 /** 6141 * Register a callback to be invoked when the context menu for this view is 6142 * being built. If this view is not long clickable, it becomes long clickable. 6143 * 6144 * @param l The callback that will run 6145 * 6146 */ 6147 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 6148 if (!isLongClickable()) { 6149 setLongClickable(true); 6150 } 6151 getListenerInfo().mOnCreateContextMenuListener = l; 6152 } 6153 6154 /** 6155 * Set an observer to collect stats for each frame rendered for this view. 6156 * 6157 * @hide 6158 */ 6159 public void addFrameMetricsListener(Window window, 6160 Window.OnFrameMetricsAvailableListener listener, 6161 Handler handler) { 6162 if (mAttachInfo != null) { 6163 if (mAttachInfo.mThreadedRenderer != null) { 6164 if (mFrameMetricsObservers == null) { 6165 mFrameMetricsObservers = new ArrayList<>(); 6166 } 6167 6168 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6169 handler.getLooper(), listener); 6170 mFrameMetricsObservers.add(fmo); 6171 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 6172 } else { 6173 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6174 } 6175 } else { 6176 if (mFrameMetricsObservers == null) { 6177 mFrameMetricsObservers = new ArrayList<>(); 6178 } 6179 6180 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6181 handler.getLooper(), listener); 6182 mFrameMetricsObservers.add(fmo); 6183 } 6184 } 6185 6186 /** 6187 * Remove observer configured to collect frame stats for this view. 6188 * 6189 * @hide 6190 */ 6191 public void removeFrameMetricsListener( 6192 Window.OnFrameMetricsAvailableListener listener) { 6193 ThreadedRenderer renderer = getThreadedRenderer(); 6194 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 6195 if (fmo == null) { 6196 throw new IllegalArgumentException( 6197 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 6198 } 6199 6200 if (mFrameMetricsObservers != null) { 6201 mFrameMetricsObservers.remove(fmo); 6202 if (renderer != null) { 6203 renderer.removeFrameMetricsObserver(fmo); 6204 } 6205 } 6206 } 6207 6208 private void registerPendingFrameMetricsObservers() { 6209 if (mFrameMetricsObservers != null) { 6210 ThreadedRenderer renderer = getThreadedRenderer(); 6211 if (renderer != null) { 6212 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 6213 renderer.addFrameMetricsObserver(fmo); 6214 } 6215 } else { 6216 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6217 } 6218 } 6219 } 6220 6221 private FrameMetricsObserver findFrameMetricsObserver( 6222 Window.OnFrameMetricsAvailableListener listener) { 6223 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 6224 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 6225 if (observer.mListener == listener) { 6226 return observer; 6227 } 6228 } 6229 6230 return null; 6231 } 6232 6233 /** 6234 * Call this view's OnClickListener, if it is defined. Performs all normal 6235 * actions associated with clicking: reporting accessibility event, playing 6236 * a sound, etc. 6237 * 6238 * @return True there was an assigned OnClickListener that was called, false 6239 * otherwise is returned. 6240 */ 6241 public boolean performClick() { 6242 final boolean result; 6243 final ListenerInfo li = mListenerInfo; 6244 if (li != null && li.mOnClickListener != null) { 6245 playSoundEffect(SoundEffectConstants.CLICK); 6246 li.mOnClickListener.onClick(this); 6247 result = true; 6248 } else { 6249 result = false; 6250 } 6251 6252 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 6253 6254 notifyEnterOrExitForAutoFillIfNeeded(true); 6255 6256 return result; 6257 } 6258 6259 /** 6260 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 6261 * this only calls the listener, and does not do any associated clicking 6262 * actions like reporting an accessibility event. 6263 * 6264 * @return True there was an assigned OnClickListener that was called, false 6265 * otherwise is returned. 6266 */ 6267 public boolean callOnClick() { 6268 ListenerInfo li = mListenerInfo; 6269 if (li != null && li.mOnClickListener != null) { 6270 li.mOnClickListener.onClick(this); 6271 return true; 6272 } 6273 return false; 6274 } 6275 6276 /** 6277 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6278 * context menu if the OnLongClickListener did not consume the event. 6279 * 6280 * @return {@code true} if one of the above receivers consumed the event, 6281 * {@code false} otherwise 6282 */ 6283 public boolean performLongClick() { 6284 return performLongClickInternal(mLongClickX, mLongClickY); 6285 } 6286 6287 /** 6288 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6289 * context menu if the OnLongClickListener did not consume the event, 6290 * anchoring it to an (x,y) coordinate. 6291 * 6292 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6293 * to disable anchoring 6294 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6295 * to disable anchoring 6296 * @return {@code true} if one of the above receivers consumed the event, 6297 * {@code false} otherwise 6298 */ 6299 public boolean performLongClick(float x, float y) { 6300 mLongClickX = x; 6301 mLongClickY = y; 6302 final boolean handled = performLongClick(); 6303 mLongClickX = Float.NaN; 6304 mLongClickY = Float.NaN; 6305 return handled; 6306 } 6307 6308 /** 6309 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6310 * context menu if the OnLongClickListener did not consume the event, 6311 * optionally anchoring it to an (x,y) coordinate. 6312 * 6313 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6314 * to disable anchoring 6315 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6316 * to disable anchoring 6317 * @return {@code true} if one of the above receivers consumed the event, 6318 * {@code false} otherwise 6319 */ 6320 private boolean performLongClickInternal(float x, float y) { 6321 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 6322 6323 boolean handled = false; 6324 final ListenerInfo li = mListenerInfo; 6325 if (li != null && li.mOnLongClickListener != null) { 6326 handled = li.mOnLongClickListener.onLongClick(View.this); 6327 } 6328 if (!handled) { 6329 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 6330 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 6331 } 6332 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 6333 if (!handled) { 6334 handled = showLongClickTooltip((int) x, (int) y); 6335 } 6336 } 6337 if (handled) { 6338 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 6339 } 6340 return handled; 6341 } 6342 6343 /** 6344 * Call this view's OnContextClickListener, if it is defined. 6345 * 6346 * @param x the x coordinate of the context click 6347 * @param y the y coordinate of the context click 6348 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6349 * otherwise. 6350 */ 6351 public boolean performContextClick(float x, float y) { 6352 return performContextClick(); 6353 } 6354 6355 /** 6356 * Call this view's OnContextClickListener, if it is defined. 6357 * 6358 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6359 * otherwise. 6360 */ 6361 public boolean performContextClick() { 6362 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 6363 6364 boolean handled = false; 6365 ListenerInfo li = mListenerInfo; 6366 if (li != null && li.mOnContextClickListener != null) { 6367 handled = li.mOnContextClickListener.onContextClick(View.this); 6368 } 6369 if (handled) { 6370 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 6371 } 6372 return handled; 6373 } 6374 6375 /** 6376 * Performs button-related actions during a touch down event. 6377 * 6378 * @param event The event. 6379 * @return True if the down was consumed. 6380 * 6381 * @hide 6382 */ 6383 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 6384 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 6385 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 6386 showContextMenu(event.getX(), event.getY()); 6387 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 6388 return true; 6389 } 6390 return false; 6391 } 6392 6393 /** 6394 * Shows the context menu for this view. 6395 * 6396 * @return {@code true} if the context menu was shown, {@code false} 6397 * otherwise 6398 * @see #showContextMenu(float, float) 6399 */ 6400 public boolean showContextMenu() { 6401 return getParent().showContextMenuForChild(this); 6402 } 6403 6404 /** 6405 * Shows the context menu for this view anchored to the specified 6406 * view-relative coordinate. 6407 * 6408 * @param x the X coordinate in pixels relative to the view to which the 6409 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6410 * @param y the Y coordinate in pixels relative to the view to which the 6411 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6412 * @return {@code true} if the context menu was shown, {@code false} 6413 * otherwise 6414 */ 6415 public boolean showContextMenu(float x, float y) { 6416 return getParent().showContextMenuForChild(this, x, y); 6417 } 6418 6419 /** 6420 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 6421 * 6422 * @param callback Callback that will control the lifecycle of the action mode 6423 * @return The new action mode if it is started, null otherwise 6424 * 6425 * @see ActionMode 6426 * @see #startActionMode(android.view.ActionMode.Callback, int) 6427 */ 6428 public ActionMode startActionMode(ActionMode.Callback callback) { 6429 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 6430 } 6431 6432 /** 6433 * Start an action mode with the given type. 6434 * 6435 * @param callback Callback that will control the lifecycle of the action mode 6436 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 6437 * @return The new action mode if it is started, null otherwise 6438 * 6439 * @see ActionMode 6440 */ 6441 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6442 ViewParent parent = getParent(); 6443 if (parent == null) return null; 6444 try { 6445 return parent.startActionModeForChild(this, callback, type); 6446 } catch (AbstractMethodError ame) { 6447 // Older implementations of custom views might not implement this. 6448 return parent.startActionModeForChild(this, callback); 6449 } 6450 } 6451 6452 /** 6453 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6454 * Context, creating a unique View identifier to retrieve the result. 6455 * 6456 * @param intent The Intent to be started. 6457 * @param requestCode The request code to use. 6458 * @hide 6459 */ 6460 public void startActivityForResult(Intent intent, int requestCode) { 6461 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6462 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6463 } 6464 6465 /** 6466 * If this View corresponds to the calling who, dispatches the activity result. 6467 * @param who The identifier for the targeted View to receive the result. 6468 * @param requestCode The integer request code originally supplied to 6469 * startActivityForResult(), allowing you to identify who this 6470 * result came from. 6471 * @param resultCode The integer result code returned by the child activity 6472 * through its setResult(). 6473 * @param data An Intent, which can return result data to the caller 6474 * (various data can be attached to Intent "extras"). 6475 * @return {@code true} if the activity result was dispatched. 6476 * @hide 6477 */ 6478 public boolean dispatchActivityResult( 6479 String who, int requestCode, int resultCode, Intent data) { 6480 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6481 onActivityResult(requestCode, resultCode, data); 6482 mStartActivityRequestWho = null; 6483 return true; 6484 } 6485 return false; 6486 } 6487 6488 /** 6489 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6490 * 6491 * @param requestCode The integer request code originally supplied to 6492 * startActivityForResult(), allowing you to identify who this 6493 * result came from. 6494 * @param resultCode The integer result code returned by the child activity 6495 * through its setResult(). 6496 * @param data An Intent, which can return result data to the caller 6497 * (various data can be attached to Intent "extras"). 6498 * @hide 6499 */ 6500 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6501 // Do nothing. 6502 } 6503 6504 /** 6505 * Register a callback to be invoked when a hardware key is pressed in this view. 6506 * Key presses in software input methods will generally not trigger the methods of 6507 * this listener. 6508 * @param l the key listener to attach to this view 6509 */ 6510 public void setOnKeyListener(OnKeyListener l) { 6511 getListenerInfo().mOnKeyListener = l; 6512 } 6513 6514 /** 6515 * Register a callback to be invoked when a touch event is sent to this view. 6516 * @param l the touch listener to attach to this view 6517 */ 6518 public void setOnTouchListener(OnTouchListener l) { 6519 getListenerInfo().mOnTouchListener = l; 6520 } 6521 6522 /** 6523 * Register a callback to be invoked when a generic motion event is sent to this view. 6524 * @param l the generic motion listener to attach to this view 6525 */ 6526 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6527 getListenerInfo().mOnGenericMotionListener = l; 6528 } 6529 6530 /** 6531 * Register a callback to be invoked when a hover event is sent to this view. 6532 * @param l the hover listener to attach to this view 6533 */ 6534 public void setOnHoverListener(OnHoverListener l) { 6535 getListenerInfo().mOnHoverListener = l; 6536 } 6537 6538 /** 6539 * Register a drag event listener callback object for this View. The parameter is 6540 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6541 * View, the system calls the 6542 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6543 * @param l An implementation of {@link android.view.View.OnDragListener}. 6544 */ 6545 public void setOnDragListener(OnDragListener l) { 6546 getListenerInfo().mOnDragListener = l; 6547 } 6548 6549 /** 6550 * Give this view focus. This will cause 6551 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6552 * 6553 * Note: this does not check whether this {@link View} should get focus, it just 6554 * gives it focus no matter what. It should only be called internally by framework 6555 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6556 * 6557 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6558 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6559 * focus moved when requestFocus() is called. It may not always 6560 * apply, in which case use the default View.FOCUS_DOWN. 6561 * @param previouslyFocusedRect The rectangle of the view that had focus 6562 * prior in this View's coordinate system. 6563 */ 6564 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6565 if (DBG) { 6566 System.out.println(this + " requestFocus()"); 6567 } 6568 6569 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6570 mPrivateFlags |= PFLAG_FOCUSED; 6571 6572 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6573 6574 if (mParent != null) { 6575 mParent.requestChildFocus(this, this); 6576 updateFocusedInCluster(oldFocus, direction); 6577 } 6578 6579 if (mAttachInfo != null) { 6580 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6581 } 6582 6583 onFocusChanged(true, direction, previouslyFocusedRect); 6584 refreshDrawableState(); 6585 } 6586 } 6587 6588 /** 6589 * Sets this view's preference for reveal behavior when it gains focus. 6590 * 6591 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6592 * this view would prefer to be brought fully into view when it gains focus. 6593 * For example, a text field that a user is meant to type into. Other views such 6594 * as scrolling containers may prefer to opt-out of this behavior.</p> 6595 * 6596 * <p>The default value for views is true, though subclasses may change this 6597 * based on their preferred behavior.</p> 6598 * 6599 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6600 * 6601 * @see #getRevealOnFocusHint() 6602 */ 6603 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6604 if (revealOnFocus) { 6605 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6606 } else { 6607 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6608 } 6609 } 6610 6611 /** 6612 * Returns this view's preference for reveal behavior when it gains focus. 6613 * 6614 * <p>When this method returns true for a child view requesting focus, ancestor 6615 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6616 * should make a best effort to make the newly focused child fully visible to the user. 6617 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6618 * other properties affecting visibility to the user as part of the focus change.</p> 6619 * 6620 * @return true if this view would prefer to become fully visible when it gains focus, 6621 * false if it would prefer not to disrupt scroll positioning 6622 * 6623 * @see #setRevealOnFocusHint(boolean) 6624 */ 6625 public final boolean getRevealOnFocusHint() { 6626 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6627 } 6628 6629 /** 6630 * Populates <code>outRect</code> with the hotspot bounds. By default, 6631 * the hotspot bounds are identical to the screen bounds. 6632 * 6633 * @param outRect rect to populate with hotspot bounds 6634 * @hide Only for internal use by views and widgets. 6635 */ 6636 public void getHotspotBounds(Rect outRect) { 6637 final Drawable background = getBackground(); 6638 if (background != null) { 6639 background.getHotspotBounds(outRect); 6640 } else { 6641 getBoundsOnScreen(outRect); 6642 } 6643 } 6644 6645 /** 6646 * Request that a rectangle of this view be visible on the screen, 6647 * scrolling if necessary just enough. 6648 * 6649 * <p>A View should call this if it maintains some notion of which part 6650 * of its content is interesting. For example, a text editing view 6651 * should call this when its cursor moves. 6652 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6653 * It should not be affected by which part of the View is currently visible or its scroll 6654 * position. 6655 * 6656 * @param rectangle The rectangle in the View's content coordinate space 6657 * @return Whether any parent scrolled. 6658 */ 6659 public boolean requestRectangleOnScreen(Rect rectangle) { 6660 return requestRectangleOnScreen(rectangle, false); 6661 } 6662 6663 /** 6664 * Request that a rectangle of this view be visible on the screen, 6665 * scrolling if necessary just enough. 6666 * 6667 * <p>A View should call this if it maintains some notion of which part 6668 * of its content is interesting. For example, a text editing view 6669 * should call this when its cursor moves. 6670 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6671 * It should not be affected by which part of the View is currently visible or its scroll 6672 * position. 6673 * <p>When <code>immediate</code> is set to true, scrolling will not be 6674 * animated. 6675 * 6676 * @param rectangle The rectangle in the View's content coordinate space 6677 * @param immediate True to forbid animated scrolling, false otherwise 6678 * @return Whether any parent scrolled. 6679 */ 6680 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6681 if (mParent == null) { 6682 return false; 6683 } 6684 6685 View child = this; 6686 6687 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6688 position.set(rectangle); 6689 6690 ViewParent parent = mParent; 6691 boolean scrolled = false; 6692 while (parent != null) { 6693 rectangle.set((int) position.left, (int) position.top, 6694 (int) position.right, (int) position.bottom); 6695 6696 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6697 6698 if (!(parent instanceof View)) { 6699 break; 6700 } 6701 6702 // move it from child's content coordinate space to parent's content coordinate space 6703 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6704 6705 child = (View) parent; 6706 parent = child.getParent(); 6707 } 6708 6709 return scrolled; 6710 } 6711 6712 /** 6713 * Called when this view wants to give up focus. If focus is cleared 6714 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6715 * <p> 6716 * <strong>Note:</strong> When a View clears focus the framework is trying 6717 * to give focus to the first focusable View from the top. Hence, if this 6718 * View is the first from the top that can take focus, then all callbacks 6719 * related to clearing focus will be invoked after which the framework will 6720 * give focus to this view. 6721 * </p> 6722 */ 6723 public void clearFocus() { 6724 if (DBG) { 6725 System.out.println(this + " clearFocus()"); 6726 } 6727 6728 clearFocusInternal(null, true, true); 6729 } 6730 6731 /** 6732 * Clears focus from the view, optionally propagating the change up through 6733 * the parent hierarchy and requesting that the root view place new focus. 6734 * 6735 * @param propagate whether to propagate the change up through the parent 6736 * hierarchy 6737 * @param refocus when propagate is true, specifies whether to request the 6738 * root view place new focus 6739 */ 6740 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6741 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6742 mPrivateFlags &= ~PFLAG_FOCUSED; 6743 6744 if (propagate && mParent != null) { 6745 mParent.clearChildFocus(this); 6746 } 6747 6748 onFocusChanged(false, 0, null); 6749 refreshDrawableState(); 6750 6751 if (propagate && (!refocus || !rootViewRequestFocus())) { 6752 notifyGlobalFocusCleared(this); 6753 } 6754 } 6755 } 6756 6757 void notifyGlobalFocusCleared(View oldFocus) { 6758 if (oldFocus != null && mAttachInfo != null) { 6759 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6760 } 6761 } 6762 6763 boolean rootViewRequestFocus() { 6764 final View root = getRootView(); 6765 return root != null && root.requestFocus(); 6766 } 6767 6768 /** 6769 * Called internally by the view system when a new view is getting focus. 6770 * This is what clears the old focus. 6771 * <p> 6772 * <b>NOTE:</b> The parent view's focused child must be updated manually 6773 * after calling this method. Otherwise, the view hierarchy may be left in 6774 * an inconstent state. 6775 */ 6776 void unFocus(View focused) { 6777 if (DBG) { 6778 System.out.println(this + " unFocus()"); 6779 } 6780 6781 clearFocusInternal(focused, false, false); 6782 } 6783 6784 /** 6785 * Returns true if this view has focus itself, or is the ancestor of the 6786 * view that has focus. 6787 * 6788 * @return True if this view has or contains focus, false otherwise. 6789 */ 6790 @ViewDebug.ExportedProperty(category = "focus") 6791 public boolean hasFocus() { 6792 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6793 } 6794 6795 /** 6796 * Returns true if this view is focusable or if it contains a reachable View 6797 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 6798 * is a view whose parents do not block descendants focus. 6799 * Only {@link #VISIBLE} views are considered focusable. 6800 * 6801 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 6802 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 6803 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 6804 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 6805 * {@code false} for views not explicitly marked as focusable. 6806 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 6807 * behavior.</p> 6808 * 6809 * @return {@code true} if the view is focusable or if the view contains a focusable 6810 * view, {@code false} otherwise 6811 * 6812 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6813 * @see ViewGroup#getTouchscreenBlocksFocus() 6814 * @see #hasExplicitFocusable() 6815 */ 6816 public boolean hasFocusable() { 6817 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 6818 } 6819 6820 /** 6821 * Returns true if this view is focusable or if it contains a reachable View 6822 * for which {@link #hasExplicitFocusable()} returns {@code true}. 6823 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 6824 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 6825 * {@link #FOCUSABLE} are considered focusable. 6826 * 6827 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 6828 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 6829 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 6830 * to focusable will not.</p> 6831 * 6832 * @return {@code true} if the view is focusable or if the view contains a focusable 6833 * view, {@code false} otherwise 6834 * 6835 * @see #hasFocusable() 6836 */ 6837 public boolean hasExplicitFocusable() { 6838 return hasFocusable(false, true); 6839 } 6840 6841 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 6842 if (!isFocusableInTouchMode()) { 6843 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6844 final ViewGroup g = (ViewGroup) p; 6845 if (g.shouldBlockFocusForTouchscreen()) { 6846 return false; 6847 } 6848 } 6849 } 6850 6851 // Invisible and gone views are never focusable. 6852 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 6853 return false; 6854 } 6855 6856 // Only use effective focusable value when allowed. 6857 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 6858 return true; 6859 } 6860 6861 return false; 6862 } 6863 6864 /** 6865 * Called by the view system when the focus state of this view changes. 6866 * When the focus change event is caused by directional navigation, direction 6867 * and previouslyFocusedRect provide insight into where the focus is coming from. 6868 * When overriding, be sure to call up through to the super class so that 6869 * the standard focus handling will occur. 6870 * 6871 * @param gainFocus True if the View has focus; false otherwise. 6872 * @param direction The direction focus has moved when requestFocus() 6873 * is called to give this view focus. Values are 6874 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6875 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6876 * It may not always apply, in which case use the default. 6877 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6878 * system, of the previously focused view. If applicable, this will be 6879 * passed in as finer grained information about where the focus is coming 6880 * from (in addition to direction). Will be <code>null</code> otherwise. 6881 */ 6882 @CallSuper 6883 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6884 @Nullable Rect previouslyFocusedRect) { 6885 if (gainFocus) { 6886 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6887 } else { 6888 notifyViewAccessibilityStateChangedIfNeeded( 6889 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6890 } 6891 6892 // Here we check whether we still need the default focus highlight, and switch it on/off. 6893 switchDefaultFocusHighlight(); 6894 6895 InputMethodManager imm = InputMethodManager.peekInstance(); 6896 if (!gainFocus) { 6897 if (isPressed()) { 6898 setPressed(false); 6899 } 6900 if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6901 imm.focusOut(this); 6902 } 6903 onFocusLost(); 6904 } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6905 imm.focusIn(this); 6906 } 6907 6908 invalidate(true); 6909 ListenerInfo li = mListenerInfo; 6910 if (li != null && li.mOnFocusChangeListener != null) { 6911 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6912 } 6913 6914 if (mAttachInfo != null) { 6915 mAttachInfo.mKeyDispatchState.reset(this); 6916 } 6917 6918 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 6919 } 6920 6921 private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 6922 if (isAutofillable() && isAttachedToWindow()) { 6923 AutofillManager afm = getAutofillManager(); 6924 if (afm != null) { 6925 if (enter && hasWindowFocus() && isFocused()) { 6926 // We have not been laid out yet, hence cannot evaluate 6927 // whether this view is visible to the user, we will do 6928 // the evaluation once layout is complete. 6929 if (!isLaidOut()) { 6930 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 6931 } else if (isVisibleToUser()) { 6932 afm.notifyViewEntered(this); 6933 } 6934 } else if (!hasWindowFocus() || !isFocused()) { 6935 afm.notifyViewExited(this); 6936 } 6937 } 6938 } 6939 } 6940 6941 /** 6942 * Sends an accessibility event of the given type. If accessibility is 6943 * not enabled this method has no effect. The default implementation calls 6944 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6945 * to populate information about the event source (this View), then calls 6946 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6947 * populate the text content of the event source including its descendants, 6948 * and last calls 6949 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6950 * on its parent to request sending of the event to interested parties. 6951 * <p> 6952 * If an {@link AccessibilityDelegate} has been specified via calling 6953 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6954 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6955 * responsible for handling this call. 6956 * </p> 6957 * 6958 * @param eventType The type of the event to send, as defined by several types from 6959 * {@link android.view.accessibility.AccessibilityEvent}, such as 6960 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6961 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6962 * 6963 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6964 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6965 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6966 * @see AccessibilityDelegate 6967 */ 6968 public void sendAccessibilityEvent(int eventType) { 6969 if (mAccessibilityDelegate != null) { 6970 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6971 } else { 6972 sendAccessibilityEventInternal(eventType); 6973 } 6974 } 6975 6976 /** 6977 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6978 * {@link AccessibilityEvent} to make an announcement which is related to some 6979 * sort of a context change for which none of the events representing UI transitions 6980 * is a good fit. For example, announcing a new page in a book. If accessibility 6981 * is not enabled this method does nothing. 6982 * 6983 * @param text The announcement text. 6984 */ 6985 public void announceForAccessibility(CharSequence text) { 6986 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6987 AccessibilityEvent event = AccessibilityEvent.obtain( 6988 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6989 onInitializeAccessibilityEvent(event); 6990 event.getText().add(text); 6991 event.setContentDescription(null); 6992 mParent.requestSendAccessibilityEvent(this, event); 6993 } 6994 } 6995 6996 /** 6997 * @see #sendAccessibilityEvent(int) 6998 * 6999 * Note: Called from the default {@link AccessibilityDelegate}. 7000 * 7001 * @hide 7002 */ 7003 public void sendAccessibilityEventInternal(int eventType) { 7004 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 7005 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 7006 } 7007 } 7008 7009 /** 7010 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 7011 * takes as an argument an empty {@link AccessibilityEvent} and does not 7012 * perform a check whether accessibility is enabled. 7013 * <p> 7014 * If an {@link AccessibilityDelegate} has been specified via calling 7015 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7016 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 7017 * is responsible for handling this call. 7018 * </p> 7019 * 7020 * @param event The event to send. 7021 * 7022 * @see #sendAccessibilityEvent(int) 7023 */ 7024 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 7025 if (mAccessibilityDelegate != null) { 7026 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 7027 } else { 7028 sendAccessibilityEventUncheckedInternal(event); 7029 } 7030 } 7031 7032 /** 7033 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 7034 * 7035 * Note: Called from the default {@link AccessibilityDelegate}. 7036 * 7037 * @hide 7038 */ 7039 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 7040 if (!isShown()) { 7041 return; 7042 } 7043 onInitializeAccessibilityEvent(event); 7044 // Only a subset of accessibility events populates text content. 7045 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 7046 dispatchPopulateAccessibilityEvent(event); 7047 } 7048 // In the beginning we called #isShown(), so we know that getParent() is not null. 7049 ViewParent parent = getParent(); 7050 if (parent != null) { 7051 getParent().requestSendAccessibilityEvent(this, event); 7052 } 7053 } 7054 7055 /** 7056 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 7057 * to its children for adding their text content to the event. Note that the 7058 * event text is populated in a separate dispatch path since we add to the 7059 * event not only the text of the source but also the text of all its descendants. 7060 * A typical implementation will call 7061 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 7062 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 7063 * on each child. Override this method if custom population of the event text 7064 * content is required. 7065 * <p> 7066 * If an {@link AccessibilityDelegate} has been specified via calling 7067 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7068 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 7069 * is responsible for handling this call. 7070 * </p> 7071 * <p> 7072 * <em>Note:</em> Accessibility events of certain types are not dispatched for 7073 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 7074 * </p> 7075 * 7076 * @param event The event. 7077 * 7078 * @return True if the event population was completed. 7079 */ 7080 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 7081 if (mAccessibilityDelegate != null) { 7082 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 7083 } else { 7084 return dispatchPopulateAccessibilityEventInternal(event); 7085 } 7086 } 7087 7088 /** 7089 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7090 * 7091 * Note: Called from the default {@link AccessibilityDelegate}. 7092 * 7093 * @hide 7094 */ 7095 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7096 onPopulateAccessibilityEvent(event); 7097 return false; 7098 } 7099 7100 /** 7101 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 7102 * giving a chance to this View to populate the accessibility event with its 7103 * text content. While this method is free to modify event 7104 * attributes other than text content, doing so should normally be performed in 7105 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 7106 * <p> 7107 * Example: Adding formatted date string to an accessibility event in addition 7108 * to the text added by the super implementation: 7109 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7110 * super.onPopulateAccessibilityEvent(event); 7111 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 7112 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 7113 * mCurrentDate.getTimeInMillis(), flags); 7114 * event.getText().add(selectedDateUtterance); 7115 * }</pre> 7116 * <p> 7117 * If an {@link AccessibilityDelegate} has been specified via calling 7118 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7119 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 7120 * is responsible for handling this call. 7121 * </p> 7122 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7123 * information to the event, in case the default implementation has basic information to add. 7124 * </p> 7125 * 7126 * @param event The accessibility event which to populate. 7127 * 7128 * @see #sendAccessibilityEvent(int) 7129 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7130 */ 7131 @CallSuper 7132 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7133 if (mAccessibilityDelegate != null) { 7134 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 7135 } else { 7136 onPopulateAccessibilityEventInternal(event); 7137 } 7138 } 7139 7140 /** 7141 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 7142 * 7143 * Note: Called from the default {@link AccessibilityDelegate}. 7144 * 7145 * @hide 7146 */ 7147 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7148 } 7149 7150 /** 7151 * Initializes an {@link AccessibilityEvent} with information about 7152 * this View which is the event source. In other words, the source of 7153 * an accessibility event is the view whose state change triggered firing 7154 * the event. 7155 * <p> 7156 * Example: Setting the password property of an event in addition 7157 * to properties set by the super implementation: 7158 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7159 * super.onInitializeAccessibilityEvent(event); 7160 * event.setPassword(true); 7161 * }</pre> 7162 * <p> 7163 * If an {@link AccessibilityDelegate} has been specified via calling 7164 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7165 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 7166 * is responsible for handling this call. 7167 * </p> 7168 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7169 * information to the event, in case the default implementation has basic information to add. 7170 * </p> 7171 * @param event The event to initialize. 7172 * 7173 * @see #sendAccessibilityEvent(int) 7174 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7175 */ 7176 @CallSuper 7177 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7178 if (mAccessibilityDelegate != null) { 7179 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 7180 } else { 7181 onInitializeAccessibilityEventInternal(event); 7182 } 7183 } 7184 7185 /** 7186 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 7187 * 7188 * Note: Called from the default {@link AccessibilityDelegate}. 7189 * 7190 * @hide 7191 */ 7192 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 7193 event.setSource(this); 7194 event.setClassName(getAccessibilityClassName()); 7195 event.setPackageName(getContext().getPackageName()); 7196 event.setEnabled(isEnabled()); 7197 event.setContentDescription(mContentDescription); 7198 7199 switch (event.getEventType()) { 7200 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 7201 ArrayList<View> focusablesTempList = (mAttachInfo != null) 7202 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 7203 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 7204 event.setItemCount(focusablesTempList.size()); 7205 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 7206 if (mAttachInfo != null) { 7207 focusablesTempList.clear(); 7208 } 7209 } break; 7210 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 7211 CharSequence text = getIterableTextForAccessibility(); 7212 if (text != null && text.length() > 0) { 7213 event.setFromIndex(getAccessibilitySelectionStart()); 7214 event.setToIndex(getAccessibilitySelectionEnd()); 7215 event.setItemCount(text.length()); 7216 } 7217 } break; 7218 } 7219 } 7220 7221 /** 7222 * Returns an {@link AccessibilityNodeInfo} representing this view from the 7223 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 7224 * This method is responsible for obtaining an accessibility node info from a 7225 * pool of reusable instances and calling 7226 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 7227 * initialize the former. 7228 * <p> 7229 * Note: The client is responsible for recycling the obtained instance by calling 7230 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 7231 * </p> 7232 * 7233 * @return A populated {@link AccessibilityNodeInfo}. 7234 * 7235 * @see AccessibilityNodeInfo 7236 */ 7237 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 7238 if (mAccessibilityDelegate != null) { 7239 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 7240 } else { 7241 return createAccessibilityNodeInfoInternal(); 7242 } 7243 } 7244 7245 /** 7246 * @see #createAccessibilityNodeInfo() 7247 * 7248 * @hide 7249 */ 7250 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 7251 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7252 if (provider != null) { 7253 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 7254 } else { 7255 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 7256 onInitializeAccessibilityNodeInfo(info); 7257 return info; 7258 } 7259 } 7260 7261 /** 7262 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 7263 * The base implementation sets: 7264 * <ul> 7265 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 7266 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 7267 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 7268 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 7269 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 7270 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 7271 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 7272 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 7273 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 7274 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 7275 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 7276 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 7277 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 7278 * </ul> 7279 * <p> 7280 * Subclasses should override this method, call the super implementation, 7281 * and set additional attributes. 7282 * </p> 7283 * <p> 7284 * If an {@link AccessibilityDelegate} has been specified via calling 7285 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7286 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 7287 * is responsible for handling this call. 7288 * </p> 7289 * 7290 * @param info The instance to initialize. 7291 */ 7292 @CallSuper 7293 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 7294 if (mAccessibilityDelegate != null) { 7295 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 7296 } else { 7297 onInitializeAccessibilityNodeInfoInternal(info); 7298 } 7299 } 7300 7301 /** 7302 * Gets the location of this view in screen coordinates. 7303 * 7304 * @param outRect The output location 7305 * @hide 7306 */ 7307 public void getBoundsOnScreen(Rect outRect) { 7308 getBoundsOnScreen(outRect, false); 7309 } 7310 7311 /** 7312 * Gets the location of this view in screen coordinates. 7313 * 7314 * @param outRect The output location 7315 * @param clipToParent Whether to clip child bounds to the parent ones. 7316 * @hide 7317 */ 7318 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 7319 if (mAttachInfo == null) { 7320 return; 7321 } 7322 7323 RectF position = mAttachInfo.mTmpTransformRect; 7324 position.set(0, 0, mRight - mLeft, mBottom - mTop); 7325 mapRectFromViewToScreenCoords(position, clipToParent); 7326 outRect.set(Math.round(position.left), Math.round(position.top), 7327 Math.round(position.right), Math.round(position.bottom)); 7328 } 7329 7330 /** 7331 * Map a rectangle from view-relative coordinates to screen-relative coordinates 7332 * 7333 * @param rect The rectangle to be mapped 7334 * @param clipToParent Whether to clip child bounds to the parent ones. 7335 * @hide 7336 */ 7337 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 7338 if (!hasIdentityMatrix()) { 7339 getMatrix().mapRect(rect); 7340 } 7341 7342 rect.offset(mLeft, mTop); 7343 7344 ViewParent parent = mParent; 7345 while (parent instanceof View) { 7346 View parentView = (View) parent; 7347 7348 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 7349 7350 if (clipToParent) { 7351 rect.left = Math.max(rect.left, 0); 7352 rect.top = Math.max(rect.top, 0); 7353 rect.right = Math.min(rect.right, parentView.getWidth()); 7354 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 7355 } 7356 7357 if (!parentView.hasIdentityMatrix()) { 7358 parentView.getMatrix().mapRect(rect); 7359 } 7360 7361 rect.offset(parentView.mLeft, parentView.mTop); 7362 7363 parent = parentView.mParent; 7364 } 7365 7366 if (parent instanceof ViewRootImpl) { 7367 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 7368 rect.offset(0, -viewRootImpl.mCurScrollY); 7369 } 7370 7371 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 7372 } 7373 7374 /** 7375 * Return the class name of this object to be used for accessibility purposes. 7376 * Subclasses should only override this if they are implementing something that 7377 * should be seen as a completely new class of view when used by accessibility, 7378 * unrelated to the class it is deriving from. This is used to fill in 7379 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 7380 */ 7381 public CharSequence getAccessibilityClassName() { 7382 return View.class.getName(); 7383 } 7384 7385 /** 7386 * Called when assist structure is being retrieved from a view as part of 7387 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 7388 * @param structure Fill in with structured view data. The default implementation 7389 * fills in all data that can be inferred from the view itself. 7390 */ 7391 public void onProvideStructure(ViewStructure structure) { 7392 onProvideStructureForAssistOrAutofill(structure, false, 0); 7393 } 7394 7395 /** 7396 * Populates a {@link ViewStructure} to fullfil an autofill request. 7397 * 7398 * <p>The structure should contain at least the following properties: 7399 * <ul> 7400 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 7401 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 7402 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 7403 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 7404 * </ul> 7405 * 7406 * <p>It's also recommended to set the following properties - the more properties the structure 7407 * has, the higher the changes of an {@link android.service.autofill.AutofillService} properly 7408 * using the structure: 7409 * 7410 * <ul> 7411 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 7412 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 7413 * view can only be filled with predefined values (typically used when the autofill type 7414 * is {@link #AUTOFILL_TYPE_LIST}). 7415 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 7416 * <li>Class name ({@link ViewStructure#setClassName(String)}). 7417 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 7418 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 7419 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 7420 * opacity ({@link ViewStructure#setOpaque(boolean)}). 7421 * <li>For views representing text fields, text properties such as the text itself 7422 * ({@link ViewStructure#setText(CharSequence)}), text hints 7423 * ({@link ViewStructure#setHint(CharSequence)}, input type 7424 * ({@link ViewStructure#setInputType(int)}), 7425 * <li>For views representing HTML nodes, its web domain 7426 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 7427 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 7428 * </ul> 7429 * 7430 * <p>The default implementation of this method already sets most of these properties based on 7431 * related {@link View} methods (for example, the autofill id is set using 7432 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 7433 * and views in the standard Android widgets library also override it to set their 7434 * relevant properties (for example, {@link android.widget.TextView} already sets the text 7435 * properties), so it's recommended to only override this method 7436 * (and call {@code super.onProvideAutofillStructure()}) when: 7437 * 7438 * <ul> 7439 * <li>The view contents does not include PII (Personally Identifiable Information), so it 7440 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 7441 * <li>The view can only be autofilled with predefined options, so it can call 7442 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 7443 * </ul> 7444 * 7445 * <p><b>NOTE:</b> the {@code left} and {@code top} values set in 7446 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 7447 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 7448 * 7449 * <p>Views support the Autofill Framework mainly by: 7450 * <ul> 7451 * <li>Providing the metadata defining what the view means and how it can be autofilled. 7452 * <li>Notifying the Android System when the view value changed by calling 7453 * {@link AutofillManager#notifyValueChanged(View)}. 7454 * <li>Implementing the methods that autofill the view. 7455 * </ul> 7456 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 7457 * for the latter. 7458 * 7459 * @param structure fill in with structured view data for autofill purposes. 7460 * @param flags optional flags. 7461 * 7462 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 7463 */ 7464 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 7465 onProvideStructureForAssistOrAutofill(structure, true, flags); 7466 } 7467 7468 private void onProvideStructureForAssistOrAutofill(ViewStructure structure, 7469 boolean forAutofill, @AutofillFlags int flags) { 7470 final int id = mID; 7471 if (id != NO_ID && !isViewIdGenerated(id)) { 7472 String pkg, type, entry; 7473 try { 7474 final Resources res = getResources(); 7475 entry = res.getResourceEntryName(id); 7476 type = res.getResourceTypeName(id); 7477 pkg = res.getResourcePackageName(id); 7478 } catch (Resources.NotFoundException e) { 7479 entry = type = pkg = null; 7480 } 7481 structure.setId(id, pkg, type, entry); 7482 } else { 7483 structure.setId(id, null, null, null); 7484 } 7485 7486 if (forAutofill) { 7487 final @AutofillType int autofillType = getAutofillType(); 7488 // Don't need to fill autofill info if view does not support it. 7489 // For example, only TextViews that are editable support autofill 7490 if (autofillType != AUTOFILL_TYPE_NONE) { 7491 structure.setAutofillType(autofillType); 7492 structure.setAutofillHints(getAutofillHints()); 7493 structure.setAutofillValue(getAutofillValue()); 7494 } 7495 } 7496 7497 int ignoredParentLeft = 0; 7498 int ignoredParentTop = 0; 7499 if (forAutofill && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 7500 View parentGroup = null; 7501 7502 ViewParent viewParent = getParent(); 7503 if (viewParent instanceof View) { 7504 parentGroup = (View) viewParent; 7505 } 7506 7507 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 7508 ignoredParentLeft += parentGroup.mLeft; 7509 ignoredParentTop += parentGroup.mTop; 7510 7511 viewParent = parentGroup.getParent(); 7512 if (viewParent instanceof View) { 7513 parentGroup = (View) viewParent; 7514 } else { 7515 break; 7516 } 7517 } 7518 } 7519 7520 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 7521 mRight - mLeft, mBottom - mTop); 7522 if (!forAutofill) { 7523 if (!hasIdentityMatrix()) { 7524 structure.setTransformation(getMatrix()); 7525 } 7526 structure.setElevation(getZ()); 7527 } 7528 structure.setVisibility(getVisibility()); 7529 structure.setEnabled(isEnabled()); 7530 if (isClickable()) { 7531 structure.setClickable(true); 7532 } 7533 if (isFocusable()) { 7534 structure.setFocusable(true); 7535 } 7536 if (isFocused()) { 7537 structure.setFocused(true); 7538 } 7539 if (isAccessibilityFocused()) { 7540 structure.setAccessibilityFocused(true); 7541 } 7542 if (isSelected()) { 7543 structure.setSelected(true); 7544 } 7545 if (isActivated()) { 7546 structure.setActivated(true); 7547 } 7548 if (isLongClickable()) { 7549 structure.setLongClickable(true); 7550 } 7551 if (this instanceof Checkable) { 7552 structure.setCheckable(true); 7553 if (((Checkable)this).isChecked()) { 7554 structure.setChecked(true); 7555 } 7556 } 7557 if (isOpaque()) { 7558 structure.setOpaque(true); 7559 } 7560 if (isContextClickable()) { 7561 structure.setContextClickable(true); 7562 } 7563 structure.setClassName(getAccessibilityClassName().toString()); 7564 structure.setContentDescription(getContentDescription()); 7565 } 7566 7567 /** 7568 * Called when assist structure is being retrieved from a view as part of 7569 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 7570 * generate additional virtual structure under this view. The defaullt implementation 7571 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 7572 * view's virtual accessibility nodes, if any. You can override this for a more 7573 * optimal implementation providing this data. 7574 */ 7575 public void onProvideVirtualStructure(ViewStructure structure) { 7576 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7577 if (provider != null) { 7578 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7579 structure.setChildCount(1); 7580 ViewStructure root = structure.newChild(0); 7581 populateVirtualStructure(root, provider, info); 7582 info.recycle(); 7583 } 7584 } 7585 7586 /** 7587 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 7588 * request. 7589 * 7590 * <p>This method should be used when the view manages a virtual structure under this view. For 7591 * example, a view that draws input fields using {@link #draw(Canvas)}. 7592 * 7593 * <p>When implementing this method, subclasses must follow the rules below: 7594 * 7595 * <ul> 7596 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 7597 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 7598 * identifying the children in the virtual structure. 7599 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 7600 * exclude intermediate levels that are irrelevant for autofill; that would improve the 7601 * autofill performance. 7602 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 7603 * children. 7604 * <li>Set the autofill properties of the child structure as defined by 7605 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 7606 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 7607 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 7608 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 7609 * when the focused virtual child changed. 7610 * <li>Call 7611 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 7612 * when the value of a virtual child changed. 7613 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 7614 * changed and the current context should be committed (for example, when the user tapped 7615 * a {@code SUBMIT} button in an HTML page). 7616 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 7617 * changed and the current context should be canceled (for example, when the user tapped 7618 * a {@code CANCEL} button in an HTML page). 7619 * <li>Provide ways for users to manually request autofill by calling 7620 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 7621 * <li>The {@code left} and {@code top} values set in 7622 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 7623 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 7624 * structure. 7625 * </ul> 7626 * 7627 * <p>Views with virtual children support the Autofill Framework mainly by: 7628 * <ul> 7629 * <li>Providing the metadata defining what the virtual children mean and how they can be 7630 * autofilled. 7631 * <li>Implementing the methods that autofill the virtual children. 7632 * </ul> 7633 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 7634 * for the latter. 7635 * 7636 * @param structure fill in with virtual children data for autofill purposes. 7637 * @param flags optional flags. 7638 * 7639 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 7640 */ 7641 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 7642 } 7643 7644 /** 7645 * Automatically fills the content of this view with the {@code value}. 7646 * 7647 * <p>Views support the Autofill Framework mainly by: 7648 * <ul> 7649 * <li>Providing the metadata defining what the view means and how it can be autofilled. 7650 * <li>Implementing the methods that autofill the view. 7651 * </ul> 7652 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 7653 * this method is responsible for latter. 7654 * 7655 * <p>This method does nothing by default, but when overridden it typically: 7656 * <ol> 7657 * <li>Checks if the provided value matches the expected type (which is defined by 7658 * {@link #getAutofillType()}). 7659 * <li>Checks if the view is editable - if it isn't, it should return right away. 7660 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 7661 * <li>Pass the actual value to the equivalent setter in the view. 7662 * </ol> 7663 * 7664 * <p>For example, a text-field view could implement the method this way: 7665 * 7666 * <pre class="prettyprint"> 7667 * @Override 7668 * public void autofill(AutofillValue value) { 7669 * if (!value.isText() || !this.isEditable()) { 7670 * return; 7671 * } 7672 * CharSequence text = value.getTextValue(); 7673 * if (text != null) { 7674 * this.setText(text); 7675 * } 7676 * } 7677 * </pre> 7678 * 7679 * <p>If the value is updated asynchronously the next call to 7680 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 7681 * changed to the autofilled value. If not, the view will not be considered autofilled. 7682 * 7683 * @param value value to be autofilled. 7684 */ 7685 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 7686 } 7687 7688 /** 7689 * Automatically fills the content of the virtual children within this view. 7690 * 7691 * <p>Views with virtual children support the Autofill Framework mainly by: 7692 * <ul> 7693 * <li>Providing the metadata defining what the virtual children mean and how they can be 7694 * autofilled. 7695 * <li>Implementing the methods that autofill the virtual children. 7696 * </ul> 7697 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 7698 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 7699 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 7700 * 7701 * <p><b>NOTE:</b> to indicate that a virtual view was autofilled, 7702 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 7703 * changes. 7704 * 7705 * @param values map of values to be autofilled, keyed by virtual child id. 7706 * 7707 * @attr ref android.R.styleable#Theme_autofilledHighlight 7708 */ 7709 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 7710 } 7711 7712 /** 7713 * Gets the unique identifier of this view in the screen, for autofill purposes. 7714 * 7715 * @return The View's autofill id. 7716 */ 7717 public final AutofillId getAutofillId() { 7718 if (mAutofillId == null) { 7719 // The autofill id needs to be unique, but its value doesn't matter, 7720 // so it's better to reuse the accessibility id to save space. 7721 mAutofillId = new AutofillId(getAccessibilityViewId()); 7722 } 7723 return mAutofillId; 7724 } 7725 7726 /** 7727 * Describes the autofill type of this view, so an 7728 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 7729 * when autofilling the view. 7730 * 7731 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 7732 * support the Autofill Framework. 7733 * 7734 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 7735 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 7736 * 7737 * @see #onProvideAutofillStructure(ViewStructure, int) 7738 * @see #autofill(AutofillValue) 7739 */ 7740 public @AutofillType int getAutofillType() { 7741 return AUTOFILL_TYPE_NONE; 7742 } 7743 7744 /** 7745 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 7746 * to autofill the view with the user's data. 7747 * 7748 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 7749 * 7750 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 7751 * {@code null} if no hints were set. 7752 * 7753 * @attr ref android.R.styleable#View_autofillHints 7754 */ 7755 @ViewDebug.ExportedProperty() 7756 @Nullable public String[] getAutofillHints() { 7757 return mAutofillHints; 7758 } 7759 7760 /** 7761 * @hide 7762 */ 7763 public boolean isAutofilled() { 7764 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 7765 } 7766 7767 /** 7768 * Gets the {@link View}'s current autofill value. 7769 * 7770 * <p>By default returns {@code null}, but views should override it to properly support the 7771 * Autofill Framework. 7772 * 7773 * @see #onProvideAutofillStructure(ViewStructure, int) 7774 * @see #autofill(AutofillValue) 7775 */ 7776 @Nullable 7777 public AutofillValue getAutofillValue() { 7778 return null; 7779 } 7780 7781 /** 7782 * Gets the mode for determining whether this view is important for autofill. 7783 * 7784 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 7785 * info about this mode. 7786 * 7787 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 7788 * {@link #setImportantForAutofill(int)}. 7789 * 7790 * @attr ref android.R.styleable#View_importantForAutofill 7791 */ 7792 @ViewDebug.ExportedProperty(mapping = { 7793 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 7794 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 7795 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 7796 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 7797 to = "yesExcludeDescendants"), 7798 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 7799 to = "noExcludeDescendants")}) 7800 public @AutofillImportance int getImportantForAutofill() { 7801 return (mPrivateFlags3 7802 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 7803 } 7804 7805 /** 7806 * Sets the mode for determining whether this view is considered important for autofill. 7807 * 7808 * <p>The platform determines the importance for autofill automatically but you 7809 * can use this method to customize the behavior. For example: 7810 * 7811 * <ol> 7812 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 7813 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 7814 * <li>When both the view and its children are irrelevant for autofill (for example, the root 7815 * view of an activity containing a spreadhseet editor), it should be 7816 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 7817 * <li>When the view content is relevant for autofill but its children aren't (for example, 7818 * a credit card expiration date represented by a custom view that overrides the proper 7819 * autofill methods and has 2 children representing the month and year), it should 7820 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 7821 * </ol> 7822 * 7823 * <p><b>NOTE:</strong> setting the mode as does {@link #IMPORTANT_FOR_AUTOFILL_NO} or 7824 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 7825 * children) will be always be considered not important; for example, when the user explicitly 7826 * makes an autofill request, all views are considered important. See 7827 * {@link #isImportantForAutofill()} for more details about how the View's importance for 7828 * autofill is used. 7829 * 7830 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 7831 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 7832 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 7833 * 7834 * @attr ref android.R.styleable#View_importantForAutofill 7835 */ 7836 public void setImportantForAutofill(@AutofillImportance int mode) { 7837 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7838 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 7839 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7840 } 7841 7842 /** 7843 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 7844 * associated with this view is considered important for autofill purposes. 7845 * 7846 * <p>Generally speaking, a view is important for autofill if: 7847 * <ol> 7848 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 7849 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 7850 * determine how other views can be autofilled. 7851 * <ol> 7852 * 7853 * <p>For example, view containers should typically return {@code false} for performance reasons 7854 * (since the important info is provided by their children), but if its properties have relevant 7855 * information (for example, a resource id called {@code credentials}, it should return 7856 * {@code true}. On the other hand, views representing labels or editable fields should 7857 * typically return {@code true}, but in some cases they could return {@code false} 7858 * (for example, if they're part of a "Captcha" mechanism). 7859 * 7860 * <p>The value returned by this method depends on the value returned by 7861 * {@link #getImportantForAutofill()}: 7862 * 7863 * <ol> 7864 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 7865 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 7866 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 7867 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 7868 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 7869 * that can return {@code true} in some cases (like a container with a resource id), 7870 * but {@code false} in most. 7871 * <li>otherwise, it returns {@code false}. 7872 * </ol> 7873 * 7874 * <p>When a view is considered important for autofill: 7875 * <ul> 7876 * <li>The view might automatically trigger an autofill request when focused on. 7877 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 7878 * request. 7879 * </ul> 7880 * 7881 * <p>On the other hand, when a view is considered not important for autofill: 7882 * <ul> 7883 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 7884 * request through {@link AutofillManager#requestAutofill(View)}. 7885 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 7886 * autofill request, unless the request has the 7887 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 7888 * </ul> 7889 * 7890 * @return whether the view is considered important for autofill. 7891 * 7892 * @see #setImportantForAutofill(int) 7893 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 7894 * @see #IMPORTANT_FOR_AUTOFILL_YES 7895 * @see #IMPORTANT_FOR_AUTOFILL_NO 7896 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 7897 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7898 * @see AutofillManager#requestAutofill(View) 7899 */ 7900 public final boolean isImportantForAutofill() { 7901 // Check parent mode to ensure we're not hidden. 7902 ViewParent parent = mParent; 7903 while (parent instanceof View) { 7904 final int parentImportance = ((View) parent).getImportantForAutofill(); 7905 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7906 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 7907 return false; 7908 } 7909 parent = parent.getParent(); 7910 } 7911 7912 final int importance = getImportantForAutofill(); 7913 7914 // First, check the explicit states. 7915 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 7916 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 7917 return true; 7918 } 7919 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7920 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 7921 return false; 7922 } 7923 7924 // Then use some heuristics to handle AUTO. 7925 7926 // Always include views that have an explicit resource id. 7927 final int id = mID; 7928 if (id != NO_ID && !isViewIdGenerated(id)) { 7929 final Resources res = getResources(); 7930 String entry = null; 7931 String pkg = null; 7932 try { 7933 entry = res.getResourceEntryName(id); 7934 pkg = res.getResourcePackageName(id); 7935 } catch (Resources.NotFoundException e) { 7936 // ignore 7937 } 7938 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 7939 return true; 7940 } 7941 } 7942 7943 // Otherwise, assume it's not important... 7944 return false; 7945 } 7946 7947 @Nullable 7948 private AutofillManager getAutofillManager() { 7949 return mContext.getSystemService(AutofillManager.class); 7950 } 7951 7952 private boolean isAutofillable() { 7953 return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill() 7954 && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID; 7955 } 7956 7957 private void populateVirtualStructure(ViewStructure structure, 7958 AccessibilityNodeProvider provider, AccessibilityNodeInfo info) { 7959 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 7960 null, null, null); 7961 Rect rect = structure.getTempRect(); 7962 info.getBoundsInParent(rect); 7963 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 7964 structure.setVisibility(VISIBLE); 7965 structure.setEnabled(info.isEnabled()); 7966 if (info.isClickable()) { 7967 structure.setClickable(true); 7968 } 7969 if (info.isFocusable()) { 7970 structure.setFocusable(true); 7971 } 7972 if (info.isFocused()) { 7973 structure.setFocused(true); 7974 } 7975 if (info.isAccessibilityFocused()) { 7976 structure.setAccessibilityFocused(true); 7977 } 7978 if (info.isSelected()) { 7979 structure.setSelected(true); 7980 } 7981 if (info.isLongClickable()) { 7982 structure.setLongClickable(true); 7983 } 7984 if (info.isCheckable()) { 7985 structure.setCheckable(true); 7986 if (info.isChecked()) { 7987 structure.setChecked(true); 7988 } 7989 } 7990 if (info.isContextClickable()) { 7991 structure.setContextClickable(true); 7992 } 7993 CharSequence cname = info.getClassName(); 7994 structure.setClassName(cname != null ? cname.toString() : null); 7995 structure.setContentDescription(info.getContentDescription()); 7996 if ((info.getText() != null || info.getError() != null)) { 7997 structure.setText(info.getText(), info.getTextSelectionStart(), 7998 info.getTextSelectionEnd()); 7999 } 8000 final int NCHILDREN = info.getChildCount(); 8001 if (NCHILDREN > 0) { 8002 structure.setChildCount(NCHILDREN); 8003 for (int i=0; i<NCHILDREN; i++) { 8004 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 8005 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 8006 ViewStructure child = structure.newChild(i); 8007 populateVirtualStructure(child, provider, cinfo); 8008 cinfo.recycle(); 8009 } 8010 } 8011 } 8012 8013 /** 8014 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 8015 * implementation calls {@link #onProvideStructure} and 8016 * {@link #onProvideVirtualStructure}. 8017 */ 8018 public void dispatchProvideStructure(ViewStructure structure) { 8019 dispatchProvideStructureForAssistOrAutofill(structure, false, 0); 8020 } 8021 8022 /** 8023 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 8024 * when an Assist structure is being created as part of an autofill request. 8025 * 8026 * <p>The default implementation does the following: 8027 * <ul> 8028 * <li>Sets the {@link AutofillId} in the structure. 8029 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 8030 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 8031 * </ul> 8032 * 8033 * <p>Typically, this method should only be overridden by subclasses that provide a view 8034 * hierarchy (such as {@link ViewGroup}) - other classes should override 8035 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 8036 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 8037 * 8038 * <p>When overridden, it must: 8039 * 8040 * <ul> 8041 * <li>Either call 8042 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 8043 * set the {@link AutofillId} in the structure (for example, by calling 8044 * {@code structure.setAutofillId(getAutofillId())}). 8045 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 8046 * set, all views in the structure should be considered important for autofill, 8047 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 8048 * respect this flag to provide a better user experience - this flag is typically used 8049 * when an user explicitly requested autofill. If the flag is not set, 8050 * then only views marked as important for autofill should be included in the 8051 * structure - skipping non-important views optimizes the overall autofill performance. 8052 * </ul> 8053 * 8054 * @param structure fill in with structured view data for autofill purposes. 8055 * @param flags optional flags. 8056 * 8057 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8058 */ 8059 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 8060 @AutofillFlags int flags) { 8061 dispatchProvideStructureForAssistOrAutofill(structure, true, flags); 8062 } 8063 8064 private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure, 8065 boolean forAutofill, @AutofillFlags int flags) { 8066 if (forAutofill) { 8067 structure.setAutofillId(getAutofillId()); 8068 onProvideAutofillStructure(structure, flags); 8069 onProvideAutofillVirtualStructure(structure, flags); 8070 } else if (!isAssistBlocked()) { 8071 onProvideStructure(structure); 8072 onProvideVirtualStructure(structure); 8073 } else { 8074 structure.setClassName(getAccessibilityClassName().toString()); 8075 structure.setAssistBlocked(true); 8076 } 8077 } 8078 8079 /** 8080 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 8081 * 8082 * Note: Called from the default {@link AccessibilityDelegate}. 8083 * 8084 * @hide 8085 */ 8086 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 8087 if (mAttachInfo == null) { 8088 return; 8089 } 8090 8091 Rect bounds = mAttachInfo.mTmpInvalRect; 8092 8093 getDrawingRect(bounds); 8094 info.setBoundsInParent(bounds); 8095 8096 getBoundsOnScreen(bounds, true); 8097 info.setBoundsInScreen(bounds); 8098 8099 ViewParent parent = getParentForAccessibility(); 8100 if (parent instanceof View) { 8101 info.setParent((View) parent); 8102 } 8103 8104 if (mID != View.NO_ID) { 8105 View rootView = getRootView(); 8106 if (rootView == null) { 8107 rootView = this; 8108 } 8109 8110 View label = rootView.findLabelForView(this, mID); 8111 if (label != null) { 8112 info.setLabeledBy(label); 8113 } 8114 8115 if ((mAttachInfo.mAccessibilityFetchFlags 8116 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 8117 && Resources.resourceHasPackage(mID)) { 8118 try { 8119 String viewId = getResources().getResourceName(mID); 8120 info.setViewIdResourceName(viewId); 8121 } catch (Resources.NotFoundException nfe) { 8122 /* ignore */ 8123 } 8124 } 8125 } 8126 8127 if (mLabelForId != View.NO_ID) { 8128 View rootView = getRootView(); 8129 if (rootView == null) { 8130 rootView = this; 8131 } 8132 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 8133 if (labeled != null) { 8134 info.setLabelFor(labeled); 8135 } 8136 } 8137 8138 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 8139 View rootView = getRootView(); 8140 if (rootView == null) { 8141 rootView = this; 8142 } 8143 View next = rootView.findViewInsideOutShouldExist(this, 8144 mAccessibilityTraversalBeforeId); 8145 if (next != null && next.includeForAccessibility()) { 8146 info.setTraversalBefore(next); 8147 } 8148 } 8149 8150 if (mAccessibilityTraversalAfterId != View.NO_ID) { 8151 View rootView = getRootView(); 8152 if (rootView == null) { 8153 rootView = this; 8154 } 8155 View next = rootView.findViewInsideOutShouldExist(this, 8156 mAccessibilityTraversalAfterId); 8157 if (next != null && next.includeForAccessibility()) { 8158 info.setTraversalAfter(next); 8159 } 8160 } 8161 8162 info.setVisibleToUser(isVisibleToUser()); 8163 8164 info.setImportantForAccessibility(isImportantForAccessibility()); 8165 info.setPackageName(mContext.getPackageName()); 8166 info.setClassName(getAccessibilityClassName()); 8167 info.setContentDescription(getContentDescription()); 8168 8169 info.setEnabled(isEnabled()); 8170 info.setClickable(isClickable()); 8171 info.setFocusable(isFocusable()); 8172 info.setFocused(isFocused()); 8173 info.setAccessibilityFocused(isAccessibilityFocused()); 8174 info.setSelected(isSelected()); 8175 info.setLongClickable(isLongClickable()); 8176 info.setContextClickable(isContextClickable()); 8177 info.setLiveRegion(getAccessibilityLiveRegion()); 8178 8179 // TODO: These make sense only if we are in an AdapterView but all 8180 // views can be selected. Maybe from accessibility perspective 8181 // we should report as selectable view in an AdapterView. 8182 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 8183 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 8184 8185 if (isFocusable()) { 8186 if (isFocused()) { 8187 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 8188 } else { 8189 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 8190 } 8191 } 8192 8193 if (!isAccessibilityFocused()) { 8194 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 8195 } else { 8196 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 8197 } 8198 8199 if (isClickable() && isEnabled()) { 8200 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 8201 } 8202 8203 if (isLongClickable() && isEnabled()) { 8204 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 8205 } 8206 8207 if (isContextClickable() && isEnabled()) { 8208 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 8209 } 8210 8211 CharSequence text = getIterableTextForAccessibility(); 8212 if (text != null && text.length() > 0) { 8213 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 8214 8215 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 8216 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 8217 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 8218 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 8219 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 8220 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 8221 } 8222 8223 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 8224 populateAccessibilityNodeInfoDrawingOrderInParent(info); 8225 } 8226 8227 /** 8228 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 8229 * additional data. 8230 * <p> 8231 * This method only needs overloading if the node is marked as having extra data available. 8232 * </p> 8233 * 8234 * @param info The info to which to add the extra data. Never {@code null}. 8235 * @param extraDataKey A key specifying the type of extra data to add to the info. The 8236 * extra data should be added to the {@link Bundle} returned by 8237 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 8238 * {@code null}. 8239 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 8240 * {@code null} if the service provided no arguments. 8241 * 8242 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 8243 */ 8244 public void addExtraDataToAccessibilityNodeInfo( 8245 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 8246 @Nullable Bundle arguments) { 8247 } 8248 8249 /** 8250 * Determine the order in which this view will be drawn relative to its siblings for a11y 8251 * 8252 * @param info The info whose drawing order should be populated 8253 */ 8254 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 8255 /* 8256 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 8257 * drawing order may not be well-defined, and some Views with custom drawing order may 8258 * not be initialized sufficiently to respond properly getChildDrawingOrder. 8259 */ 8260 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 8261 info.setDrawingOrder(0); 8262 return; 8263 } 8264 int drawingOrderInParent = 1; 8265 // Iterate up the hierarchy if parents are not important for a11y 8266 View viewAtDrawingLevel = this; 8267 final ViewParent parent = getParentForAccessibility(); 8268 while (viewAtDrawingLevel != parent) { 8269 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 8270 if (!(currentParent instanceof ViewGroup)) { 8271 // Should only happen for the Decor 8272 drawingOrderInParent = 0; 8273 break; 8274 } else { 8275 final ViewGroup parentGroup = (ViewGroup) currentParent; 8276 final int childCount = parentGroup.getChildCount(); 8277 if (childCount > 1) { 8278 List<View> preorderedList = parentGroup.buildOrderedChildList(); 8279 if (preorderedList != null) { 8280 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 8281 for (int i = 0; i < childDrawIndex; i++) { 8282 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 8283 } 8284 } else { 8285 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 8286 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 8287 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 8288 .getChildDrawingOrder(childCount, childIndex) : childIndex; 8289 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 8290 if (childDrawIndex != 0) { 8291 for (int i = 0; i < numChildrenToIterate; i++) { 8292 final int otherDrawIndex = (customOrder ? 8293 parentGroup.getChildDrawingOrder(childCount, i) : i); 8294 if (otherDrawIndex < childDrawIndex) { 8295 drawingOrderInParent += 8296 numViewsForAccessibility(parentGroup.getChildAt(i)); 8297 } 8298 } 8299 } 8300 } 8301 } 8302 } 8303 viewAtDrawingLevel = (View) currentParent; 8304 } 8305 info.setDrawingOrder(drawingOrderInParent); 8306 } 8307 8308 private static int numViewsForAccessibility(View view) { 8309 if (view != null) { 8310 if (view.includeForAccessibility()) { 8311 return 1; 8312 } else if (view instanceof ViewGroup) { 8313 return ((ViewGroup) view).getNumChildrenForAccessibility(); 8314 } 8315 } 8316 return 0; 8317 } 8318 8319 private View findLabelForView(View view, int labeledId) { 8320 if (mMatchLabelForPredicate == null) { 8321 mMatchLabelForPredicate = new MatchLabelForPredicate(); 8322 } 8323 mMatchLabelForPredicate.mLabeledId = labeledId; 8324 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 8325 } 8326 8327 /** 8328 * Computes whether this view is visible to the user. Such a view is 8329 * attached, visible, all its predecessors are visible, it is not clipped 8330 * entirely by its predecessors, and has an alpha greater than zero. 8331 * 8332 * @return Whether the view is visible on the screen. 8333 * 8334 * @hide 8335 */ 8336 protected boolean isVisibleToUser() { 8337 return isVisibleToUser(null); 8338 } 8339 8340 /** 8341 * Computes whether the given portion of this view is visible to the user. 8342 * Such a view is attached, visible, all its predecessors are visible, 8343 * has an alpha greater than zero, and the specified portion is not 8344 * clipped entirely by its predecessors. 8345 * 8346 * @param boundInView the portion of the view to test; coordinates should be relative; may be 8347 * <code>null</code>, and the entire view will be tested in this case. 8348 * When <code>true</code> is returned by the function, the actual visible 8349 * region will be stored in this parameter; that is, if boundInView is fully 8350 * contained within the view, no modification will be made, otherwise regions 8351 * outside of the visible area of the view will be clipped. 8352 * 8353 * @return Whether the specified portion of the view is visible on the screen. 8354 * 8355 * @hide 8356 */ 8357 protected boolean isVisibleToUser(Rect boundInView) { 8358 if (mAttachInfo != null) { 8359 // Attached to invisible window means this view is not visible. 8360 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 8361 return false; 8362 } 8363 // An invisible predecessor or one with alpha zero means 8364 // that this view is not visible to the user. 8365 Object current = this; 8366 while (current instanceof View) { 8367 View view = (View) current; 8368 // We have attach info so this view is attached and there is no 8369 // need to check whether we reach to ViewRootImpl on the way up. 8370 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 8371 view.getVisibility() != VISIBLE) { 8372 return false; 8373 } 8374 current = view.mParent; 8375 } 8376 // Check if the view is entirely covered by its predecessors. 8377 Rect visibleRect = mAttachInfo.mTmpInvalRect; 8378 Point offset = mAttachInfo.mPoint; 8379 if (!getGlobalVisibleRect(visibleRect, offset)) { 8380 return false; 8381 } 8382 // Check if the visible portion intersects the rectangle of interest. 8383 if (boundInView != null) { 8384 visibleRect.offset(-offset.x, -offset.y); 8385 return boundInView.intersect(visibleRect); 8386 } 8387 return true; 8388 } 8389 return false; 8390 } 8391 8392 /** 8393 * Returns the delegate for implementing accessibility support via 8394 * composition. For more details see {@link AccessibilityDelegate}. 8395 * 8396 * @return The delegate, or null if none set. 8397 * 8398 * @hide 8399 */ 8400 public AccessibilityDelegate getAccessibilityDelegate() { 8401 return mAccessibilityDelegate; 8402 } 8403 8404 /** 8405 * Sets a delegate for implementing accessibility support via composition 8406 * (as opposed to inheritance). For more details, see 8407 * {@link AccessibilityDelegate}. 8408 * <p> 8409 * <strong>Note:</strong> On platform versions prior to 8410 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 8411 * views in the {@code android.widget.*} package are called <i>before</i> 8412 * host methods. This prevents certain properties such as class name from 8413 * being modified by overriding 8414 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 8415 * as any changes will be overwritten by the host class. 8416 * <p> 8417 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 8418 * methods are called <i>after</i> host methods, which all properties to be 8419 * modified without being overwritten by the host class. 8420 * 8421 * @param delegate the object to which accessibility method calls should be 8422 * delegated 8423 * @see AccessibilityDelegate 8424 */ 8425 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 8426 mAccessibilityDelegate = delegate; 8427 } 8428 8429 /** 8430 * Gets the provider for managing a virtual view hierarchy rooted at this View 8431 * and reported to {@link android.accessibilityservice.AccessibilityService}s 8432 * that explore the window content. 8433 * <p> 8434 * If this method returns an instance, this instance is responsible for managing 8435 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 8436 * View including the one representing the View itself. Similarly the returned 8437 * instance is responsible for performing accessibility actions on any virtual 8438 * view or the root view itself. 8439 * </p> 8440 * <p> 8441 * If an {@link AccessibilityDelegate} has been specified via calling 8442 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8443 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 8444 * is responsible for handling this call. 8445 * </p> 8446 * 8447 * @return The provider. 8448 * 8449 * @see AccessibilityNodeProvider 8450 */ 8451 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 8452 if (mAccessibilityDelegate != null) { 8453 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 8454 } else { 8455 return null; 8456 } 8457 } 8458 8459 /** 8460 * Gets the unique identifier of this view on the screen for accessibility purposes. 8461 * 8462 * @return The view accessibility id. 8463 * 8464 * @hide 8465 */ 8466 public int getAccessibilityViewId() { 8467 if (mAccessibilityViewId == NO_ID) { 8468 mAccessibilityViewId = mContext.getNextAccessibilityId(); 8469 } 8470 return mAccessibilityViewId; 8471 } 8472 8473 /** 8474 * Gets the unique identifier of the window in which this View reseides. 8475 * 8476 * @return The window accessibility id. 8477 * 8478 * @hide 8479 */ 8480 public int getAccessibilityWindowId() { 8481 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 8482 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 8483 } 8484 8485 /** 8486 * Returns the {@link View}'s content description. 8487 * <p> 8488 * <strong>Note:</strong> Do not override this method, as it will have no 8489 * effect on the content description presented to accessibility services. 8490 * You must call {@link #setContentDescription(CharSequence)} to modify the 8491 * content description. 8492 * 8493 * @return the content description 8494 * @see #setContentDescription(CharSequence) 8495 * @attr ref android.R.styleable#View_contentDescription 8496 */ 8497 @ViewDebug.ExportedProperty(category = "accessibility") 8498 public CharSequence getContentDescription() { 8499 return mContentDescription; 8500 } 8501 8502 /** 8503 * Sets the {@link View}'s content description. 8504 * <p> 8505 * A content description briefly describes the view and is primarily used 8506 * for accessibility support to determine how a view should be presented to 8507 * the user. In the case of a view with no textual representation, such as 8508 * {@link android.widget.ImageButton}, a useful content description 8509 * explains what the view does. For example, an image button with a phone 8510 * icon that is used to place a call may use "Call" as its content 8511 * description. An image of a floppy disk that is used to save a file may 8512 * use "Save". 8513 * 8514 * @param contentDescription The content description. 8515 * @see #getContentDescription() 8516 * @attr ref android.R.styleable#View_contentDescription 8517 */ 8518 @RemotableViewMethod 8519 public void setContentDescription(CharSequence contentDescription) { 8520 if (mContentDescription == null) { 8521 if (contentDescription == null) { 8522 return; 8523 } 8524 } else if (mContentDescription.equals(contentDescription)) { 8525 return; 8526 } 8527 mContentDescription = contentDescription; 8528 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 8529 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 8530 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 8531 notifySubtreeAccessibilityStateChangedIfNeeded(); 8532 } else { 8533 notifyViewAccessibilityStateChangedIfNeeded( 8534 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 8535 } 8536 } 8537 8538 /** 8539 * Sets the id of a view before which this one is visited in accessibility traversal. 8540 * A screen-reader must visit the content of this view before the content of the one 8541 * it precedes. For example, if view B is set to be before view A, then a screen-reader 8542 * will traverse the entire content of B before traversing the entire content of A, 8543 * regardles of what traversal strategy it is using. 8544 * <p> 8545 * Views that do not have specified before/after relationships are traversed in order 8546 * determined by the screen-reader. 8547 * </p> 8548 * <p> 8549 * Setting that this view is before a view that is not important for accessibility 8550 * or if this view is not important for accessibility will have no effect as the 8551 * screen-reader is not aware of unimportant views. 8552 * </p> 8553 * 8554 * @param beforeId The id of a view this one precedes in accessibility traversal. 8555 * 8556 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 8557 * 8558 * @see #setImportantForAccessibility(int) 8559 */ 8560 @RemotableViewMethod 8561 public void setAccessibilityTraversalBefore(int beforeId) { 8562 if (mAccessibilityTraversalBeforeId == beforeId) { 8563 return; 8564 } 8565 mAccessibilityTraversalBeforeId = beforeId; 8566 notifyViewAccessibilityStateChangedIfNeeded( 8567 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8568 } 8569 8570 /** 8571 * Gets the id of a view before which this one is visited in accessibility traversal. 8572 * 8573 * @return The id of a view this one precedes in accessibility traversal if 8574 * specified, otherwise {@link #NO_ID}. 8575 * 8576 * @see #setAccessibilityTraversalBefore(int) 8577 */ 8578 public int getAccessibilityTraversalBefore() { 8579 return mAccessibilityTraversalBeforeId; 8580 } 8581 8582 /** 8583 * Sets the id of a view after which this one is visited in accessibility traversal. 8584 * A screen-reader must visit the content of the other view before the content of this 8585 * one. For example, if view B is set to be after view A, then a screen-reader 8586 * will traverse the entire content of A before traversing the entire content of B, 8587 * regardles of what traversal strategy it is using. 8588 * <p> 8589 * Views that do not have specified before/after relationships are traversed in order 8590 * determined by the screen-reader. 8591 * </p> 8592 * <p> 8593 * Setting that this view is after a view that is not important for accessibility 8594 * or if this view is not important for accessibility will have no effect as the 8595 * screen-reader is not aware of unimportant views. 8596 * </p> 8597 * 8598 * @param afterId The id of a view this one succedees in accessibility traversal. 8599 * 8600 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 8601 * 8602 * @see #setImportantForAccessibility(int) 8603 */ 8604 @RemotableViewMethod 8605 public void setAccessibilityTraversalAfter(int afterId) { 8606 if (mAccessibilityTraversalAfterId == afterId) { 8607 return; 8608 } 8609 mAccessibilityTraversalAfterId = afterId; 8610 notifyViewAccessibilityStateChangedIfNeeded( 8611 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8612 } 8613 8614 /** 8615 * Gets the id of a view after which this one is visited in accessibility traversal. 8616 * 8617 * @return The id of a view this one succeedes in accessibility traversal if 8618 * specified, otherwise {@link #NO_ID}. 8619 * 8620 * @see #setAccessibilityTraversalAfter(int) 8621 */ 8622 public int getAccessibilityTraversalAfter() { 8623 return mAccessibilityTraversalAfterId; 8624 } 8625 8626 /** 8627 * Gets the id of a view for which this view serves as a label for 8628 * accessibility purposes. 8629 * 8630 * @return The labeled view id. 8631 */ 8632 @ViewDebug.ExportedProperty(category = "accessibility") 8633 public int getLabelFor() { 8634 return mLabelForId; 8635 } 8636 8637 /** 8638 * Sets the id of a view for which this view serves as a label for 8639 * accessibility purposes. 8640 * 8641 * @param id The labeled view id. 8642 */ 8643 @RemotableViewMethod 8644 public void setLabelFor(@IdRes int id) { 8645 if (mLabelForId == id) { 8646 return; 8647 } 8648 mLabelForId = id; 8649 if (mLabelForId != View.NO_ID 8650 && mID == View.NO_ID) { 8651 mID = generateViewId(); 8652 } 8653 notifyViewAccessibilityStateChangedIfNeeded( 8654 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8655 } 8656 8657 /** 8658 * Invoked whenever this view loses focus, either by losing window focus or by losing 8659 * focus within its window. This method can be used to clear any state tied to the 8660 * focus. For instance, if a button is held pressed with the trackball and the window 8661 * loses focus, this method can be used to cancel the press. 8662 * 8663 * Subclasses of View overriding this method should always call super.onFocusLost(). 8664 * 8665 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 8666 * @see #onWindowFocusChanged(boolean) 8667 * 8668 * @hide pending API council approval 8669 */ 8670 @CallSuper 8671 protected void onFocusLost() { 8672 resetPressedState(); 8673 } 8674 8675 private void resetPressedState() { 8676 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 8677 return; 8678 } 8679 8680 if (isPressed()) { 8681 setPressed(false); 8682 8683 if (!mHasPerformedLongPress) { 8684 removeLongPressCallback(); 8685 } 8686 } 8687 } 8688 8689 /** 8690 * Returns true if this view has focus 8691 * 8692 * @return True if this view has focus, false otherwise. 8693 */ 8694 @ViewDebug.ExportedProperty(category = "focus") 8695 public boolean isFocused() { 8696 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8697 } 8698 8699 /** 8700 * Find the view in the hierarchy rooted at this view that currently has 8701 * focus. 8702 * 8703 * @return The view that currently has focus, or null if no focused view can 8704 * be found. 8705 */ 8706 public View findFocus() { 8707 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 8708 } 8709 8710 /** 8711 * Indicates whether this view is one of the set of scrollable containers in 8712 * its window. 8713 * 8714 * @return whether this view is one of the set of scrollable containers in 8715 * its window 8716 * 8717 * @attr ref android.R.styleable#View_isScrollContainer 8718 */ 8719 public boolean isScrollContainer() { 8720 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 8721 } 8722 8723 /** 8724 * Change whether this view is one of the set of scrollable containers in 8725 * its window. This will be used to determine whether the window can 8726 * resize or must pan when a soft input area is open -- scrollable 8727 * containers allow the window to use resize mode since the container 8728 * will appropriately shrink. 8729 * 8730 * @attr ref android.R.styleable#View_isScrollContainer 8731 */ 8732 public void setScrollContainer(boolean isScrollContainer) { 8733 if (isScrollContainer) { 8734 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 8735 mAttachInfo.mScrollContainers.add(this); 8736 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 8737 } 8738 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 8739 } else { 8740 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 8741 mAttachInfo.mScrollContainers.remove(this); 8742 } 8743 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 8744 } 8745 } 8746 8747 /** 8748 * Returns the quality of the drawing cache. 8749 * 8750 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8751 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8752 * 8753 * @see #setDrawingCacheQuality(int) 8754 * @see #setDrawingCacheEnabled(boolean) 8755 * @see #isDrawingCacheEnabled() 8756 * 8757 * @attr ref android.R.styleable#View_drawingCacheQuality 8758 */ 8759 @DrawingCacheQuality 8760 public int getDrawingCacheQuality() { 8761 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 8762 } 8763 8764 /** 8765 * Set the drawing cache quality of this view. This value is used only when the 8766 * drawing cache is enabled 8767 * 8768 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8769 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8770 * 8771 * @see #getDrawingCacheQuality() 8772 * @see #setDrawingCacheEnabled(boolean) 8773 * @see #isDrawingCacheEnabled() 8774 * 8775 * @attr ref android.R.styleable#View_drawingCacheQuality 8776 */ 8777 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 8778 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 8779 } 8780 8781 /** 8782 * Returns whether the screen should remain on, corresponding to the current 8783 * value of {@link #KEEP_SCREEN_ON}. 8784 * 8785 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 8786 * 8787 * @see #setKeepScreenOn(boolean) 8788 * 8789 * @attr ref android.R.styleable#View_keepScreenOn 8790 */ 8791 public boolean getKeepScreenOn() { 8792 return (mViewFlags & KEEP_SCREEN_ON) != 0; 8793 } 8794 8795 /** 8796 * Controls whether the screen should remain on, modifying the 8797 * value of {@link #KEEP_SCREEN_ON}. 8798 * 8799 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 8800 * 8801 * @see #getKeepScreenOn() 8802 * 8803 * @attr ref android.R.styleable#View_keepScreenOn 8804 */ 8805 public void setKeepScreenOn(boolean keepScreenOn) { 8806 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 8807 } 8808 8809 /** 8810 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8811 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8812 * 8813 * @attr ref android.R.styleable#View_nextFocusLeft 8814 */ 8815 public int getNextFocusLeftId() { 8816 return mNextFocusLeftId; 8817 } 8818 8819 /** 8820 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8821 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 8822 * decide automatically. 8823 * 8824 * @attr ref android.R.styleable#View_nextFocusLeft 8825 */ 8826 public void setNextFocusLeftId(int nextFocusLeftId) { 8827 mNextFocusLeftId = nextFocusLeftId; 8828 } 8829 8830 /** 8831 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8832 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8833 * 8834 * @attr ref android.R.styleable#View_nextFocusRight 8835 */ 8836 public int getNextFocusRightId() { 8837 return mNextFocusRightId; 8838 } 8839 8840 /** 8841 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8842 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 8843 * decide automatically. 8844 * 8845 * @attr ref android.R.styleable#View_nextFocusRight 8846 */ 8847 public void setNextFocusRightId(int nextFocusRightId) { 8848 mNextFocusRightId = nextFocusRightId; 8849 } 8850 8851 /** 8852 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8853 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8854 * 8855 * @attr ref android.R.styleable#View_nextFocusUp 8856 */ 8857 public int getNextFocusUpId() { 8858 return mNextFocusUpId; 8859 } 8860 8861 /** 8862 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8863 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 8864 * decide automatically. 8865 * 8866 * @attr ref android.R.styleable#View_nextFocusUp 8867 */ 8868 public void setNextFocusUpId(int nextFocusUpId) { 8869 mNextFocusUpId = nextFocusUpId; 8870 } 8871 8872 /** 8873 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8874 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8875 * 8876 * @attr ref android.R.styleable#View_nextFocusDown 8877 */ 8878 public int getNextFocusDownId() { 8879 return mNextFocusDownId; 8880 } 8881 8882 /** 8883 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8884 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 8885 * decide automatically. 8886 * 8887 * @attr ref android.R.styleable#View_nextFocusDown 8888 */ 8889 public void setNextFocusDownId(int nextFocusDownId) { 8890 mNextFocusDownId = nextFocusDownId; 8891 } 8892 8893 /** 8894 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8895 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8896 * 8897 * @attr ref android.R.styleable#View_nextFocusForward 8898 */ 8899 public int getNextFocusForwardId() { 8900 return mNextFocusForwardId; 8901 } 8902 8903 /** 8904 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8905 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 8906 * decide automatically. 8907 * 8908 * @attr ref android.R.styleable#View_nextFocusForward 8909 */ 8910 public void setNextFocusForwardId(int nextFocusForwardId) { 8911 mNextFocusForwardId = nextFocusForwardId; 8912 } 8913 8914 /** 8915 * Gets the id of the root of the next keyboard navigation cluster. 8916 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 8917 * decide automatically. 8918 * 8919 * @attr ref android.R.styleable#View_nextClusterForward 8920 */ 8921 public int getNextClusterForwardId() { 8922 return mNextClusterForwardId; 8923 } 8924 8925 /** 8926 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 8927 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 8928 * decide automatically. 8929 * 8930 * @attr ref android.R.styleable#View_nextClusterForward 8931 */ 8932 public void setNextClusterForwardId(int nextClusterForwardId) { 8933 mNextClusterForwardId = nextClusterForwardId; 8934 } 8935 8936 /** 8937 * Returns the visibility of this view and all of its ancestors 8938 * 8939 * @return True if this view and all of its ancestors are {@link #VISIBLE} 8940 */ 8941 public boolean isShown() { 8942 View current = this; 8943 //noinspection ConstantConditions 8944 do { 8945 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 8946 return false; 8947 } 8948 ViewParent parent = current.mParent; 8949 if (parent == null) { 8950 return false; // We are not attached to the view root 8951 } 8952 if (!(parent instanceof View)) { 8953 return true; 8954 } 8955 current = (View) parent; 8956 } while (current != null); 8957 8958 return false; 8959 } 8960 8961 /** 8962 * Called by the view hierarchy when the content insets for a window have 8963 * changed, to allow it to adjust its content to fit within those windows. 8964 * The content insets tell you the space that the status bar, input method, 8965 * and other system windows infringe on the application's window. 8966 * 8967 * <p>You do not normally need to deal with this function, since the default 8968 * window decoration given to applications takes care of applying it to the 8969 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 8970 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 8971 * and your content can be placed under those system elements. You can then 8972 * use this method within your view hierarchy if you have parts of your UI 8973 * which you would like to ensure are not being covered. 8974 * 8975 * <p>The default implementation of this method simply applies the content 8976 * insets to the view's padding, consuming that content (modifying the 8977 * insets to be 0), and returning true. This behavior is off by default, but can 8978 * be enabled through {@link #setFitsSystemWindows(boolean)}. 8979 * 8980 * <p>This function's traversal down the hierarchy is depth-first. The same content 8981 * insets object is propagated down the hierarchy, so any changes made to it will 8982 * be seen by all following views (including potentially ones above in 8983 * the hierarchy since this is a depth-first traversal). The first view 8984 * that returns true will abort the entire traversal. 8985 * 8986 * <p>The default implementation works well for a situation where it is 8987 * used with a container that covers the entire window, allowing it to 8988 * apply the appropriate insets to its content on all edges. If you need 8989 * a more complicated layout (such as two different views fitting system 8990 * windows, one on the top of the window, and one on the bottom), 8991 * you can override the method and handle the insets however you would like. 8992 * Note that the insets provided by the framework are always relative to the 8993 * far edges of the window, not accounting for the location of the called view 8994 * within that window. (In fact when this method is called you do not yet know 8995 * where the layout will place the view, as it is done before layout happens.) 8996 * 8997 * <p>Note: unlike many View methods, there is no dispatch phase to this 8998 * call. If you are overriding it in a ViewGroup and want to allow the 8999 * call to continue to your children, you must be sure to call the super 9000 * implementation. 9001 * 9002 * <p>Here is a sample layout that makes use of fitting system windows 9003 * to have controls for a video view placed inside of the window decorations 9004 * that it hides and shows. This can be used with code like the second 9005 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 9006 * 9007 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 9008 * 9009 * @param insets Current content insets of the window. Prior to 9010 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 9011 * the insets or else you and Android will be unhappy. 9012 * 9013 * @return {@code true} if this view applied the insets and it should not 9014 * continue propagating further down the hierarchy, {@code false} otherwise. 9015 * @see #getFitsSystemWindows() 9016 * @see #setFitsSystemWindows(boolean) 9017 * @see #setSystemUiVisibility(int) 9018 * 9019 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 9020 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 9021 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 9022 * to implement handling their own insets. 9023 */ 9024 @Deprecated 9025 protected boolean fitSystemWindows(Rect insets) { 9026 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 9027 if (insets == null) { 9028 // Null insets by definition have already been consumed. 9029 // This call cannot apply insets since there are none to apply, 9030 // so return false. 9031 return false; 9032 } 9033 // If we're not in the process of dispatching the newer apply insets call, 9034 // that means we're not in the compatibility path. Dispatch into the newer 9035 // apply insets path and take things from there. 9036 try { 9037 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 9038 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 9039 } finally { 9040 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 9041 } 9042 } else { 9043 // We're being called from the newer apply insets path. 9044 // Perform the standard fallback behavior. 9045 return fitSystemWindowsInt(insets); 9046 } 9047 } 9048 9049 private boolean fitSystemWindowsInt(Rect insets) { 9050 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 9051 mUserPaddingStart = UNDEFINED_PADDING; 9052 mUserPaddingEnd = UNDEFINED_PADDING; 9053 Rect localInsets = sThreadLocal.get(); 9054 if (localInsets == null) { 9055 localInsets = new Rect(); 9056 sThreadLocal.set(localInsets); 9057 } 9058 boolean res = computeFitSystemWindows(insets, localInsets); 9059 mUserPaddingLeftInitial = localInsets.left; 9060 mUserPaddingRightInitial = localInsets.right; 9061 internalSetPadding(localInsets.left, localInsets.top, 9062 localInsets.right, localInsets.bottom); 9063 return res; 9064 } 9065 return false; 9066 } 9067 9068 /** 9069 * Called when the view should apply {@link WindowInsets} according to its internal policy. 9070 * 9071 * <p>This method should be overridden by views that wish to apply a policy different from or 9072 * in addition to the default behavior. Clients that wish to force a view subtree 9073 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 9074 * 9075 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 9076 * it will be called during dispatch instead of this method. The listener may optionally 9077 * call this method from its own implementation if it wishes to apply the view's default 9078 * insets policy in addition to its own.</p> 9079 * 9080 * <p>Implementations of this method should either return the insets parameter unchanged 9081 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 9082 * that this view applied itself. This allows new inset types added in future platform 9083 * versions to pass through existing implementations unchanged without being erroneously 9084 * consumed.</p> 9085 * 9086 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 9087 * property is set then the view will consume the system window insets and apply them 9088 * as padding for the view.</p> 9089 * 9090 * @param insets Insets to apply 9091 * @return The supplied insets with any applied insets consumed 9092 */ 9093 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 9094 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 9095 // We weren't called from within a direct call to fitSystemWindows, 9096 // call into it as a fallback in case we're in a class that overrides it 9097 // and has logic to perform. 9098 if (fitSystemWindows(insets.getSystemWindowInsets())) { 9099 return insets.consumeSystemWindowInsets(); 9100 } 9101 } else { 9102 // We were called from within a direct call to fitSystemWindows. 9103 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 9104 return insets.consumeSystemWindowInsets(); 9105 } 9106 } 9107 return insets; 9108 } 9109 9110 /** 9111 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 9112 * window insets to this view. The listener's 9113 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 9114 * method will be called instead of the view's 9115 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 9116 * 9117 * @param listener Listener to set 9118 * 9119 * @see #onApplyWindowInsets(WindowInsets) 9120 */ 9121 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 9122 getListenerInfo().mOnApplyWindowInsetsListener = listener; 9123 } 9124 9125 /** 9126 * Request to apply the given window insets to this view or another view in its subtree. 9127 * 9128 * <p>This method should be called by clients wishing to apply insets corresponding to areas 9129 * obscured by window decorations or overlays. This can include the status and navigation bars, 9130 * action bars, input methods and more. New inset categories may be added in the future. 9131 * The method returns the insets provided minus any that were applied by this view or its 9132 * children.</p> 9133 * 9134 * <p>Clients wishing to provide custom behavior should override the 9135 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 9136 * {@link OnApplyWindowInsetsListener} via the 9137 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 9138 * method.</p> 9139 * 9140 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 9141 * </p> 9142 * 9143 * @param insets Insets to apply 9144 * @return The provided insets minus the insets that were consumed 9145 */ 9146 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 9147 try { 9148 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 9149 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 9150 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 9151 } else { 9152 return onApplyWindowInsets(insets); 9153 } 9154 } finally { 9155 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 9156 } 9157 } 9158 9159 /** 9160 * Compute the view's coordinate within the surface. 9161 * 9162 * <p>Computes the coordinates of this view in its surface. The argument 9163 * must be an array of two integers. After the method returns, the array 9164 * contains the x and y location in that order.</p> 9165 * @hide 9166 * @param location an array of two integers in which to hold the coordinates 9167 */ 9168 public void getLocationInSurface(@Size(2) int[] location) { 9169 getLocationInWindow(location); 9170 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 9171 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 9172 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 9173 } 9174 } 9175 9176 /** 9177 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 9178 * only available if the view is attached. 9179 * 9180 * @return WindowInsets from the top of the view hierarchy or null if View is detached 9181 */ 9182 public WindowInsets getRootWindowInsets() { 9183 if (mAttachInfo != null) { 9184 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 9185 } 9186 return null; 9187 } 9188 9189 /** 9190 * @hide Compute the insets that should be consumed by this view and the ones 9191 * that should propagate to those under it. 9192 */ 9193 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 9194 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 9195 || mAttachInfo == null 9196 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 9197 && !mAttachInfo.mOverscanRequested)) { 9198 outLocalInsets.set(inoutInsets); 9199 inoutInsets.set(0, 0, 0, 0); 9200 return true; 9201 } else { 9202 // The application wants to take care of fitting system window for 9203 // the content... however we still need to take care of any overscan here. 9204 final Rect overscan = mAttachInfo.mOverscanInsets; 9205 outLocalInsets.set(overscan); 9206 inoutInsets.left -= overscan.left; 9207 inoutInsets.top -= overscan.top; 9208 inoutInsets.right -= overscan.right; 9209 inoutInsets.bottom -= overscan.bottom; 9210 return false; 9211 } 9212 } 9213 9214 /** 9215 * Compute insets that should be consumed by this view and the ones that should propagate 9216 * to those under it. 9217 * 9218 * @param in Insets currently being processed by this View, likely received as a parameter 9219 * to {@link #onApplyWindowInsets(WindowInsets)}. 9220 * @param outLocalInsets A Rect that will receive the insets that should be consumed 9221 * by this view 9222 * @return Insets that should be passed along to views under this one 9223 */ 9224 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 9225 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 9226 || mAttachInfo == null 9227 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 9228 outLocalInsets.set(in.getSystemWindowInsets()); 9229 return in.consumeSystemWindowInsets(); 9230 } else { 9231 outLocalInsets.set(0, 0, 0, 0); 9232 return in; 9233 } 9234 } 9235 9236 /** 9237 * Sets whether or not this view should account for system screen decorations 9238 * such as the status bar and inset its content; that is, controlling whether 9239 * the default implementation of {@link #fitSystemWindows(Rect)} will be 9240 * executed. See that method for more details. 9241 * 9242 * <p>Note that if you are providing your own implementation of 9243 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 9244 * flag to true -- your implementation will be overriding the default 9245 * implementation that checks this flag. 9246 * 9247 * @param fitSystemWindows If true, then the default implementation of 9248 * {@link #fitSystemWindows(Rect)} will be executed. 9249 * 9250 * @attr ref android.R.styleable#View_fitsSystemWindows 9251 * @see #getFitsSystemWindows() 9252 * @see #fitSystemWindows(Rect) 9253 * @see #setSystemUiVisibility(int) 9254 */ 9255 public void setFitsSystemWindows(boolean fitSystemWindows) { 9256 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 9257 } 9258 9259 /** 9260 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 9261 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 9262 * will be executed. 9263 * 9264 * @return {@code true} if the default implementation of 9265 * {@link #fitSystemWindows(Rect)} will be executed. 9266 * 9267 * @attr ref android.R.styleable#View_fitsSystemWindows 9268 * @see #setFitsSystemWindows(boolean) 9269 * @see #fitSystemWindows(Rect) 9270 * @see #setSystemUiVisibility(int) 9271 */ 9272 @ViewDebug.ExportedProperty 9273 public boolean getFitsSystemWindows() { 9274 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 9275 } 9276 9277 /** @hide */ 9278 public boolean fitsSystemWindows() { 9279 return getFitsSystemWindows(); 9280 } 9281 9282 /** 9283 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 9284 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 9285 */ 9286 @Deprecated 9287 public void requestFitSystemWindows() { 9288 if (mParent != null) { 9289 mParent.requestFitSystemWindows(); 9290 } 9291 } 9292 9293 /** 9294 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 9295 */ 9296 public void requestApplyInsets() { 9297 requestFitSystemWindows(); 9298 } 9299 9300 /** 9301 * For use by PhoneWindow to make its own system window fitting optional. 9302 * @hide 9303 */ 9304 public void makeOptionalFitsSystemWindows() { 9305 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 9306 } 9307 9308 /** 9309 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 9310 * treat them as such. 9311 * @hide 9312 */ 9313 public void getOutsets(Rect outOutsetRect) { 9314 if (mAttachInfo != null) { 9315 outOutsetRect.set(mAttachInfo.mOutsets); 9316 } else { 9317 outOutsetRect.setEmpty(); 9318 } 9319 } 9320 9321 /** 9322 * Returns the visibility status for this view. 9323 * 9324 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9325 * @attr ref android.R.styleable#View_visibility 9326 */ 9327 @ViewDebug.ExportedProperty(mapping = { 9328 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 9329 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 9330 @ViewDebug.IntToString(from = GONE, to = "GONE") 9331 }) 9332 @Visibility 9333 public int getVisibility() { 9334 return mViewFlags & VISIBILITY_MASK; 9335 } 9336 9337 /** 9338 * Set the visibility state of this view. 9339 * 9340 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9341 * @attr ref android.R.styleable#View_visibility 9342 */ 9343 @RemotableViewMethod 9344 public void setVisibility(@Visibility int visibility) { 9345 setFlags(visibility, VISIBILITY_MASK); 9346 } 9347 9348 /** 9349 * Returns the enabled status for this view. The interpretation of the 9350 * enabled state varies by subclass. 9351 * 9352 * @return True if this view is enabled, false otherwise. 9353 */ 9354 @ViewDebug.ExportedProperty 9355 public boolean isEnabled() { 9356 return (mViewFlags & ENABLED_MASK) == ENABLED; 9357 } 9358 9359 /** 9360 * Set the enabled state of this view. The interpretation of the enabled 9361 * state varies by subclass. 9362 * 9363 * @param enabled True if this view is enabled, false otherwise. 9364 */ 9365 @RemotableViewMethod 9366 public void setEnabled(boolean enabled) { 9367 if (enabled == isEnabled()) return; 9368 9369 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 9370 9371 /* 9372 * The View most likely has to change its appearance, so refresh 9373 * the drawable state. 9374 */ 9375 refreshDrawableState(); 9376 9377 // Invalidate too, since the default behavior for views is to be 9378 // be drawn at 50% alpha rather than to change the drawable. 9379 invalidate(true); 9380 9381 if (!enabled) { 9382 cancelPendingInputEvents(); 9383 } 9384 } 9385 9386 /** 9387 * Set whether this view can receive the focus. 9388 * <p> 9389 * Setting this to false will also ensure that this view is not focusable 9390 * in touch mode. 9391 * 9392 * @param focusable If true, this view can receive the focus. 9393 * 9394 * @see #setFocusableInTouchMode(boolean) 9395 * @see #setFocusable(int) 9396 * @attr ref android.R.styleable#View_focusable 9397 */ 9398 public void setFocusable(boolean focusable) { 9399 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 9400 } 9401 9402 /** 9403 * Sets whether this view can receive focus. 9404 * <p> 9405 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 9406 * automatically based on the view's interactivity. This is the default. 9407 * <p> 9408 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 9409 * in touch mode. 9410 * 9411 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 9412 * or {@link #FOCUSABLE_AUTO}. 9413 * @see #setFocusableInTouchMode(boolean) 9414 * @attr ref android.R.styleable#View_focusable 9415 */ 9416 public void setFocusable(@Focusable int focusable) { 9417 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 9418 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 9419 } 9420 setFlags(focusable, FOCUSABLE_MASK); 9421 } 9422 9423 /** 9424 * Set whether this view can receive focus while in touch mode. 9425 * 9426 * Setting this to true will also ensure that this view is focusable. 9427 * 9428 * @param focusableInTouchMode If true, this view can receive the focus while 9429 * in touch mode. 9430 * 9431 * @see #setFocusable(boolean) 9432 * @attr ref android.R.styleable#View_focusableInTouchMode 9433 */ 9434 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 9435 // Focusable in touch mode should always be set before the focusable flag 9436 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 9437 // which, in touch mode, will not successfully request focus on this view 9438 // because the focusable in touch mode flag is not set 9439 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 9440 9441 // Clear FOCUSABLE_AUTO if set. 9442 if (focusableInTouchMode) { 9443 // Clears FOCUSABLE_AUTO if set. 9444 setFlags(FOCUSABLE, FOCUSABLE_MASK); 9445 } 9446 } 9447 9448 /** 9449 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 9450 * to autofill the view with the user's data. 9451 * 9452 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 9453 * For example, if the application accepts either an username or email address to identify 9454 * an user. 9455 * 9456 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 9457 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 9458 * constants such as: 9459 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 9460 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 9461 * {@link #AUTOFILL_HINT_NAME}, 9462 * {@link #AUTOFILL_HINT_PHONE}, 9463 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 9464 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 9465 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 9466 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 9467 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 9468 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 9469 * 9470 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 9471 * @attr ref android.R.styleable#View_autofillHints 9472 */ 9473 public void setAutofillHints(@Nullable String... autofillHints) { 9474 if (autofillHints == null || autofillHints.length == 0) { 9475 mAutofillHints = null; 9476 } else { 9477 mAutofillHints = autofillHints; 9478 } 9479 } 9480 9481 /** 9482 * @hide 9483 */ 9484 @TestApi 9485 public void setAutofilled(boolean isAutofilled) { 9486 boolean wasChanged = isAutofilled != isAutofilled(); 9487 9488 if (wasChanged) { 9489 if (isAutofilled) { 9490 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 9491 } else { 9492 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 9493 } 9494 9495 invalidate(); 9496 } 9497 } 9498 9499 /** 9500 * Set whether this view should have sound effects enabled for events such as 9501 * clicking and touching. 9502 * 9503 * <p>You may wish to disable sound effects for a view if you already play sounds, 9504 * for instance, a dial key that plays dtmf tones. 9505 * 9506 * @param soundEffectsEnabled whether sound effects are enabled for this view. 9507 * @see #isSoundEffectsEnabled() 9508 * @see #playSoundEffect(int) 9509 * @attr ref android.R.styleable#View_soundEffectsEnabled 9510 */ 9511 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 9512 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 9513 } 9514 9515 /** 9516 * @return whether this view should have sound effects enabled for events such as 9517 * clicking and touching. 9518 * 9519 * @see #setSoundEffectsEnabled(boolean) 9520 * @see #playSoundEffect(int) 9521 * @attr ref android.R.styleable#View_soundEffectsEnabled 9522 */ 9523 @ViewDebug.ExportedProperty 9524 public boolean isSoundEffectsEnabled() { 9525 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 9526 } 9527 9528 /** 9529 * Set whether this view should have haptic feedback for events such as 9530 * long presses. 9531 * 9532 * <p>You may wish to disable haptic feedback if your view already controls 9533 * its own haptic feedback. 9534 * 9535 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 9536 * @see #isHapticFeedbackEnabled() 9537 * @see #performHapticFeedback(int) 9538 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9539 */ 9540 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 9541 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 9542 } 9543 9544 /** 9545 * @return whether this view should have haptic feedback enabled for events 9546 * long presses. 9547 * 9548 * @see #setHapticFeedbackEnabled(boolean) 9549 * @see #performHapticFeedback(int) 9550 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9551 */ 9552 @ViewDebug.ExportedProperty 9553 public boolean isHapticFeedbackEnabled() { 9554 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 9555 } 9556 9557 /** 9558 * Returns the layout direction for this view. 9559 * 9560 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 9561 * {@link #LAYOUT_DIRECTION_RTL}, 9562 * {@link #LAYOUT_DIRECTION_INHERIT} or 9563 * {@link #LAYOUT_DIRECTION_LOCALE}. 9564 * 9565 * @attr ref android.R.styleable#View_layoutDirection 9566 * 9567 * @hide 9568 */ 9569 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9570 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 9571 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 9572 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 9573 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 9574 }) 9575 @LayoutDir 9576 public int getRawLayoutDirection() { 9577 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 9578 } 9579 9580 /** 9581 * Set the layout direction for this view. This will propagate a reset of layout direction 9582 * resolution to the view's children and resolve layout direction for this view. 9583 * 9584 * @param layoutDirection the layout direction to set. Should be one of: 9585 * 9586 * {@link #LAYOUT_DIRECTION_LTR}, 9587 * {@link #LAYOUT_DIRECTION_RTL}, 9588 * {@link #LAYOUT_DIRECTION_INHERIT}, 9589 * {@link #LAYOUT_DIRECTION_LOCALE}. 9590 * 9591 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 9592 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 9593 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 9594 * 9595 * @attr ref android.R.styleable#View_layoutDirection 9596 */ 9597 @RemotableViewMethod 9598 public void setLayoutDirection(@LayoutDir int layoutDirection) { 9599 if (getRawLayoutDirection() != layoutDirection) { 9600 // Reset the current layout direction and the resolved one 9601 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 9602 resetRtlProperties(); 9603 // Set the new layout direction (filtered) 9604 mPrivateFlags2 |= 9605 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 9606 // We need to resolve all RTL properties as they all depend on layout direction 9607 resolveRtlPropertiesIfNeeded(); 9608 requestLayout(); 9609 invalidate(true); 9610 } 9611 } 9612 9613 /** 9614 * Returns the resolved layout direction for this view. 9615 * 9616 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 9617 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 9618 * 9619 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 9620 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 9621 * 9622 * @attr ref android.R.styleable#View_layoutDirection 9623 */ 9624 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9625 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 9626 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 9627 }) 9628 @ResolvedLayoutDir 9629 public int getLayoutDirection() { 9630 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 9631 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 9632 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 9633 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 9634 } 9635 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 9636 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 9637 } 9638 9639 /** 9640 * Indicates whether or not this view's layout is right-to-left. This is resolved from 9641 * layout attribute and/or the inherited value from the parent 9642 * 9643 * @return true if the layout is right-to-left. 9644 * 9645 * @hide 9646 */ 9647 @ViewDebug.ExportedProperty(category = "layout") 9648 public boolean isLayoutRtl() { 9649 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 9650 } 9651 9652 /** 9653 * Indicates whether the view is currently tracking transient state that the 9654 * app should not need to concern itself with saving and restoring, but that 9655 * the framework should take special note to preserve when possible. 9656 * 9657 * <p>A view with transient state cannot be trivially rebound from an external 9658 * data source, such as an adapter binding item views in a list. This may be 9659 * because the view is performing an animation, tracking user selection 9660 * of content, or similar.</p> 9661 * 9662 * @return true if the view has transient state 9663 */ 9664 @ViewDebug.ExportedProperty(category = "layout") 9665 public boolean hasTransientState() { 9666 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 9667 } 9668 9669 /** 9670 * Set whether this view is currently tracking transient state that the 9671 * framework should attempt to preserve when possible. This flag is reference counted, 9672 * so every call to setHasTransientState(true) should be paired with a later call 9673 * to setHasTransientState(false). 9674 * 9675 * <p>A view with transient state cannot be trivially rebound from an external 9676 * data source, such as an adapter binding item views in a list. This may be 9677 * because the view is performing an animation, tracking user selection 9678 * of content, or similar.</p> 9679 * 9680 * @param hasTransientState true if this view has transient state 9681 */ 9682 public void setHasTransientState(boolean hasTransientState) { 9683 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 9684 mTransientStateCount - 1; 9685 if (mTransientStateCount < 0) { 9686 mTransientStateCount = 0; 9687 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 9688 "unmatched pair of setHasTransientState calls"); 9689 } else if ((hasTransientState && mTransientStateCount == 1) || 9690 (!hasTransientState && mTransientStateCount == 0)) { 9691 // update flag if we've just incremented up from 0 or decremented down to 0 9692 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 9693 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 9694 if (mParent != null) { 9695 try { 9696 mParent.childHasTransientStateChanged(this, hasTransientState); 9697 } catch (AbstractMethodError e) { 9698 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 9699 " does not fully implement ViewParent", e); 9700 } 9701 } 9702 } 9703 } 9704 9705 /** 9706 * Returns true if this view is currently attached to a window. 9707 */ 9708 public boolean isAttachedToWindow() { 9709 return mAttachInfo != null; 9710 } 9711 9712 /** 9713 * Returns true if this view has been through at least one layout since it 9714 * was last attached to or detached from a window. 9715 */ 9716 public boolean isLaidOut() { 9717 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 9718 } 9719 9720 /** 9721 * If this view doesn't do any drawing on its own, set this flag to 9722 * allow further optimizations. By default, this flag is not set on 9723 * View, but could be set on some View subclasses such as ViewGroup. 9724 * 9725 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 9726 * you should clear this flag. 9727 * 9728 * @param willNotDraw whether or not this View draw on its own 9729 */ 9730 public void setWillNotDraw(boolean willNotDraw) { 9731 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 9732 } 9733 9734 /** 9735 * Returns whether or not this View draws on its own. 9736 * 9737 * @return true if this view has nothing to draw, false otherwise 9738 */ 9739 @ViewDebug.ExportedProperty(category = "drawing") 9740 public boolean willNotDraw() { 9741 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 9742 } 9743 9744 /** 9745 * When a View's drawing cache is enabled, drawing is redirected to an 9746 * offscreen bitmap. Some views, like an ImageView, must be able to 9747 * bypass this mechanism if they already draw a single bitmap, to avoid 9748 * unnecessary usage of the memory. 9749 * 9750 * @param willNotCacheDrawing true if this view does not cache its 9751 * drawing, false otherwise 9752 */ 9753 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 9754 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 9755 } 9756 9757 /** 9758 * Returns whether or not this View can cache its drawing or not. 9759 * 9760 * @return true if this view does not cache its drawing, false otherwise 9761 */ 9762 @ViewDebug.ExportedProperty(category = "drawing") 9763 public boolean willNotCacheDrawing() { 9764 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 9765 } 9766 9767 /** 9768 * Indicates whether this view reacts to click events or not. 9769 * 9770 * @return true if the view is clickable, false otherwise 9771 * 9772 * @see #setClickable(boolean) 9773 * @attr ref android.R.styleable#View_clickable 9774 */ 9775 @ViewDebug.ExportedProperty 9776 public boolean isClickable() { 9777 return (mViewFlags & CLICKABLE) == CLICKABLE; 9778 } 9779 9780 /** 9781 * Enables or disables click events for this view. When a view 9782 * is clickable it will change its state to "pressed" on every click. 9783 * Subclasses should set the view clickable to visually react to 9784 * user's clicks. 9785 * 9786 * @param clickable true to make the view clickable, false otherwise 9787 * 9788 * @see #isClickable() 9789 * @attr ref android.R.styleable#View_clickable 9790 */ 9791 public void setClickable(boolean clickable) { 9792 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 9793 } 9794 9795 /** 9796 * Indicates whether this view reacts to long click events or not. 9797 * 9798 * @return true if the view is long clickable, false otherwise 9799 * 9800 * @see #setLongClickable(boolean) 9801 * @attr ref android.R.styleable#View_longClickable 9802 */ 9803 public boolean isLongClickable() { 9804 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 9805 } 9806 9807 /** 9808 * Enables or disables long click events for this view. When a view is long 9809 * clickable it reacts to the user holding down the button for a longer 9810 * duration than a tap. This event can either launch the listener or a 9811 * context menu. 9812 * 9813 * @param longClickable true to make the view long clickable, false otherwise 9814 * @see #isLongClickable() 9815 * @attr ref android.R.styleable#View_longClickable 9816 */ 9817 public void setLongClickable(boolean longClickable) { 9818 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 9819 } 9820 9821 /** 9822 * Indicates whether this view reacts to context clicks or not. 9823 * 9824 * @return true if the view is context clickable, false otherwise 9825 * @see #setContextClickable(boolean) 9826 * @attr ref android.R.styleable#View_contextClickable 9827 */ 9828 public boolean isContextClickable() { 9829 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 9830 } 9831 9832 /** 9833 * Enables or disables context clicking for this view. This event can launch the listener. 9834 * 9835 * @param contextClickable true to make the view react to a context click, false otherwise 9836 * @see #isContextClickable() 9837 * @attr ref android.R.styleable#View_contextClickable 9838 */ 9839 public void setContextClickable(boolean contextClickable) { 9840 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 9841 } 9842 9843 /** 9844 * Sets the pressed state for this view and provides a touch coordinate for 9845 * animation hinting. 9846 * 9847 * @param pressed Pass true to set the View's internal state to "pressed", 9848 * or false to reverts the View's internal state from a 9849 * previously set "pressed" state. 9850 * @param x The x coordinate of the touch that caused the press 9851 * @param y The y coordinate of the touch that caused the press 9852 */ 9853 private void setPressed(boolean pressed, float x, float y) { 9854 if (pressed) { 9855 drawableHotspotChanged(x, y); 9856 } 9857 9858 setPressed(pressed); 9859 } 9860 9861 /** 9862 * Sets the pressed state for this view. 9863 * 9864 * @see #isClickable() 9865 * @see #setClickable(boolean) 9866 * 9867 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 9868 * the View's internal state from a previously set "pressed" state. 9869 */ 9870 public void setPressed(boolean pressed) { 9871 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 9872 9873 if (pressed) { 9874 mPrivateFlags |= PFLAG_PRESSED; 9875 } else { 9876 mPrivateFlags &= ~PFLAG_PRESSED; 9877 } 9878 9879 if (needsRefresh) { 9880 refreshDrawableState(); 9881 } 9882 dispatchSetPressed(pressed); 9883 } 9884 9885 /** 9886 * Dispatch setPressed to all of this View's children. 9887 * 9888 * @see #setPressed(boolean) 9889 * 9890 * @param pressed The new pressed state 9891 */ 9892 protected void dispatchSetPressed(boolean pressed) { 9893 } 9894 9895 /** 9896 * Indicates whether the view is currently in pressed state. Unless 9897 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 9898 * the pressed state. 9899 * 9900 * @see #setPressed(boolean) 9901 * @see #isClickable() 9902 * @see #setClickable(boolean) 9903 * 9904 * @return true if the view is currently pressed, false otherwise 9905 */ 9906 @ViewDebug.ExportedProperty 9907 public boolean isPressed() { 9908 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 9909 } 9910 9911 /** 9912 * @hide 9913 * Indicates whether this view will participate in data collection through 9914 * {@link ViewStructure}. If true, it will not provide any data 9915 * for itself or its children. If false, the normal data collection will be allowed. 9916 * 9917 * @return Returns false if assist data collection is not blocked, else true. 9918 * 9919 * @see #setAssistBlocked(boolean) 9920 * @attr ref android.R.styleable#View_assistBlocked 9921 */ 9922 public boolean isAssistBlocked() { 9923 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 9924 } 9925 9926 /** 9927 * @hide 9928 * Controls whether assist data collection from this view and its children is enabled 9929 * (that is, whether {@link #onProvideStructure} and 9930 * {@link #onProvideVirtualStructure} will be called). The default value is false, 9931 * allowing normal assist collection. Setting this to false will disable assist collection. 9932 * 9933 * @param enabled Set to true to <em>disable</em> assist data collection, or false 9934 * (the default) to allow it. 9935 * 9936 * @see #isAssistBlocked() 9937 * @see #onProvideStructure 9938 * @see #onProvideVirtualStructure 9939 * @attr ref android.R.styleable#View_assistBlocked 9940 */ 9941 public void setAssistBlocked(boolean enabled) { 9942 if (enabled) { 9943 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 9944 } else { 9945 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 9946 } 9947 } 9948 9949 /** 9950 * Indicates whether this view will save its state (that is, 9951 * whether its {@link #onSaveInstanceState} method will be called). 9952 * 9953 * @return Returns true if the view state saving is enabled, else false. 9954 * 9955 * @see #setSaveEnabled(boolean) 9956 * @attr ref android.R.styleable#View_saveEnabled 9957 */ 9958 public boolean isSaveEnabled() { 9959 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 9960 } 9961 9962 /** 9963 * Controls whether the saving of this view's state is 9964 * enabled (that is, whether its {@link #onSaveInstanceState} method 9965 * will be called). Note that even if freezing is enabled, the 9966 * view still must have an id assigned to it (via {@link #setId(int)}) 9967 * for its state to be saved. This flag can only disable the 9968 * saving of this view; any child views may still have their state saved. 9969 * 9970 * @param enabled Set to false to <em>disable</em> state saving, or true 9971 * (the default) to allow it. 9972 * 9973 * @see #isSaveEnabled() 9974 * @see #setId(int) 9975 * @see #onSaveInstanceState() 9976 * @attr ref android.R.styleable#View_saveEnabled 9977 */ 9978 public void setSaveEnabled(boolean enabled) { 9979 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 9980 } 9981 9982 /** 9983 * Gets whether the framework should discard touches when the view's 9984 * window is obscured by another visible window. 9985 * Refer to the {@link View} security documentation for more details. 9986 * 9987 * @return True if touch filtering is enabled. 9988 * 9989 * @see #setFilterTouchesWhenObscured(boolean) 9990 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9991 */ 9992 @ViewDebug.ExportedProperty 9993 public boolean getFilterTouchesWhenObscured() { 9994 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 9995 } 9996 9997 /** 9998 * Sets whether the framework should discard touches when the view's 9999 * window is obscured by another visible window. 10000 * Refer to the {@link View} security documentation for more details. 10001 * 10002 * @param enabled True if touch filtering should be enabled. 10003 * 10004 * @see #getFilterTouchesWhenObscured 10005 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 10006 */ 10007 public void setFilterTouchesWhenObscured(boolean enabled) { 10008 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 10009 FILTER_TOUCHES_WHEN_OBSCURED); 10010 } 10011 10012 /** 10013 * Indicates whether the entire hierarchy under this view will save its 10014 * state when a state saving traversal occurs from its parent. The default 10015 * is true; if false, these views will not be saved unless 10016 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 10017 * 10018 * @return Returns true if the view state saving from parent is enabled, else false. 10019 * 10020 * @see #setSaveFromParentEnabled(boolean) 10021 */ 10022 public boolean isSaveFromParentEnabled() { 10023 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 10024 } 10025 10026 /** 10027 * Controls whether the entire hierarchy under this view will save its 10028 * state when a state saving traversal occurs from its parent. The default 10029 * is true; if false, these views will not be saved unless 10030 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 10031 * 10032 * @param enabled Set to false to <em>disable</em> state saving, or true 10033 * (the default) to allow it. 10034 * 10035 * @see #isSaveFromParentEnabled() 10036 * @see #setId(int) 10037 * @see #onSaveInstanceState() 10038 */ 10039 public void setSaveFromParentEnabled(boolean enabled) { 10040 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 10041 } 10042 10043 10044 /** 10045 * Returns whether this View is currently able to take focus. 10046 * 10047 * @return True if this view can take focus, or false otherwise. 10048 */ 10049 @ViewDebug.ExportedProperty(category = "focus") 10050 public final boolean isFocusable() { 10051 return FOCUSABLE == (mViewFlags & FOCUSABLE); 10052 } 10053 10054 /** 10055 * Returns the focusable setting for this view. 10056 * 10057 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 10058 * @attr ref android.R.styleable#View_focusable 10059 */ 10060 @ViewDebug.ExportedProperty(mapping = { 10061 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 10062 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 10063 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 10064 }, category = "focus") 10065 @Focusable 10066 public int getFocusable() { 10067 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 10068 } 10069 10070 /** 10071 * When a view is focusable, it may not want to take focus when in touch mode. 10072 * For example, a button would like focus when the user is navigating via a D-pad 10073 * so that the user can click on it, but once the user starts touching the screen, 10074 * the button shouldn't take focus 10075 * @return Whether the view is focusable in touch mode. 10076 * @attr ref android.R.styleable#View_focusableInTouchMode 10077 */ 10078 @ViewDebug.ExportedProperty(category = "focus") 10079 public final boolean isFocusableInTouchMode() { 10080 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 10081 } 10082 10083 /** 10084 * Find the nearest view in the specified direction that can take focus. 10085 * This does not actually give focus to that view. 10086 * 10087 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10088 * 10089 * @return The nearest focusable in the specified direction, or null if none 10090 * can be found. 10091 */ 10092 public View focusSearch(@FocusRealDirection int direction) { 10093 if (mParent != null) { 10094 return mParent.focusSearch(this, direction); 10095 } else { 10096 return null; 10097 } 10098 } 10099 10100 /** 10101 * Returns whether this View is a root of a keyboard navigation cluster. 10102 * 10103 * @return True if this view is a root of a cluster, or false otherwise. 10104 * @attr ref android.R.styleable#View_keyboardNavigationCluster 10105 */ 10106 @ViewDebug.ExportedProperty(category = "focus") 10107 public final boolean isKeyboardNavigationCluster() { 10108 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 10109 } 10110 10111 /** 10112 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 10113 * will be ignored. 10114 * 10115 * @return the keyboard navigation cluster that this view is in (can be this view) 10116 * or {@code null} if not in one 10117 */ 10118 View findKeyboardNavigationCluster() { 10119 if (mParent instanceof View) { 10120 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 10121 if (cluster != null) { 10122 return cluster; 10123 } else if (isKeyboardNavigationCluster()) { 10124 return this; 10125 } 10126 } 10127 return null; 10128 } 10129 10130 /** 10131 * Set whether this view is a root of a keyboard navigation cluster. 10132 * 10133 * @param isCluster If true, this view is a root of a cluster. 10134 * 10135 * @attr ref android.R.styleable#View_keyboardNavigationCluster 10136 */ 10137 public void setKeyboardNavigationCluster(boolean isCluster) { 10138 if (isCluster) { 10139 mPrivateFlags3 |= PFLAG3_CLUSTER; 10140 } else { 10141 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 10142 } 10143 } 10144 10145 /** 10146 * Sets this View as the one which receives focus the next time cluster navigation jumps 10147 * to the cluster containing this View. This does NOT change focus even if the cluster 10148 * containing this view is current. 10149 * 10150 * @hide 10151 */ 10152 public final void setFocusedInCluster() { 10153 setFocusedInCluster(findKeyboardNavigationCluster()); 10154 } 10155 10156 private void setFocusedInCluster(View cluster) { 10157 if (this instanceof ViewGroup) { 10158 ((ViewGroup) this).mFocusedInCluster = null; 10159 } 10160 if (cluster == this) { 10161 return; 10162 } 10163 ViewParent parent = mParent; 10164 View child = this; 10165 while (parent instanceof ViewGroup) { 10166 ((ViewGroup) parent).mFocusedInCluster = child; 10167 if (parent == cluster) { 10168 break; 10169 } 10170 child = (View) parent; 10171 parent = parent.getParent(); 10172 } 10173 } 10174 10175 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 10176 if (oldFocus != null) { 10177 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 10178 View cluster = findKeyboardNavigationCluster(); 10179 if (oldCluster != cluster) { 10180 // Going from one cluster to another, so save last-focused. 10181 // This covers cluster jumps because they are always FOCUS_DOWN 10182 oldFocus.setFocusedInCluster(oldCluster); 10183 if (!(oldFocus.mParent instanceof ViewGroup)) { 10184 return; 10185 } 10186 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 10187 // This is a result of ordered navigation so consider navigation through 10188 // the previous cluster "complete" and clear its last-focused memory. 10189 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 10190 } else if (oldFocus instanceof ViewGroup 10191 && ((ViewGroup) oldFocus).getDescendantFocusability() 10192 == ViewGroup.FOCUS_AFTER_DESCENDANTS 10193 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 10194 // This means oldFocus is not focusable since it obviously has a focusable 10195 // child (this). Don't restore focus to it in the future. 10196 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 10197 } 10198 } 10199 } 10200 } 10201 10202 /** 10203 * Returns whether this View should receive focus when the focus is restored for the view 10204 * hierarchy containing this view. 10205 * <p> 10206 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 10207 * window or serves as a target of cluster navigation. 10208 * 10209 * @see #restoreDefaultFocus() 10210 * 10211 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 10212 * @attr ref android.R.styleable#View_focusedByDefault 10213 */ 10214 @ViewDebug.ExportedProperty(category = "focus") 10215 public final boolean isFocusedByDefault() { 10216 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 10217 } 10218 10219 /** 10220 * Sets whether this View should receive focus when the focus is restored for the view 10221 * hierarchy containing this view. 10222 * <p> 10223 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 10224 * window or serves as a target of cluster navigation. 10225 * 10226 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 10227 * {@code false} otherwise. 10228 * 10229 * @see #restoreDefaultFocus() 10230 * 10231 * @attr ref android.R.styleable#View_focusedByDefault 10232 */ 10233 public void setFocusedByDefault(boolean isFocusedByDefault) { 10234 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 10235 return; 10236 } 10237 10238 if (isFocusedByDefault) { 10239 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 10240 } else { 10241 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 10242 } 10243 10244 if (mParent instanceof ViewGroup) { 10245 if (isFocusedByDefault) { 10246 ((ViewGroup) mParent).setDefaultFocus(this); 10247 } else { 10248 ((ViewGroup) mParent).clearDefaultFocus(this); 10249 } 10250 } 10251 } 10252 10253 /** 10254 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 10255 * 10256 * @return {@code true} if this view has default focus, {@code false} otherwise 10257 */ 10258 boolean hasDefaultFocus() { 10259 return isFocusedByDefault(); 10260 } 10261 10262 /** 10263 * Find the nearest keyboard navigation cluster in the specified direction. 10264 * This does not actually give focus to that cluster. 10265 * 10266 * @param currentCluster The starting point of the search. Null means the current cluster is not 10267 * found yet 10268 * @param direction Direction to look 10269 * 10270 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 10271 * can be found 10272 */ 10273 public View keyboardNavigationClusterSearch(View currentCluster, 10274 @FocusDirection int direction) { 10275 if (isKeyboardNavigationCluster()) { 10276 currentCluster = this; 10277 } 10278 if (isRootNamespace()) { 10279 // Root namespace means we should consider ourselves the top of the 10280 // tree for group searching; otherwise we could be group searching 10281 // into other tabs. see LocalActivityManager and TabHost for more info. 10282 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 10283 this, currentCluster, direction); 10284 } else if (mParent != null) { 10285 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 10286 } 10287 return null; 10288 } 10289 10290 /** 10291 * This method is the last chance for the focused view and its ancestors to 10292 * respond to an arrow key. This is called when the focused view did not 10293 * consume the key internally, nor could the view system find a new view in 10294 * the requested direction to give focus to. 10295 * 10296 * @param focused The currently focused view. 10297 * @param direction The direction focus wants to move. One of FOCUS_UP, 10298 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 10299 * @return True if the this view consumed this unhandled move. 10300 */ 10301 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 10302 return false; 10303 } 10304 10305 /** 10306 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 10307 * have {@link android.R.attr#state_focused} defined in its background. 10308 * 10309 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 10310 * highlight, {@code false} otherwise. 10311 * 10312 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 10313 */ 10314 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 10315 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 10316 } 10317 10318 /** 10319 10320 /** 10321 * Returns whether this View should use a default focus highlight when it gets focused but 10322 * doesn't have {@link android.R.attr#state_focused} defined in its background. 10323 * 10324 * @return True if this View should use a default focus highlight. 10325 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 10326 */ 10327 @ViewDebug.ExportedProperty(category = "focus") 10328 public final boolean getDefaultFocusHighlightEnabled() { 10329 return mDefaultFocusHighlightEnabled; 10330 } 10331 10332 /** 10333 * If a user manually specified the next view id for a particular direction, 10334 * use the root to look up the view. 10335 * @param root The root view of the hierarchy containing this view. 10336 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 10337 * or FOCUS_BACKWARD. 10338 * @return The user specified next view, or null if there is none. 10339 */ 10340 View findUserSetNextFocus(View root, @FocusDirection int direction) { 10341 switch (direction) { 10342 case FOCUS_LEFT: 10343 if (mNextFocusLeftId == View.NO_ID) return null; 10344 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 10345 case FOCUS_RIGHT: 10346 if (mNextFocusRightId == View.NO_ID) return null; 10347 return findViewInsideOutShouldExist(root, mNextFocusRightId); 10348 case FOCUS_UP: 10349 if (mNextFocusUpId == View.NO_ID) return null; 10350 return findViewInsideOutShouldExist(root, mNextFocusUpId); 10351 case FOCUS_DOWN: 10352 if (mNextFocusDownId == View.NO_ID) return null; 10353 return findViewInsideOutShouldExist(root, mNextFocusDownId); 10354 case FOCUS_FORWARD: 10355 if (mNextFocusForwardId == View.NO_ID) return null; 10356 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 10357 case FOCUS_BACKWARD: { 10358 if (mID == View.NO_ID) return null; 10359 final int id = mID; 10360 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 10361 @Override 10362 public boolean test(View t) { 10363 return t.mNextFocusForwardId == id; 10364 } 10365 }); 10366 } 10367 } 10368 return null; 10369 } 10370 10371 /** 10372 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 10373 * use the root to look up the view. 10374 * 10375 * @param root the root view of the hierarchy containing this view 10376 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 10377 * @return the user-specified next cluster, or {@code null} if there is none 10378 */ 10379 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 10380 switch (direction) { 10381 case FOCUS_FORWARD: 10382 if (mNextClusterForwardId == View.NO_ID) return null; 10383 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 10384 case FOCUS_BACKWARD: { 10385 if (mID == View.NO_ID) return null; 10386 final int id = mID; 10387 return root.findViewByPredicateInsideOut(this, 10388 (Predicate<View>) t -> t.mNextClusterForwardId == id); 10389 } 10390 } 10391 return null; 10392 } 10393 10394 private View findViewInsideOutShouldExist(View root, int id) { 10395 if (mMatchIdPredicate == null) { 10396 mMatchIdPredicate = new MatchIdPredicate(); 10397 } 10398 mMatchIdPredicate.mId = id; 10399 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 10400 if (result == null) { 10401 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 10402 } 10403 return result; 10404 } 10405 10406 /** 10407 * Find and return all focusable views that are descendants of this view, 10408 * possibly including this view if it is focusable itself. 10409 * 10410 * @param direction The direction of the focus 10411 * @return A list of focusable views 10412 */ 10413 public ArrayList<View> getFocusables(@FocusDirection int direction) { 10414 ArrayList<View> result = new ArrayList<View>(24); 10415 addFocusables(result, direction); 10416 return result; 10417 } 10418 10419 /** 10420 * Add any focusable views that are descendants of this view (possibly 10421 * including this view if it is focusable itself) to views. If we are in touch mode, 10422 * only add views that are also focusable in touch mode. 10423 * 10424 * @param views Focusable views found so far 10425 * @param direction The direction of the focus 10426 */ 10427 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 10428 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 10429 } 10430 10431 /** 10432 * Adds any focusable views that are descendants of this view (possibly 10433 * including this view if it is focusable itself) to views. This method 10434 * adds all focusable views regardless if we are in touch mode or 10435 * only views focusable in touch mode if we are in touch mode or 10436 * only views that can take accessibility focus if accessibility is enabled 10437 * depending on the focusable mode parameter. 10438 * 10439 * @param views Focusable views found so far or null if all we are interested is 10440 * the number of focusables. 10441 * @param direction The direction of the focus. 10442 * @param focusableMode The type of focusables to be added. 10443 * 10444 * @see #FOCUSABLES_ALL 10445 * @see #FOCUSABLES_TOUCH_MODE 10446 */ 10447 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 10448 @FocusableMode int focusableMode) { 10449 if (views == null) { 10450 return; 10451 } 10452 if (!isFocusable()) { 10453 return; 10454 } 10455 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 10456 && !isFocusableInTouchMode()) { 10457 return; 10458 } 10459 views.add(this); 10460 } 10461 10462 /** 10463 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 10464 * including this view if it is a cluster root itself) to views. 10465 * 10466 * @param views Keyboard navigation cluster roots found so far 10467 * @param direction Direction to look 10468 */ 10469 public void addKeyboardNavigationClusters( 10470 @NonNull Collection<View> views, 10471 int direction) { 10472 if (!isKeyboardNavigationCluster()) { 10473 return; 10474 } 10475 if (!hasFocusable()) { 10476 return; 10477 } 10478 views.add(this); 10479 } 10480 10481 /** 10482 * Finds the Views that contain given text. The containment is case insensitive. 10483 * The search is performed by either the text that the View renders or the content 10484 * description that describes the view for accessibility purposes and the view does 10485 * not render or both. Clients can specify how the search is to be performed via 10486 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 10487 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 10488 * 10489 * @param outViews The output list of matching Views. 10490 * @param searched The text to match against. 10491 * 10492 * @see #FIND_VIEWS_WITH_TEXT 10493 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 10494 * @see #setContentDescription(CharSequence) 10495 */ 10496 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 10497 @FindViewFlags int flags) { 10498 if (getAccessibilityNodeProvider() != null) { 10499 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 10500 outViews.add(this); 10501 } 10502 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 10503 && (searched != null && searched.length() > 0) 10504 && (mContentDescription != null && mContentDescription.length() > 0)) { 10505 String searchedLowerCase = searched.toString().toLowerCase(); 10506 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 10507 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 10508 outViews.add(this); 10509 } 10510 } 10511 } 10512 10513 /** 10514 * Find and return all touchable views that are descendants of this view, 10515 * possibly including this view if it is touchable itself. 10516 * 10517 * @return A list of touchable views 10518 */ 10519 public ArrayList<View> getTouchables() { 10520 ArrayList<View> result = new ArrayList<View>(); 10521 addTouchables(result); 10522 return result; 10523 } 10524 10525 /** 10526 * Add any touchable views that are descendants of this view (possibly 10527 * including this view if it is touchable itself) to views. 10528 * 10529 * @param views Touchable views found so far 10530 */ 10531 public void addTouchables(ArrayList<View> views) { 10532 final int viewFlags = mViewFlags; 10533 10534 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 10535 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 10536 && (viewFlags & ENABLED_MASK) == ENABLED) { 10537 views.add(this); 10538 } 10539 } 10540 10541 /** 10542 * Returns whether this View is accessibility focused. 10543 * 10544 * @return True if this View is accessibility focused. 10545 */ 10546 public boolean isAccessibilityFocused() { 10547 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 10548 } 10549 10550 /** 10551 * Call this to try to give accessibility focus to this view. 10552 * 10553 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 10554 * returns false or the view is no visible or the view already has accessibility 10555 * focus. 10556 * 10557 * See also {@link #focusSearch(int)}, which is what you call to say that you 10558 * have focus, and you want your parent to look for the next one. 10559 * 10560 * @return Whether this view actually took accessibility focus. 10561 * 10562 * @hide 10563 */ 10564 public boolean requestAccessibilityFocus() { 10565 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 10566 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 10567 return false; 10568 } 10569 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10570 return false; 10571 } 10572 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 10573 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 10574 ViewRootImpl viewRootImpl = getViewRootImpl(); 10575 if (viewRootImpl != null) { 10576 viewRootImpl.setAccessibilityFocus(this, null); 10577 } 10578 invalidate(); 10579 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 10580 return true; 10581 } 10582 return false; 10583 } 10584 10585 /** 10586 * Call this to try to clear accessibility focus of this view. 10587 * 10588 * See also {@link #focusSearch(int)}, which is what you call to say that you 10589 * have focus, and you want your parent to look for the next one. 10590 * 10591 * @hide 10592 */ 10593 public void clearAccessibilityFocus() { 10594 clearAccessibilityFocusNoCallbacks(0); 10595 10596 // Clear the global reference of accessibility focus if this view or 10597 // any of its descendants had accessibility focus. This will NOT send 10598 // an event or update internal state if focus is cleared from a 10599 // descendant view, which may leave views in inconsistent states. 10600 final ViewRootImpl viewRootImpl = getViewRootImpl(); 10601 if (viewRootImpl != null) { 10602 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 10603 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 10604 viewRootImpl.setAccessibilityFocus(null, null); 10605 } 10606 } 10607 } 10608 10609 private void sendAccessibilityHoverEvent(int eventType) { 10610 // Since we are not delivering to a client accessibility events from not 10611 // important views (unless the clinet request that) we need to fire the 10612 // event from the deepest view exposed to the client. As a consequence if 10613 // the user crosses a not exposed view the client will see enter and exit 10614 // of the exposed predecessor followed by and enter and exit of that same 10615 // predecessor when entering and exiting the not exposed descendant. This 10616 // is fine since the client has a clear idea which view is hovered at the 10617 // price of a couple more events being sent. This is a simple and 10618 // working solution. 10619 View source = this; 10620 while (true) { 10621 if (source.includeForAccessibility()) { 10622 source.sendAccessibilityEvent(eventType); 10623 return; 10624 } 10625 ViewParent parent = source.getParent(); 10626 if (parent instanceof View) { 10627 source = (View) parent; 10628 } else { 10629 return; 10630 } 10631 } 10632 } 10633 10634 /** 10635 * Clears accessibility focus without calling any callback methods 10636 * normally invoked in {@link #clearAccessibilityFocus()}. This method 10637 * is used separately from that one for clearing accessibility focus when 10638 * giving this focus to another view. 10639 * 10640 * @param action The action, if any, that led to focus being cleared. Set to 10641 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 10642 * the window. 10643 */ 10644 void clearAccessibilityFocusNoCallbacks(int action) { 10645 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 10646 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 10647 invalidate(); 10648 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 10649 AccessibilityEvent event = AccessibilityEvent.obtain( 10650 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 10651 event.setAction(action); 10652 if (mAccessibilityDelegate != null) { 10653 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 10654 } else { 10655 sendAccessibilityEventUnchecked(event); 10656 } 10657 } 10658 } 10659 } 10660 10661 /** 10662 * Call this to try to give focus to a specific view or to one of its 10663 * descendants. 10664 * 10665 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10666 * false), or if it is focusable and it is not focusable in touch mode 10667 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10668 * 10669 * See also {@link #focusSearch(int)}, which is what you call to say that you 10670 * have focus, and you want your parent to look for the next one. 10671 * 10672 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 10673 * {@link #FOCUS_DOWN} and <code>null</code>. 10674 * 10675 * @return Whether this view or one of its descendants actually took focus. 10676 */ 10677 public final boolean requestFocus() { 10678 return requestFocus(View.FOCUS_DOWN); 10679 } 10680 10681 /** 10682 * This will request focus for whichever View was last focused within this 10683 * cluster before a focus-jump out of it. 10684 * 10685 * @hide 10686 */ 10687 @TestApi 10688 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 10689 // Prioritize focusableByDefault over algorithmic focus selection. 10690 if (restoreDefaultFocus()) { 10691 return true; 10692 } 10693 return requestFocus(direction); 10694 } 10695 10696 /** 10697 * This will request focus for whichever View not in a cluster was last focused before a 10698 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 10699 * the "first" focusable view it finds. 10700 * 10701 * @hide 10702 */ 10703 @TestApi 10704 public boolean restoreFocusNotInCluster() { 10705 return requestFocus(View.FOCUS_DOWN); 10706 } 10707 10708 /** 10709 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 10710 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 10711 * 10712 * @return Whether this view or one of its descendants actually took focus 10713 */ 10714 public boolean restoreDefaultFocus() { 10715 return requestFocus(View.FOCUS_DOWN); 10716 } 10717 10718 /** 10719 * Call this to try to give focus to a specific view or to one of its 10720 * descendants and give it a hint about what direction focus is heading. 10721 * 10722 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10723 * false), or if it is focusable and it is not focusable in touch mode 10724 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10725 * 10726 * See also {@link #focusSearch(int)}, which is what you call to say that you 10727 * have focus, and you want your parent to look for the next one. 10728 * 10729 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 10730 * <code>null</code> set for the previously focused rectangle. 10731 * 10732 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10733 * @return Whether this view or one of its descendants actually took focus. 10734 */ 10735 public final boolean requestFocus(int direction) { 10736 return requestFocus(direction, null); 10737 } 10738 10739 /** 10740 * Call this to try to give focus to a specific view or to one of its descendants 10741 * and give it hints about the direction and a specific rectangle that the focus 10742 * is coming from. The rectangle can help give larger views a finer grained hint 10743 * about where focus is coming from, and therefore, where to show selection, or 10744 * forward focus change internally. 10745 * 10746 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10747 * false), or if it is focusable and it is not focusable in touch mode 10748 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10749 * 10750 * A View will not take focus if it is not visible. 10751 * 10752 * A View will not take focus if one of its parents has 10753 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 10754 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 10755 * 10756 * See also {@link #focusSearch(int)}, which is what you call to say that you 10757 * have focus, and you want your parent to look for the next one. 10758 * 10759 * You may wish to override this method if your custom {@link View} has an internal 10760 * {@link View} that it wishes to forward the request to. 10761 * 10762 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10763 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 10764 * to give a finer grained hint about where focus is coming from. May be null 10765 * if there is no hint. 10766 * @return Whether this view or one of its descendants actually took focus. 10767 */ 10768 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 10769 return requestFocusNoSearch(direction, previouslyFocusedRect); 10770 } 10771 10772 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 10773 // need to be focusable 10774 if ((mViewFlags & FOCUSABLE) != FOCUSABLE 10775 || (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10776 return false; 10777 } 10778 10779 // need to be focusable in touch mode if in touch mode 10780 if (isInTouchMode() && 10781 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 10782 return false; 10783 } 10784 10785 // need to not have any parents blocking us 10786 if (hasAncestorThatBlocksDescendantFocus()) { 10787 return false; 10788 } 10789 10790 handleFocusGainInternal(direction, previouslyFocusedRect); 10791 return true; 10792 } 10793 10794 /** 10795 * Call this to try to give focus to a specific view or to one of its descendants. This is a 10796 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 10797 * touch mode to request focus when they are touched. 10798 * 10799 * @return Whether this view or one of its descendants actually took focus. 10800 * 10801 * @see #isInTouchMode() 10802 * 10803 */ 10804 public final boolean requestFocusFromTouch() { 10805 // Leave touch mode if we need to 10806 if (isInTouchMode()) { 10807 ViewRootImpl viewRoot = getViewRootImpl(); 10808 if (viewRoot != null) { 10809 viewRoot.ensureTouchMode(false); 10810 } 10811 } 10812 return requestFocus(View.FOCUS_DOWN); 10813 } 10814 10815 /** 10816 * @return Whether any ancestor of this view blocks descendant focus. 10817 */ 10818 private boolean hasAncestorThatBlocksDescendantFocus() { 10819 final boolean focusableInTouchMode = isFocusableInTouchMode(); 10820 ViewParent ancestor = mParent; 10821 while (ancestor instanceof ViewGroup) { 10822 final ViewGroup vgAncestor = (ViewGroup) ancestor; 10823 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 10824 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 10825 return true; 10826 } else { 10827 ancestor = vgAncestor.getParent(); 10828 } 10829 } 10830 return false; 10831 } 10832 10833 /** 10834 * Gets the mode for determining whether this View is important for accessibility. 10835 * A view is important for accessibility if it fires accessibility events and if it 10836 * is reported to accessibility services that query the screen. 10837 * 10838 * @return The mode for determining whether a view is important for accessibility, one 10839 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 10840 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 10841 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 10842 * 10843 * @attr ref android.R.styleable#View_importantForAccessibility 10844 * 10845 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10846 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10847 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10848 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10849 */ 10850 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 10851 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 10852 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 10853 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 10854 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 10855 to = "noHideDescendants") 10856 }) 10857 public int getImportantForAccessibility() { 10858 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 10859 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 10860 } 10861 10862 /** 10863 * Sets the live region mode for this view. This indicates to accessibility 10864 * services whether they should automatically notify the user about changes 10865 * to the view's content description or text, or to the content descriptions 10866 * or text of the view's children (where applicable). 10867 * <p> 10868 * For example, in a login screen with a TextView that displays an "incorrect 10869 * password" notification, that view should be marked as a live region with 10870 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10871 * <p> 10872 * To disable change notifications for this view, use 10873 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 10874 * mode for most views. 10875 * <p> 10876 * To indicate that the user should be notified of changes, use 10877 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10878 * <p> 10879 * If the view's changes should interrupt ongoing speech and notify the user 10880 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 10881 * 10882 * @param mode The live region mode for this view, one of: 10883 * <ul> 10884 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 10885 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 10886 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 10887 * </ul> 10888 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10889 */ 10890 public void setAccessibilityLiveRegion(int mode) { 10891 if (mode != getAccessibilityLiveRegion()) { 10892 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10893 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 10894 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10895 notifyViewAccessibilityStateChangedIfNeeded( 10896 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10897 } 10898 } 10899 10900 /** 10901 * Gets the live region mode for this View. 10902 * 10903 * @return The live region mode for the view. 10904 * 10905 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10906 * 10907 * @see #setAccessibilityLiveRegion(int) 10908 */ 10909 public int getAccessibilityLiveRegion() { 10910 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 10911 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 10912 } 10913 10914 /** 10915 * Sets how to determine whether this view is important for accessibility 10916 * which is if it fires accessibility events and if it is reported to 10917 * accessibility services that query the screen. 10918 * 10919 * @param mode How to determine whether this view is important for accessibility. 10920 * 10921 * @attr ref android.R.styleable#View_importantForAccessibility 10922 * 10923 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10924 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10925 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10926 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10927 */ 10928 public void setImportantForAccessibility(int mode) { 10929 final int oldMode = getImportantForAccessibility(); 10930 if (mode != oldMode) { 10931 final boolean hideDescendants = 10932 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 10933 10934 // If this node or its descendants are no longer important, try to 10935 // clear accessibility focus. 10936 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 10937 final View focusHost = findAccessibilityFocusHost(hideDescendants); 10938 if (focusHost != null) { 10939 focusHost.clearAccessibilityFocus(); 10940 } 10941 } 10942 10943 // If we're moving between AUTO and another state, we might not need 10944 // to send a subtree changed notification. We'll store the computed 10945 // importance, since we'll need to check it later to make sure. 10946 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 10947 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 10948 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 10949 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 10950 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 10951 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 10952 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 10953 notifySubtreeAccessibilityStateChangedIfNeeded(); 10954 } else { 10955 notifyViewAccessibilityStateChangedIfNeeded( 10956 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10957 } 10958 } 10959 } 10960 10961 /** 10962 * Returns the view within this view's hierarchy that is hosting 10963 * accessibility focus. 10964 * 10965 * @param searchDescendants whether to search for focus in descendant views 10966 * @return the view hosting accessibility focus, or {@code null} 10967 */ 10968 private View findAccessibilityFocusHost(boolean searchDescendants) { 10969 if (isAccessibilityFocusedViewOrHost()) { 10970 return this; 10971 } 10972 10973 if (searchDescendants) { 10974 final ViewRootImpl viewRoot = getViewRootImpl(); 10975 if (viewRoot != null) { 10976 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 10977 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 10978 return focusHost; 10979 } 10980 } 10981 } 10982 10983 return null; 10984 } 10985 10986 /** 10987 * Computes whether this view should be exposed for accessibility. In 10988 * general, views that are interactive or provide information are exposed 10989 * while views that serve only as containers are hidden. 10990 * <p> 10991 * If an ancestor of this view has importance 10992 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 10993 * returns <code>false</code>. 10994 * <p> 10995 * Otherwise, the value is computed according to the view's 10996 * {@link #getImportantForAccessibility()} value: 10997 * <ol> 10998 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 10999 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 11000 * </code> 11001 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 11002 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 11003 * view satisfies any of the following: 11004 * <ul> 11005 * <li>Is actionable, e.g. {@link #isClickable()}, 11006 * {@link #isLongClickable()}, or {@link #isFocusable()} 11007 * <li>Has an {@link AccessibilityDelegate} 11008 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 11009 * {@link OnKeyListener}, etc. 11010 * <li>Is an accessibility live region, e.g. 11011 * {@link #getAccessibilityLiveRegion()} is not 11012 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 11013 * </ul> 11014 * </ol> 11015 * 11016 * @return Whether the view is exposed for accessibility. 11017 * @see #setImportantForAccessibility(int) 11018 * @see #getImportantForAccessibility() 11019 */ 11020 public boolean isImportantForAccessibility() { 11021 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 11022 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 11023 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 11024 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 11025 return false; 11026 } 11027 11028 // Check parent mode to ensure we're not hidden. 11029 ViewParent parent = mParent; 11030 while (parent instanceof View) { 11031 if (((View) parent).getImportantForAccessibility() 11032 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 11033 return false; 11034 } 11035 parent = parent.getParent(); 11036 } 11037 11038 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 11039 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 11040 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 11041 } 11042 11043 /** 11044 * Gets the parent for accessibility purposes. Note that the parent for 11045 * accessibility is not necessary the immediate parent. It is the first 11046 * predecessor that is important for accessibility. 11047 * 11048 * @return The parent for accessibility purposes. 11049 */ 11050 public ViewParent getParentForAccessibility() { 11051 if (mParent instanceof View) { 11052 View parentView = (View) mParent; 11053 if (parentView.includeForAccessibility()) { 11054 return mParent; 11055 } else { 11056 return mParent.getParentForAccessibility(); 11057 } 11058 } 11059 return null; 11060 } 11061 11062 /** 11063 * Adds the children of this View relevant for accessibility to the given list 11064 * as output. Since some Views are not important for accessibility the added 11065 * child views are not necessarily direct children of this view, rather they are 11066 * the first level of descendants important for accessibility. 11067 * 11068 * @param outChildren The output list that will receive children for accessibility. 11069 */ 11070 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 11071 11072 } 11073 11074 /** 11075 * Whether to regard this view for accessibility. A view is regarded for 11076 * accessibility if it is important for accessibility or the querying 11077 * accessibility service has explicitly requested that view not 11078 * important for accessibility are regarded. 11079 * 11080 * @return Whether to regard the view for accessibility. 11081 * 11082 * @hide 11083 */ 11084 public boolean includeForAccessibility() { 11085 if (mAttachInfo != null) { 11086 return (mAttachInfo.mAccessibilityFetchFlags 11087 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 11088 || isImportantForAccessibility(); 11089 } 11090 return false; 11091 } 11092 11093 /** 11094 * Returns whether the View is considered actionable from 11095 * accessibility perspective. Such view are important for 11096 * accessibility. 11097 * 11098 * @return True if the view is actionable for accessibility. 11099 * 11100 * @hide 11101 */ 11102 public boolean isActionableForAccessibility() { 11103 return (isClickable() || isLongClickable() || isFocusable()); 11104 } 11105 11106 /** 11107 * Returns whether the View has registered callbacks which makes it 11108 * important for accessibility. 11109 * 11110 * @return True if the view is actionable for accessibility. 11111 */ 11112 private boolean hasListenersForAccessibility() { 11113 ListenerInfo info = getListenerInfo(); 11114 return mTouchDelegate != null || info.mOnKeyListener != null 11115 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 11116 || info.mOnHoverListener != null || info.mOnDragListener != null; 11117 } 11118 11119 /** 11120 * Notifies that the accessibility state of this view changed. The change 11121 * is local to this view and does not represent structural changes such 11122 * as children and parent. For example, the view became focusable. The 11123 * notification is at at most once every 11124 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 11125 * to avoid unnecessary load to the system. Also once a view has a pending 11126 * notification this method is a NOP until the notification has been sent. 11127 * 11128 * @hide 11129 */ 11130 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 11131 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 11132 return; 11133 } 11134 if (mSendViewStateChangedAccessibilityEvent == null) { 11135 mSendViewStateChangedAccessibilityEvent = 11136 new SendViewStateChangedAccessibilityEvent(); 11137 } 11138 mSendViewStateChangedAccessibilityEvent.runOrPost(changeType); 11139 } 11140 11141 /** 11142 * Notifies that the accessibility state of this view changed. The change 11143 * is *not* local to this view and does represent structural changes such 11144 * as children and parent. For example, the view size changed. The 11145 * notification is at at most once every 11146 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 11147 * to avoid unnecessary load to the system. Also once a view has a pending 11148 * notification this method is a NOP until the notification has been sent. 11149 * 11150 * @hide 11151 */ 11152 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 11153 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 11154 return; 11155 } 11156 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 11157 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 11158 if (mParent != null) { 11159 try { 11160 mParent.notifySubtreeAccessibilityStateChanged( 11161 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 11162 } catch (AbstractMethodError e) { 11163 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11164 " does not fully implement ViewParent", e); 11165 } 11166 } 11167 } 11168 } 11169 11170 /** 11171 * Change the visibility of the View without triggering any other changes. This is 11172 * important for transitions, where visibility changes should not adjust focus or 11173 * trigger a new layout. This is only used when the visibility has already been changed 11174 * and we need a transient value during an animation. When the animation completes, 11175 * the original visibility value is always restored. 11176 * 11177 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11178 * @hide 11179 */ 11180 public void setTransitionVisibility(@Visibility int visibility) { 11181 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 11182 } 11183 11184 /** 11185 * Reset the flag indicating the accessibility state of the subtree rooted 11186 * at this view changed. 11187 */ 11188 void resetSubtreeAccessibilityStateChanged() { 11189 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 11190 } 11191 11192 /** 11193 * Report an accessibility action to this view's parents for delegated processing. 11194 * 11195 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 11196 * call this method to delegate an accessibility action to a supporting parent. If the parent 11197 * returns true from its 11198 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 11199 * method this method will return true to signify that the action was consumed.</p> 11200 * 11201 * <p>This method is useful for implementing nested scrolling child views. If 11202 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 11203 * a custom view implementation may invoke this method to allow a parent to consume the 11204 * scroll first. If this method returns true the custom view should skip its own scrolling 11205 * behavior.</p> 11206 * 11207 * @param action Accessibility action to delegate 11208 * @param arguments Optional action arguments 11209 * @return true if the action was consumed by a parent 11210 */ 11211 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 11212 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 11213 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 11214 return true; 11215 } 11216 } 11217 return false; 11218 } 11219 11220 /** 11221 * Performs the specified accessibility action on the view. For 11222 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 11223 * <p> 11224 * If an {@link AccessibilityDelegate} has been specified via calling 11225 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 11226 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 11227 * is responsible for handling this call. 11228 * </p> 11229 * 11230 * <p>The default implementation will delegate 11231 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 11232 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 11233 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 11234 * 11235 * @param action The action to perform. 11236 * @param arguments Optional action arguments. 11237 * @return Whether the action was performed. 11238 */ 11239 public boolean performAccessibilityAction(int action, Bundle arguments) { 11240 if (mAccessibilityDelegate != null) { 11241 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 11242 } else { 11243 return performAccessibilityActionInternal(action, arguments); 11244 } 11245 } 11246 11247 /** 11248 * @see #performAccessibilityAction(int, Bundle) 11249 * 11250 * Note: Called from the default {@link AccessibilityDelegate}. 11251 * 11252 * @hide 11253 */ 11254 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 11255 if (isNestedScrollingEnabled() 11256 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 11257 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 11258 || action == R.id.accessibilityActionScrollUp 11259 || action == R.id.accessibilityActionScrollLeft 11260 || action == R.id.accessibilityActionScrollDown 11261 || action == R.id.accessibilityActionScrollRight)) { 11262 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 11263 return true; 11264 } 11265 } 11266 11267 switch (action) { 11268 case AccessibilityNodeInfo.ACTION_CLICK: { 11269 if (isClickable()) { 11270 performClick(); 11271 return true; 11272 } 11273 } break; 11274 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 11275 if (isLongClickable()) { 11276 performLongClick(); 11277 return true; 11278 } 11279 } break; 11280 case AccessibilityNodeInfo.ACTION_FOCUS: { 11281 if (!hasFocus()) { 11282 // Get out of touch mode since accessibility 11283 // wants to move focus around. 11284 getViewRootImpl().ensureTouchMode(false); 11285 return requestFocus(); 11286 } 11287 } break; 11288 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 11289 if (hasFocus()) { 11290 clearFocus(); 11291 return !isFocused(); 11292 } 11293 } break; 11294 case AccessibilityNodeInfo.ACTION_SELECT: { 11295 if (!isSelected()) { 11296 setSelected(true); 11297 return isSelected(); 11298 } 11299 } break; 11300 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 11301 if (isSelected()) { 11302 setSelected(false); 11303 return !isSelected(); 11304 } 11305 } break; 11306 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 11307 if (!isAccessibilityFocused()) { 11308 return requestAccessibilityFocus(); 11309 } 11310 } break; 11311 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 11312 if (isAccessibilityFocused()) { 11313 clearAccessibilityFocus(); 11314 return true; 11315 } 11316 } break; 11317 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 11318 if (arguments != null) { 11319 final int granularity = arguments.getInt( 11320 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 11321 final boolean extendSelection = arguments.getBoolean( 11322 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 11323 return traverseAtGranularity(granularity, true, extendSelection); 11324 } 11325 } break; 11326 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 11327 if (arguments != null) { 11328 final int granularity = arguments.getInt( 11329 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 11330 final boolean extendSelection = arguments.getBoolean( 11331 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 11332 return traverseAtGranularity(granularity, false, extendSelection); 11333 } 11334 } break; 11335 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 11336 CharSequence text = getIterableTextForAccessibility(); 11337 if (text == null) { 11338 return false; 11339 } 11340 final int start = (arguments != null) ? arguments.getInt( 11341 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 11342 final int end = (arguments != null) ? arguments.getInt( 11343 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 11344 // Only cursor position can be specified (selection length == 0) 11345 if ((getAccessibilitySelectionStart() != start 11346 || getAccessibilitySelectionEnd() != end) 11347 && (start == end)) { 11348 setAccessibilitySelection(start, end); 11349 notifyViewAccessibilityStateChangedIfNeeded( 11350 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11351 return true; 11352 } 11353 } break; 11354 case R.id.accessibilityActionShowOnScreen: { 11355 if (mAttachInfo != null) { 11356 final Rect r = mAttachInfo.mTmpInvalRect; 11357 getDrawingRect(r); 11358 return requestRectangleOnScreen(r, true); 11359 } 11360 } break; 11361 case R.id.accessibilityActionContextClick: { 11362 if (isContextClickable()) { 11363 performContextClick(); 11364 return true; 11365 } 11366 } break; 11367 } 11368 return false; 11369 } 11370 11371 private boolean traverseAtGranularity(int granularity, boolean forward, 11372 boolean extendSelection) { 11373 CharSequence text = getIterableTextForAccessibility(); 11374 if (text == null || text.length() == 0) { 11375 return false; 11376 } 11377 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 11378 if (iterator == null) { 11379 return false; 11380 } 11381 int current = getAccessibilitySelectionEnd(); 11382 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 11383 current = forward ? 0 : text.length(); 11384 } 11385 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 11386 if (range == null) { 11387 return false; 11388 } 11389 final int segmentStart = range[0]; 11390 final int segmentEnd = range[1]; 11391 int selectionStart; 11392 int selectionEnd; 11393 if (extendSelection && isAccessibilitySelectionExtendable()) { 11394 selectionStart = getAccessibilitySelectionStart(); 11395 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 11396 selectionStart = forward ? segmentStart : segmentEnd; 11397 } 11398 selectionEnd = forward ? segmentEnd : segmentStart; 11399 } else { 11400 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 11401 } 11402 setAccessibilitySelection(selectionStart, selectionEnd); 11403 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 11404 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 11405 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 11406 return true; 11407 } 11408 11409 /** 11410 * Gets the text reported for accessibility purposes. 11411 * 11412 * @return The accessibility text. 11413 * 11414 * @hide 11415 */ 11416 public CharSequence getIterableTextForAccessibility() { 11417 return getContentDescription(); 11418 } 11419 11420 /** 11421 * Gets whether accessibility selection can be extended. 11422 * 11423 * @return If selection is extensible. 11424 * 11425 * @hide 11426 */ 11427 public boolean isAccessibilitySelectionExtendable() { 11428 return false; 11429 } 11430 11431 /** 11432 * @hide 11433 */ 11434 public int getAccessibilitySelectionStart() { 11435 return mAccessibilityCursorPosition; 11436 } 11437 11438 /** 11439 * @hide 11440 */ 11441 public int getAccessibilitySelectionEnd() { 11442 return getAccessibilitySelectionStart(); 11443 } 11444 11445 /** 11446 * @hide 11447 */ 11448 public void setAccessibilitySelection(int start, int end) { 11449 if (start == end && end == mAccessibilityCursorPosition) { 11450 return; 11451 } 11452 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 11453 mAccessibilityCursorPosition = start; 11454 } else { 11455 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 11456 } 11457 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 11458 } 11459 11460 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 11461 int fromIndex, int toIndex) { 11462 if (mParent == null) { 11463 return; 11464 } 11465 AccessibilityEvent event = AccessibilityEvent.obtain( 11466 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 11467 onInitializeAccessibilityEvent(event); 11468 onPopulateAccessibilityEvent(event); 11469 event.setFromIndex(fromIndex); 11470 event.setToIndex(toIndex); 11471 event.setAction(action); 11472 event.setMovementGranularity(granularity); 11473 mParent.requestSendAccessibilityEvent(this, event); 11474 } 11475 11476 /** 11477 * @hide 11478 */ 11479 public TextSegmentIterator getIteratorForGranularity(int granularity) { 11480 switch (granularity) { 11481 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 11482 CharSequence text = getIterableTextForAccessibility(); 11483 if (text != null && text.length() > 0) { 11484 CharacterTextSegmentIterator iterator = 11485 CharacterTextSegmentIterator.getInstance( 11486 mContext.getResources().getConfiguration().locale); 11487 iterator.initialize(text.toString()); 11488 return iterator; 11489 } 11490 } break; 11491 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 11492 CharSequence text = getIterableTextForAccessibility(); 11493 if (text != null && text.length() > 0) { 11494 WordTextSegmentIterator iterator = 11495 WordTextSegmentIterator.getInstance( 11496 mContext.getResources().getConfiguration().locale); 11497 iterator.initialize(text.toString()); 11498 return iterator; 11499 } 11500 } break; 11501 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 11502 CharSequence text = getIterableTextForAccessibility(); 11503 if (text != null && text.length() > 0) { 11504 ParagraphTextSegmentIterator iterator = 11505 ParagraphTextSegmentIterator.getInstance(); 11506 iterator.initialize(text.toString()); 11507 return iterator; 11508 } 11509 } break; 11510 } 11511 return null; 11512 } 11513 11514 /** 11515 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 11516 * and {@link #onFinishTemporaryDetach()}. 11517 * 11518 * <p>This method always returns {@code true} when called directly or indirectly from 11519 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 11520 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 11521 * <ul> 11522 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 11523 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 11524 * </ul> 11525 * </p> 11526 * 11527 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 11528 * and {@link #onFinishTemporaryDetach()}. 11529 */ 11530 public final boolean isTemporarilyDetached() { 11531 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 11532 } 11533 11534 /** 11535 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 11536 * a container View. 11537 */ 11538 @CallSuper 11539 public void dispatchStartTemporaryDetach() { 11540 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 11541 notifyEnterOrExitForAutoFillIfNeeded(false); 11542 onStartTemporaryDetach(); 11543 } 11544 11545 /** 11546 * This is called when a container is going to temporarily detach a child, with 11547 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 11548 * It will either be followed by {@link #onFinishTemporaryDetach()} or 11549 * {@link #onDetachedFromWindow()} when the container is done. 11550 */ 11551 public void onStartTemporaryDetach() { 11552 removeUnsetPressCallback(); 11553 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 11554 } 11555 11556 /** 11557 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 11558 * a container View. 11559 */ 11560 @CallSuper 11561 public void dispatchFinishTemporaryDetach() { 11562 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 11563 onFinishTemporaryDetach(); 11564 if (hasWindowFocus() && hasFocus()) { 11565 InputMethodManager.getInstance().focusIn(this); 11566 } 11567 notifyEnterOrExitForAutoFillIfNeeded(true); 11568 } 11569 11570 /** 11571 * Called after {@link #onStartTemporaryDetach} when the container is done 11572 * changing the view. 11573 */ 11574 public void onFinishTemporaryDetach() { 11575 } 11576 11577 /** 11578 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 11579 * for this view's window. Returns null if the view is not currently attached 11580 * to the window. Normally you will not need to use this directly, but 11581 * just use the standard high-level event callbacks like 11582 * {@link #onKeyDown(int, KeyEvent)}. 11583 */ 11584 public KeyEvent.DispatcherState getKeyDispatcherState() { 11585 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 11586 } 11587 11588 /** 11589 * Dispatch a key event before it is processed by any input method 11590 * associated with the view hierarchy. This can be used to intercept 11591 * key events in special situations before the IME consumes them; a 11592 * typical example would be handling the BACK key to update the application's 11593 * UI instead of allowing the IME to see it and close itself. 11594 * 11595 * @param event The key event to be dispatched. 11596 * @return True if the event was handled, false otherwise. 11597 */ 11598 public boolean dispatchKeyEventPreIme(KeyEvent event) { 11599 return onKeyPreIme(event.getKeyCode(), event); 11600 } 11601 11602 /** 11603 * Dispatch a key event to the next view on the focus path. This path runs 11604 * from the top of the view tree down to the currently focused view. If this 11605 * view has focus, it will dispatch to itself. Otherwise it will dispatch 11606 * the next node down the focus path. This method also fires any key 11607 * listeners. 11608 * 11609 * @param event The key event to be dispatched. 11610 * @return True if the event was handled, false otherwise. 11611 */ 11612 public boolean dispatchKeyEvent(KeyEvent event) { 11613 if (mInputEventConsistencyVerifier != null) { 11614 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 11615 } 11616 11617 // Give any attached key listener a first crack at the event. 11618 //noinspection SimplifiableIfStatement 11619 ListenerInfo li = mListenerInfo; 11620 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 11621 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 11622 return true; 11623 } 11624 11625 if (event.dispatch(this, mAttachInfo != null 11626 ? mAttachInfo.mKeyDispatchState : null, this)) { 11627 return true; 11628 } 11629 11630 if (mInputEventConsistencyVerifier != null) { 11631 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11632 } 11633 return false; 11634 } 11635 11636 /** 11637 * Dispatches a key shortcut event. 11638 * 11639 * @param event The key event to be dispatched. 11640 * @return True if the event was handled by the view, false otherwise. 11641 */ 11642 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 11643 return onKeyShortcut(event.getKeyCode(), event); 11644 } 11645 11646 /** 11647 * Pass the touch screen motion event down to the target view, or this 11648 * view if it is the target. 11649 * 11650 * @param event The motion event to be dispatched. 11651 * @return True if the event was handled by the view, false otherwise. 11652 */ 11653 public boolean dispatchTouchEvent(MotionEvent event) { 11654 // If the event should be handled by accessibility focus first. 11655 if (event.isTargetAccessibilityFocus()) { 11656 // We don't have focus or no virtual descendant has it, do not handle the event. 11657 if (!isAccessibilityFocusedViewOrHost()) { 11658 return false; 11659 } 11660 // We have focus and got the event, then use normal event dispatch. 11661 event.setTargetAccessibilityFocus(false); 11662 } 11663 11664 boolean result = false; 11665 11666 if (mInputEventConsistencyVerifier != null) { 11667 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 11668 } 11669 11670 final int actionMasked = event.getActionMasked(); 11671 if (actionMasked == MotionEvent.ACTION_DOWN) { 11672 // Defensive cleanup for new gesture 11673 stopNestedScroll(); 11674 } 11675 11676 if (onFilterTouchEventForSecurity(event)) { 11677 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 11678 result = true; 11679 } 11680 //noinspection SimplifiableIfStatement 11681 ListenerInfo li = mListenerInfo; 11682 if (li != null && li.mOnTouchListener != null 11683 && (mViewFlags & ENABLED_MASK) == ENABLED 11684 && li.mOnTouchListener.onTouch(this, event)) { 11685 result = true; 11686 } 11687 11688 if (!result && onTouchEvent(event)) { 11689 result = true; 11690 } 11691 } 11692 11693 if (!result && mInputEventConsistencyVerifier != null) { 11694 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11695 } 11696 11697 // Clean up after nested scrolls if this is the end of a gesture; 11698 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 11699 // of the gesture. 11700 if (actionMasked == MotionEvent.ACTION_UP || 11701 actionMasked == MotionEvent.ACTION_CANCEL || 11702 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 11703 stopNestedScroll(); 11704 } 11705 11706 return result; 11707 } 11708 11709 boolean isAccessibilityFocusedViewOrHost() { 11710 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 11711 .getAccessibilityFocusedHost() == this); 11712 } 11713 11714 /** 11715 * Filter the touch event to apply security policies. 11716 * 11717 * @param event The motion event to be filtered. 11718 * @return True if the event should be dispatched, false if the event should be dropped. 11719 * 11720 * @see #getFilterTouchesWhenObscured 11721 */ 11722 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 11723 //noinspection RedundantIfStatement 11724 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 11725 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 11726 // Window is obscured, drop this touch. 11727 return false; 11728 } 11729 return true; 11730 } 11731 11732 /** 11733 * Pass a trackball motion event down to the focused view. 11734 * 11735 * @param event The motion event to be dispatched. 11736 * @return True if the event was handled by the view, false otherwise. 11737 */ 11738 public boolean dispatchTrackballEvent(MotionEvent event) { 11739 if (mInputEventConsistencyVerifier != null) { 11740 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 11741 } 11742 11743 return onTrackballEvent(event); 11744 } 11745 11746 /** 11747 * Pass a captured pointer event down to the focused view. 11748 * 11749 * @param event The motion event to be dispatched. 11750 * @return True if the event was handled by the view, false otherwise. 11751 */ 11752 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 11753 if (!hasPointerCapture()) { 11754 return false; 11755 } 11756 //noinspection SimplifiableIfStatement 11757 ListenerInfo li = mListenerInfo; 11758 if (li != null && li.mOnCapturedPointerListener != null 11759 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 11760 return true; 11761 } 11762 return onCapturedPointerEvent(event); 11763 } 11764 11765 /** 11766 * Dispatch a generic motion event. 11767 * <p> 11768 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11769 * are delivered to the view under the pointer. All other generic motion events are 11770 * delivered to the focused view. Hover events are handled specially and are delivered 11771 * to {@link #onHoverEvent(MotionEvent)}. 11772 * </p> 11773 * 11774 * @param event The motion event to be dispatched. 11775 * @return True if the event was handled by the view, false otherwise. 11776 */ 11777 public boolean dispatchGenericMotionEvent(MotionEvent event) { 11778 if (mInputEventConsistencyVerifier != null) { 11779 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 11780 } 11781 11782 final int source = event.getSource(); 11783 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 11784 final int action = event.getAction(); 11785 if (action == MotionEvent.ACTION_HOVER_ENTER 11786 || action == MotionEvent.ACTION_HOVER_MOVE 11787 || action == MotionEvent.ACTION_HOVER_EXIT) { 11788 if (dispatchHoverEvent(event)) { 11789 return true; 11790 } 11791 } else if (dispatchGenericPointerEvent(event)) { 11792 return true; 11793 } 11794 } else if (dispatchGenericFocusedEvent(event)) { 11795 return true; 11796 } 11797 11798 if (dispatchGenericMotionEventInternal(event)) { 11799 return true; 11800 } 11801 11802 if (mInputEventConsistencyVerifier != null) { 11803 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11804 } 11805 return false; 11806 } 11807 11808 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 11809 //noinspection SimplifiableIfStatement 11810 ListenerInfo li = mListenerInfo; 11811 if (li != null && li.mOnGenericMotionListener != null 11812 && (mViewFlags & ENABLED_MASK) == ENABLED 11813 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 11814 return true; 11815 } 11816 11817 if (onGenericMotionEvent(event)) { 11818 return true; 11819 } 11820 11821 final int actionButton = event.getActionButton(); 11822 switch (event.getActionMasked()) { 11823 case MotionEvent.ACTION_BUTTON_PRESS: 11824 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 11825 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11826 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11827 if (performContextClick(event.getX(), event.getY())) { 11828 mInContextButtonPress = true; 11829 setPressed(true, event.getX(), event.getY()); 11830 removeTapCallback(); 11831 removeLongPressCallback(); 11832 return true; 11833 } 11834 } 11835 break; 11836 11837 case MotionEvent.ACTION_BUTTON_RELEASE: 11838 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11839 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11840 mInContextButtonPress = false; 11841 mIgnoreNextUpEvent = true; 11842 } 11843 break; 11844 } 11845 11846 if (mInputEventConsistencyVerifier != null) { 11847 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11848 } 11849 return false; 11850 } 11851 11852 /** 11853 * Dispatch a hover event. 11854 * <p> 11855 * Do not call this method directly. 11856 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11857 * </p> 11858 * 11859 * @param event The motion event to be dispatched. 11860 * @return True if the event was handled by the view, false otherwise. 11861 */ 11862 protected boolean dispatchHoverEvent(MotionEvent event) { 11863 ListenerInfo li = mListenerInfo; 11864 //noinspection SimplifiableIfStatement 11865 if (li != null && li.mOnHoverListener != null 11866 && (mViewFlags & ENABLED_MASK) == ENABLED 11867 && li.mOnHoverListener.onHover(this, event)) { 11868 return true; 11869 } 11870 11871 return onHoverEvent(event); 11872 } 11873 11874 /** 11875 * Returns true if the view has a child to which it has recently sent 11876 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 11877 * it does not have a hovered child, then it must be the innermost hovered view. 11878 * @hide 11879 */ 11880 protected boolean hasHoveredChild() { 11881 return false; 11882 } 11883 11884 /** 11885 * Dispatch a generic motion event to the view under the first pointer. 11886 * <p> 11887 * Do not call this method directly. 11888 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11889 * </p> 11890 * 11891 * @param event The motion event to be dispatched. 11892 * @return True if the event was handled by the view, false otherwise. 11893 */ 11894 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 11895 return false; 11896 } 11897 11898 /** 11899 * Dispatch a generic motion event to the currently focused view. 11900 * <p> 11901 * Do not call this method directly. 11902 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11903 * </p> 11904 * 11905 * @param event The motion event to be dispatched. 11906 * @return True if the event was handled by the view, false otherwise. 11907 */ 11908 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 11909 return false; 11910 } 11911 11912 /** 11913 * Dispatch a pointer event. 11914 * <p> 11915 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 11916 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 11917 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 11918 * and should not be expected to handle other pointing device features. 11919 * </p> 11920 * 11921 * @param event The motion event to be dispatched. 11922 * @return True if the event was handled by the view, false otherwise. 11923 * @hide 11924 */ 11925 public final boolean dispatchPointerEvent(MotionEvent event) { 11926 if (event.isTouchEvent()) { 11927 return dispatchTouchEvent(event); 11928 } else { 11929 return dispatchGenericMotionEvent(event); 11930 } 11931 } 11932 11933 /** 11934 * Called when the window containing this view gains or loses window focus. 11935 * ViewGroups should override to route to their children. 11936 * 11937 * @param hasFocus True if the window containing this view now has focus, 11938 * false otherwise. 11939 */ 11940 public void dispatchWindowFocusChanged(boolean hasFocus) { 11941 onWindowFocusChanged(hasFocus); 11942 } 11943 11944 /** 11945 * Called when the window containing this view gains or loses focus. Note 11946 * that this is separate from view focus: to receive key events, both 11947 * your view and its window must have focus. If a window is displayed 11948 * on top of yours that takes input focus, then your own window will lose 11949 * focus but the view focus will remain unchanged. 11950 * 11951 * @param hasWindowFocus True if the window containing this view now has 11952 * focus, false otherwise. 11953 */ 11954 public void onWindowFocusChanged(boolean hasWindowFocus) { 11955 InputMethodManager imm = InputMethodManager.peekInstance(); 11956 if (!hasWindowFocus) { 11957 if (isPressed()) { 11958 setPressed(false); 11959 } 11960 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11961 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 11962 imm.focusOut(this); 11963 } 11964 removeLongPressCallback(); 11965 removeTapCallback(); 11966 onFocusLost(); 11967 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 11968 imm.focusIn(this); 11969 } 11970 11971 notifyEnterOrExitForAutoFillIfNeeded(hasWindowFocus); 11972 11973 refreshDrawableState(); 11974 } 11975 11976 /** 11977 * Returns true if this view is in a window that currently has window focus. 11978 * Note that this is not the same as the view itself having focus. 11979 * 11980 * @return True if this view is in a window that currently has window focus. 11981 */ 11982 public boolean hasWindowFocus() { 11983 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 11984 } 11985 11986 /** 11987 * Dispatch a view visibility change down the view hierarchy. 11988 * ViewGroups should override to route to their children. 11989 * @param changedView The view whose visibility changed. Could be 'this' or 11990 * an ancestor view. 11991 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 11992 * {@link #INVISIBLE} or {@link #GONE}. 11993 */ 11994 protected void dispatchVisibilityChanged(@NonNull View changedView, 11995 @Visibility int visibility) { 11996 onVisibilityChanged(changedView, visibility); 11997 } 11998 11999 /** 12000 * Called when the visibility of the view or an ancestor of the view has 12001 * changed. 12002 * 12003 * @param changedView The view whose visibility changed. May be 12004 * {@code this} or an ancestor view. 12005 * @param visibility The new visibility, one of {@link #VISIBLE}, 12006 * {@link #INVISIBLE} or {@link #GONE}. 12007 */ 12008 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 12009 } 12010 12011 /** 12012 * Dispatch a hint about whether this view is displayed. For instance, when 12013 * a View moves out of the screen, it might receives a display hint indicating 12014 * the view is not displayed. Applications should not <em>rely</em> on this hint 12015 * as there is no guarantee that they will receive one. 12016 * 12017 * @param hint A hint about whether or not this view is displayed: 12018 * {@link #VISIBLE} or {@link #INVISIBLE}. 12019 */ 12020 public void dispatchDisplayHint(@Visibility int hint) { 12021 onDisplayHint(hint); 12022 } 12023 12024 /** 12025 * Gives this view a hint about whether is displayed or not. For instance, when 12026 * a View moves out of the screen, it might receives a display hint indicating 12027 * the view is not displayed. Applications should not <em>rely</em> on this hint 12028 * as there is no guarantee that they will receive one. 12029 * 12030 * @param hint A hint about whether or not this view is displayed: 12031 * {@link #VISIBLE} or {@link #INVISIBLE}. 12032 */ 12033 protected void onDisplayHint(@Visibility int hint) { 12034 } 12035 12036 /** 12037 * Dispatch a window visibility change down the view hierarchy. 12038 * ViewGroups should override to route to their children. 12039 * 12040 * @param visibility The new visibility of the window. 12041 * 12042 * @see #onWindowVisibilityChanged(int) 12043 */ 12044 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 12045 onWindowVisibilityChanged(visibility); 12046 } 12047 12048 /** 12049 * Called when the window containing has change its visibility 12050 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 12051 * that this tells you whether or not your window is being made visible 12052 * to the window manager; this does <em>not</em> tell you whether or not 12053 * your window is obscured by other windows on the screen, even if it 12054 * is itself visible. 12055 * 12056 * @param visibility The new visibility of the window. 12057 */ 12058 protected void onWindowVisibilityChanged(@Visibility int visibility) { 12059 if (visibility == VISIBLE) { 12060 initialAwakenScrollBars(); 12061 } 12062 } 12063 12064 /** 12065 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 12066 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 12067 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 12068 * 12069 * @param isVisible true if this view's visibility to the user is uninterrupted by its 12070 * ancestors or by window visibility 12071 * @return true if this view is visible to the user, not counting clipping or overlapping 12072 */ 12073 boolean dispatchVisibilityAggregated(boolean isVisible) { 12074 final boolean thisVisible = getVisibility() == VISIBLE; 12075 // If we're not visible but something is telling us we are, ignore it. 12076 if (thisVisible || !isVisible) { 12077 onVisibilityAggregated(isVisible); 12078 } 12079 return thisVisible && isVisible; 12080 } 12081 12082 /** 12083 * Called when the user-visibility of this View is potentially affected by a change 12084 * to this view itself, an ancestor view or the window this view is attached to. 12085 * 12086 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 12087 * and this view's window is also visible 12088 */ 12089 @CallSuper 12090 public void onVisibilityAggregated(boolean isVisible) { 12091 if (isVisible && mAttachInfo != null) { 12092 initialAwakenScrollBars(); 12093 } 12094 12095 final Drawable dr = mBackground; 12096 if (dr != null && isVisible != dr.isVisible()) { 12097 dr.setVisible(isVisible, false); 12098 } 12099 final Drawable hl = mDefaultFocusHighlight; 12100 if (hl != null && isVisible != hl.isVisible()) { 12101 hl.setVisible(isVisible, false); 12102 } 12103 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 12104 if (fg != null && isVisible != fg.isVisible()) { 12105 fg.setVisible(isVisible, false); 12106 } 12107 12108 if (isAutofillable()) { 12109 AutofillManager afm = getAutofillManager(); 12110 12111 if (afm != null && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID) { 12112 if (mVisibilityChangeForAutofillHandler != null) { 12113 mVisibilityChangeForAutofillHandler.removeMessages(0); 12114 } 12115 12116 // If the view is in the background but still part of the hierarchy this is called 12117 // with isVisible=false. Hence visibility==false requires further checks 12118 if (isVisible) { 12119 afm.notifyViewVisibilityChange(this, true); 12120 } else { 12121 if (mVisibilityChangeForAutofillHandler == null) { 12122 mVisibilityChangeForAutofillHandler = 12123 new VisibilityChangeForAutofillHandler(afm, this); 12124 } 12125 // Let current operation (e.g. removal of the view from the hierarchy) 12126 // finish before checking state 12127 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 12128 } 12129 } 12130 } 12131 } 12132 12133 /** 12134 * Returns the current visibility of the window this view is attached to 12135 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 12136 * 12137 * @return Returns the current visibility of the view's window. 12138 */ 12139 @Visibility 12140 public int getWindowVisibility() { 12141 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 12142 } 12143 12144 /** 12145 * Retrieve the overall visible display size in which the window this view is 12146 * attached to has been positioned in. This takes into account screen 12147 * decorations above the window, for both cases where the window itself 12148 * is being position inside of them or the window is being placed under 12149 * then and covered insets are used for the window to position its content 12150 * inside. In effect, this tells you the available area where content can 12151 * be placed and remain visible to users. 12152 * 12153 * <p>This function requires an IPC back to the window manager to retrieve 12154 * the requested information, so should not be used in performance critical 12155 * code like drawing. 12156 * 12157 * @param outRect Filled in with the visible display frame. If the view 12158 * is not attached to a window, this is simply the raw display size. 12159 */ 12160 public void getWindowVisibleDisplayFrame(Rect outRect) { 12161 if (mAttachInfo != null) { 12162 try { 12163 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 12164 } catch (RemoteException e) { 12165 return; 12166 } 12167 // XXX This is really broken, and probably all needs to be done 12168 // in the window manager, and we need to know more about whether 12169 // we want the area behind or in front of the IME. 12170 final Rect insets = mAttachInfo.mVisibleInsets; 12171 outRect.left += insets.left; 12172 outRect.top += insets.top; 12173 outRect.right -= insets.right; 12174 outRect.bottom -= insets.bottom; 12175 return; 12176 } 12177 // The view is not attached to a display so we don't have a context. 12178 // Make a best guess about the display size. 12179 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 12180 d.getRectSize(outRect); 12181 } 12182 12183 /** 12184 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 12185 * is currently in without any insets. 12186 * 12187 * @hide 12188 */ 12189 public void getWindowDisplayFrame(Rect outRect) { 12190 if (mAttachInfo != null) { 12191 try { 12192 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 12193 } catch (RemoteException e) { 12194 return; 12195 } 12196 return; 12197 } 12198 // The view is not attached to a display so we don't have a context. 12199 // Make a best guess about the display size. 12200 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 12201 d.getRectSize(outRect); 12202 } 12203 12204 /** 12205 * Dispatch a notification about a resource configuration change down 12206 * the view hierarchy. 12207 * ViewGroups should override to route to their children. 12208 * 12209 * @param newConfig The new resource configuration. 12210 * 12211 * @see #onConfigurationChanged(android.content.res.Configuration) 12212 */ 12213 public void dispatchConfigurationChanged(Configuration newConfig) { 12214 onConfigurationChanged(newConfig); 12215 } 12216 12217 /** 12218 * Called when the current configuration of the resources being used 12219 * by the application have changed. You can use this to decide when 12220 * to reload resources that can changed based on orientation and other 12221 * configuration characteristics. You only need to use this if you are 12222 * not relying on the normal {@link android.app.Activity} mechanism of 12223 * recreating the activity instance upon a configuration change. 12224 * 12225 * @param newConfig The new resource configuration. 12226 */ 12227 protected void onConfigurationChanged(Configuration newConfig) { 12228 } 12229 12230 /** 12231 * Private function to aggregate all per-view attributes in to the view 12232 * root. 12233 */ 12234 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 12235 performCollectViewAttributes(attachInfo, visibility); 12236 } 12237 12238 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 12239 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 12240 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 12241 attachInfo.mKeepScreenOn = true; 12242 } 12243 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 12244 ListenerInfo li = mListenerInfo; 12245 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 12246 attachInfo.mHasSystemUiListeners = true; 12247 } 12248 } 12249 } 12250 12251 void needGlobalAttributesUpdate(boolean force) { 12252 final AttachInfo ai = mAttachInfo; 12253 if (ai != null && !ai.mRecomputeGlobalAttributes) { 12254 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 12255 || ai.mHasSystemUiListeners) { 12256 ai.mRecomputeGlobalAttributes = true; 12257 } 12258 } 12259 } 12260 12261 /** 12262 * Returns whether the device is currently in touch mode. Touch mode is entered 12263 * once the user begins interacting with the device by touch, and affects various 12264 * things like whether focus is always visible to the user. 12265 * 12266 * @return Whether the device is in touch mode. 12267 */ 12268 @ViewDebug.ExportedProperty 12269 public boolean isInTouchMode() { 12270 if (mAttachInfo != null) { 12271 return mAttachInfo.mInTouchMode; 12272 } else { 12273 return ViewRootImpl.isInTouchMode(); 12274 } 12275 } 12276 12277 /** 12278 * Returns the context the view is running in, through which it can 12279 * access the current theme, resources, etc. 12280 * 12281 * @return The view's Context. 12282 */ 12283 @ViewDebug.CapturedViewProperty 12284 public final Context getContext() { 12285 return mContext; 12286 } 12287 12288 /** 12289 * Handle a key event before it is processed by any input method 12290 * associated with the view hierarchy. This can be used to intercept 12291 * key events in special situations before the IME consumes them; a 12292 * typical example would be handling the BACK key to update the application's 12293 * UI instead of allowing the IME to see it and close itself. 12294 * 12295 * @param keyCode The value in event.getKeyCode(). 12296 * @param event Description of the key event. 12297 * @return If you handled the event, return true. If you want to allow the 12298 * event to be handled by the next receiver, return false. 12299 */ 12300 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 12301 return false; 12302 } 12303 12304 /** 12305 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 12306 * KeyEvent.Callback.onKeyDown()}: perform press of the view 12307 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 12308 * is released, if the view is enabled and clickable. 12309 * <p> 12310 * Key presses in software keyboards will generally NOT trigger this 12311 * listener, although some may elect to do so in some situations. Do not 12312 * rely on this to catch software key presses. 12313 * 12314 * @param keyCode a key code that represents the button pressed, from 12315 * {@link android.view.KeyEvent} 12316 * @param event the KeyEvent object that defines the button action 12317 */ 12318 public boolean onKeyDown(int keyCode, KeyEvent event) { 12319 if (KeyEvent.isConfirmKey(keyCode)) { 12320 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 12321 return true; 12322 } 12323 12324 if (event.getRepeatCount() == 0) { 12325 // Long clickable items don't necessarily have to be clickable. 12326 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 12327 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 12328 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 12329 // For the purposes of menu anchoring and drawable hotspots, 12330 // key events are considered to be at the center of the view. 12331 final float x = getWidth() / 2f; 12332 final float y = getHeight() / 2f; 12333 if (clickable) { 12334 setPressed(true, x, y); 12335 } 12336 checkForLongClick(0, x, y); 12337 return true; 12338 } 12339 } 12340 } 12341 12342 return false; 12343 } 12344 12345 /** 12346 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 12347 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 12348 * the event). 12349 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12350 * although some may elect to do so in some situations. Do not rely on this to 12351 * catch software key presses. 12352 */ 12353 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 12354 return false; 12355 } 12356 12357 /** 12358 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 12359 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 12360 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 12361 * or {@link KeyEvent#KEYCODE_SPACE} is released. 12362 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12363 * although some may elect to do so in some situations. Do not rely on this to 12364 * catch software key presses. 12365 * 12366 * @param keyCode A key code that represents the button pressed, from 12367 * {@link android.view.KeyEvent}. 12368 * @param event The KeyEvent object that defines the button action. 12369 */ 12370 public boolean onKeyUp(int keyCode, KeyEvent event) { 12371 if (KeyEvent.isConfirmKey(keyCode)) { 12372 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 12373 return true; 12374 } 12375 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 12376 setPressed(false); 12377 12378 if (!mHasPerformedLongPress) { 12379 // This is a tap, so remove the longpress check 12380 removeLongPressCallback(); 12381 if (!event.isCanceled()) { 12382 return performClick(); 12383 } 12384 } 12385 } 12386 } 12387 return false; 12388 } 12389 12390 /** 12391 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 12392 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 12393 * the event). 12394 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12395 * although some may elect to do so in some situations. Do not rely on this to 12396 * catch software key presses. 12397 * 12398 * @param keyCode A key code that represents the button pressed, from 12399 * {@link android.view.KeyEvent}. 12400 * @param repeatCount The number of times the action was made. 12401 * @param event The KeyEvent object that defines the button action. 12402 */ 12403 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 12404 return false; 12405 } 12406 12407 /** 12408 * Called on the focused view when a key shortcut event is not handled. 12409 * Override this method to implement local key shortcuts for the View. 12410 * Key shortcuts can also be implemented by setting the 12411 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 12412 * 12413 * @param keyCode The value in event.getKeyCode(). 12414 * @param event Description of the key event. 12415 * @return If you handled the event, return true. If you want to allow the 12416 * event to be handled by the next receiver, return false. 12417 */ 12418 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 12419 return false; 12420 } 12421 12422 /** 12423 * Check whether the called view is a text editor, in which case it 12424 * would make sense to automatically display a soft input window for 12425 * it. Subclasses should override this if they implement 12426 * {@link #onCreateInputConnection(EditorInfo)} to return true if 12427 * a call on that method would return a non-null InputConnection, and 12428 * they are really a first-class editor that the user would normally 12429 * start typing on when the go into a window containing your view. 12430 * 12431 * <p>The default implementation always returns false. This does 12432 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 12433 * will not be called or the user can not otherwise perform edits on your 12434 * view; it is just a hint to the system that this is not the primary 12435 * purpose of this view. 12436 * 12437 * @return Returns true if this view is a text editor, else false. 12438 */ 12439 public boolean onCheckIsTextEditor() { 12440 return false; 12441 } 12442 12443 /** 12444 * Create a new InputConnection for an InputMethod to interact 12445 * with the view. The default implementation returns null, since it doesn't 12446 * support input methods. You can override this to implement such support. 12447 * This is only needed for views that take focus and text input. 12448 * 12449 * <p>When implementing this, you probably also want to implement 12450 * {@link #onCheckIsTextEditor()} to indicate you will return a 12451 * non-null InputConnection.</p> 12452 * 12453 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 12454 * object correctly and in its entirety, so that the connected IME can rely 12455 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 12456 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 12457 * must be filled in with the correct cursor position for IMEs to work correctly 12458 * with your application.</p> 12459 * 12460 * @param outAttrs Fill in with attribute information about the connection. 12461 */ 12462 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 12463 return null; 12464 } 12465 12466 /** 12467 * Called by the {@link android.view.inputmethod.InputMethodManager} 12468 * when a view who is not the current 12469 * input connection target is trying to make a call on the manager. The 12470 * default implementation returns false; you can override this to return 12471 * true for certain views if you are performing InputConnection proxying 12472 * to them. 12473 * @param view The View that is making the InputMethodManager call. 12474 * @return Return true to allow the call, false to reject. 12475 */ 12476 public boolean checkInputConnectionProxy(View view) { 12477 return false; 12478 } 12479 12480 /** 12481 * Show the context menu for this view. It is not safe to hold on to the 12482 * menu after returning from this method. 12483 * 12484 * You should normally not overload this method. Overload 12485 * {@link #onCreateContextMenu(ContextMenu)} or define an 12486 * {@link OnCreateContextMenuListener} to add items to the context menu. 12487 * 12488 * @param menu The context menu to populate 12489 */ 12490 public void createContextMenu(ContextMenu menu) { 12491 ContextMenuInfo menuInfo = getContextMenuInfo(); 12492 12493 // Sets the current menu info so all items added to menu will have 12494 // my extra info set. 12495 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 12496 12497 onCreateContextMenu(menu); 12498 ListenerInfo li = mListenerInfo; 12499 if (li != null && li.mOnCreateContextMenuListener != null) { 12500 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 12501 } 12502 12503 // Clear the extra information so subsequent items that aren't mine don't 12504 // have my extra info. 12505 ((MenuBuilder)menu).setCurrentMenuInfo(null); 12506 12507 if (mParent != null) { 12508 mParent.createContextMenu(menu); 12509 } 12510 } 12511 12512 /** 12513 * Views should implement this if they have extra information to associate 12514 * with the context menu. The return result is supplied as a parameter to 12515 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 12516 * callback. 12517 * 12518 * @return Extra information about the item for which the context menu 12519 * should be shown. This information will vary across different 12520 * subclasses of View. 12521 */ 12522 protected ContextMenuInfo getContextMenuInfo() { 12523 return null; 12524 } 12525 12526 /** 12527 * Views should implement this if the view itself is going to add items to 12528 * the context menu. 12529 * 12530 * @param menu the context menu to populate 12531 */ 12532 protected void onCreateContextMenu(ContextMenu menu) { 12533 } 12534 12535 /** 12536 * Implement this method to handle trackball motion events. The 12537 * <em>relative</em> movement of the trackball since the last event 12538 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 12539 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 12540 * that a movement of 1 corresponds to the user pressing one DPAD key (so 12541 * they will often be fractional values, representing the more fine-grained 12542 * movement information available from a trackball). 12543 * 12544 * @param event The motion event. 12545 * @return True if the event was handled, false otherwise. 12546 */ 12547 public boolean onTrackballEvent(MotionEvent event) { 12548 return false; 12549 } 12550 12551 /** 12552 * Implement this method to handle generic motion events. 12553 * <p> 12554 * Generic motion events describe joystick movements, mouse hovers, track pad 12555 * touches, scroll wheel movements and other input events. The 12556 * {@link MotionEvent#getSource() source} of the motion event specifies 12557 * the class of input that was received. Implementations of this method 12558 * must examine the bits in the source before processing the event. 12559 * The following code example shows how this is done. 12560 * </p><p> 12561 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 12562 * are delivered to the view under the pointer. All other generic motion events are 12563 * delivered to the focused view. 12564 * </p> 12565 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 12566 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 12567 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 12568 * // process the joystick movement... 12569 * return true; 12570 * } 12571 * } 12572 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 12573 * switch (event.getAction()) { 12574 * case MotionEvent.ACTION_HOVER_MOVE: 12575 * // process the mouse hover movement... 12576 * return true; 12577 * case MotionEvent.ACTION_SCROLL: 12578 * // process the scroll wheel movement... 12579 * return true; 12580 * } 12581 * } 12582 * return super.onGenericMotionEvent(event); 12583 * }</pre> 12584 * 12585 * @param event The generic motion event being processed. 12586 * @return True if the event was handled, false otherwise. 12587 */ 12588 public boolean onGenericMotionEvent(MotionEvent event) { 12589 return false; 12590 } 12591 12592 /** 12593 * Implement this method to handle hover events. 12594 * <p> 12595 * This method is called whenever a pointer is hovering into, over, or out of the 12596 * bounds of a view and the view is not currently being touched. 12597 * Hover events are represented as pointer events with action 12598 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 12599 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 12600 * </p> 12601 * <ul> 12602 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 12603 * when the pointer enters the bounds of the view.</li> 12604 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 12605 * when the pointer has already entered the bounds of the view and has moved.</li> 12606 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 12607 * when the pointer has exited the bounds of the view or when the pointer is 12608 * about to go down due to a button click, tap, or similar user action that 12609 * causes the view to be touched.</li> 12610 * </ul> 12611 * <p> 12612 * The view should implement this method to return true to indicate that it is 12613 * handling the hover event, such as by changing its drawable state. 12614 * </p><p> 12615 * The default implementation calls {@link #setHovered} to update the hovered state 12616 * of the view when a hover enter or hover exit event is received, if the view 12617 * is enabled and is clickable. The default implementation also sends hover 12618 * accessibility events. 12619 * </p> 12620 * 12621 * @param event The motion event that describes the hover. 12622 * @return True if the view handled the hover event. 12623 * 12624 * @see #isHovered 12625 * @see #setHovered 12626 * @see #onHoverChanged 12627 */ 12628 public boolean onHoverEvent(MotionEvent event) { 12629 // The root view may receive hover (or touch) events that are outside the bounds of 12630 // the window. This code ensures that we only send accessibility events for 12631 // hovers that are actually within the bounds of the root view. 12632 final int action = event.getActionMasked(); 12633 if (!mSendingHoverAccessibilityEvents) { 12634 if ((action == MotionEvent.ACTION_HOVER_ENTER 12635 || action == MotionEvent.ACTION_HOVER_MOVE) 12636 && !hasHoveredChild() 12637 && pointInView(event.getX(), event.getY())) { 12638 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 12639 mSendingHoverAccessibilityEvents = true; 12640 } 12641 } else { 12642 if (action == MotionEvent.ACTION_HOVER_EXIT 12643 || (action == MotionEvent.ACTION_MOVE 12644 && !pointInView(event.getX(), event.getY()))) { 12645 mSendingHoverAccessibilityEvents = false; 12646 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 12647 } 12648 } 12649 12650 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 12651 && event.isFromSource(InputDevice.SOURCE_MOUSE) 12652 && isOnScrollbar(event.getX(), event.getY())) { 12653 awakenScrollBars(); 12654 } 12655 12656 // If we consider ourself hoverable, or if we we're already hovered, 12657 // handle changing state in response to ENTER and EXIT events. 12658 if (isHoverable() || isHovered()) { 12659 switch (action) { 12660 case MotionEvent.ACTION_HOVER_ENTER: 12661 setHovered(true); 12662 break; 12663 case MotionEvent.ACTION_HOVER_EXIT: 12664 setHovered(false); 12665 break; 12666 } 12667 12668 // Dispatch the event to onGenericMotionEvent before returning true. 12669 // This is to provide compatibility with existing applications that 12670 // handled HOVER_MOVE events in onGenericMotionEvent and that would 12671 // break because of the new default handling for hoverable views 12672 // in onHoverEvent. 12673 // Note that onGenericMotionEvent will be called by default when 12674 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 12675 dispatchGenericMotionEventInternal(event); 12676 // The event was already handled by calling setHovered(), so always 12677 // return true. 12678 return true; 12679 } 12680 12681 return false; 12682 } 12683 12684 /** 12685 * Returns true if the view should handle {@link #onHoverEvent} 12686 * by calling {@link #setHovered} to change its hovered state. 12687 * 12688 * @return True if the view is hoverable. 12689 */ 12690 private boolean isHoverable() { 12691 final int viewFlags = mViewFlags; 12692 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12693 return false; 12694 } 12695 12696 return (viewFlags & CLICKABLE) == CLICKABLE 12697 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 12698 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12699 } 12700 12701 /** 12702 * Returns true if the view is currently hovered. 12703 * 12704 * @return True if the view is currently hovered. 12705 * 12706 * @see #setHovered 12707 * @see #onHoverChanged 12708 */ 12709 @ViewDebug.ExportedProperty 12710 public boolean isHovered() { 12711 return (mPrivateFlags & PFLAG_HOVERED) != 0; 12712 } 12713 12714 /** 12715 * Sets whether the view is currently hovered. 12716 * <p> 12717 * Calling this method also changes the drawable state of the view. This 12718 * enables the view to react to hover by using different drawable resources 12719 * to change its appearance. 12720 * </p><p> 12721 * The {@link #onHoverChanged} method is called when the hovered state changes. 12722 * </p> 12723 * 12724 * @param hovered True if the view is hovered. 12725 * 12726 * @see #isHovered 12727 * @see #onHoverChanged 12728 */ 12729 public void setHovered(boolean hovered) { 12730 if (hovered) { 12731 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 12732 mPrivateFlags |= PFLAG_HOVERED; 12733 refreshDrawableState(); 12734 onHoverChanged(true); 12735 } 12736 } else { 12737 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 12738 mPrivateFlags &= ~PFLAG_HOVERED; 12739 refreshDrawableState(); 12740 onHoverChanged(false); 12741 } 12742 } 12743 } 12744 12745 /** 12746 * Implement this method to handle hover state changes. 12747 * <p> 12748 * This method is called whenever the hover state changes as a result of a 12749 * call to {@link #setHovered}. 12750 * </p> 12751 * 12752 * @param hovered The current hover state, as returned by {@link #isHovered}. 12753 * 12754 * @see #isHovered 12755 * @see #setHovered 12756 */ 12757 public void onHoverChanged(boolean hovered) { 12758 } 12759 12760 /** 12761 * Handles scroll bar dragging by mouse input. 12762 * 12763 * @hide 12764 * @param event The motion event. 12765 * 12766 * @return true if the event was handled as a scroll bar dragging, false otherwise. 12767 */ 12768 protected boolean handleScrollBarDragging(MotionEvent event) { 12769 if (mScrollCache == null) { 12770 return false; 12771 } 12772 final float x = event.getX(); 12773 final float y = event.getY(); 12774 final int action = event.getAction(); 12775 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 12776 && action != MotionEvent.ACTION_DOWN) 12777 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 12778 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 12779 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12780 return false; 12781 } 12782 12783 switch (action) { 12784 case MotionEvent.ACTION_MOVE: 12785 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 12786 return false; 12787 } 12788 if (mScrollCache.mScrollBarDraggingState 12789 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 12790 final Rect bounds = mScrollCache.mScrollBarBounds; 12791 getVerticalScrollBarBounds(bounds, null); 12792 final int range = computeVerticalScrollRange(); 12793 final int offset = computeVerticalScrollOffset(); 12794 final int extent = computeVerticalScrollExtent(); 12795 12796 final int thumbLength = ScrollBarUtils.getThumbLength( 12797 bounds.height(), bounds.width(), extent, range); 12798 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12799 bounds.height(), thumbLength, extent, range, offset); 12800 12801 final float diff = y - mScrollCache.mScrollBarDraggingPos; 12802 final float maxThumbOffset = bounds.height() - thumbLength; 12803 final float newThumbOffset = 12804 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12805 final int height = getHeight(); 12806 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12807 && height > 0 && extent > 0) { 12808 final int newY = Math.round((range - extent) 12809 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 12810 if (newY != getScrollY()) { 12811 mScrollCache.mScrollBarDraggingPos = y; 12812 setScrollY(newY); 12813 } 12814 } 12815 return true; 12816 } 12817 if (mScrollCache.mScrollBarDraggingState 12818 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 12819 final Rect bounds = mScrollCache.mScrollBarBounds; 12820 getHorizontalScrollBarBounds(bounds, null); 12821 final int range = computeHorizontalScrollRange(); 12822 final int offset = computeHorizontalScrollOffset(); 12823 final int extent = computeHorizontalScrollExtent(); 12824 12825 final int thumbLength = ScrollBarUtils.getThumbLength( 12826 bounds.width(), bounds.height(), extent, range); 12827 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12828 bounds.width(), thumbLength, extent, range, offset); 12829 12830 final float diff = x - mScrollCache.mScrollBarDraggingPos; 12831 final float maxThumbOffset = bounds.width() - thumbLength; 12832 final float newThumbOffset = 12833 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12834 final int width = getWidth(); 12835 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12836 && width > 0 && extent > 0) { 12837 final int newX = Math.round((range - extent) 12838 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 12839 if (newX != getScrollX()) { 12840 mScrollCache.mScrollBarDraggingPos = x; 12841 setScrollX(newX); 12842 } 12843 } 12844 return true; 12845 } 12846 case MotionEvent.ACTION_DOWN: 12847 if (mScrollCache.state == ScrollabilityCache.OFF) { 12848 return false; 12849 } 12850 if (isOnVerticalScrollbarThumb(x, y)) { 12851 mScrollCache.mScrollBarDraggingState = 12852 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 12853 mScrollCache.mScrollBarDraggingPos = y; 12854 return true; 12855 } 12856 if (isOnHorizontalScrollbarThumb(x, y)) { 12857 mScrollCache.mScrollBarDraggingState = 12858 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 12859 mScrollCache.mScrollBarDraggingPos = x; 12860 return true; 12861 } 12862 } 12863 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12864 return false; 12865 } 12866 12867 /** 12868 * Implement this method to handle touch screen motion events. 12869 * <p> 12870 * If this method is used to detect click actions, it is recommended that 12871 * the actions be performed by implementing and calling 12872 * {@link #performClick()}. This will ensure consistent system behavior, 12873 * including: 12874 * <ul> 12875 * <li>obeying click sound preferences 12876 * <li>dispatching OnClickListener calls 12877 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 12878 * accessibility features are enabled 12879 * </ul> 12880 * 12881 * @param event The motion event. 12882 * @return True if the event was handled, false otherwise. 12883 */ 12884 public boolean onTouchEvent(MotionEvent event) { 12885 final float x = event.getX(); 12886 final float y = event.getY(); 12887 final int viewFlags = mViewFlags; 12888 final int action = event.getAction(); 12889 12890 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 12891 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 12892 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12893 12894 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12895 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 12896 setPressed(false); 12897 } 12898 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12899 // A disabled view that is clickable still consumes the touch 12900 // events, it just doesn't respond to them. 12901 return clickable; 12902 } 12903 if (mTouchDelegate != null) { 12904 if (mTouchDelegate.onTouchEvent(event)) { 12905 return true; 12906 } 12907 } 12908 12909 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 12910 switch (action) { 12911 case MotionEvent.ACTION_UP: 12912 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12913 if ((viewFlags & TOOLTIP) == TOOLTIP) { 12914 handleTooltipUp(); 12915 } 12916 if (!clickable) { 12917 removeTapCallback(); 12918 removeLongPressCallback(); 12919 mInContextButtonPress = false; 12920 mHasPerformedLongPress = false; 12921 mIgnoreNextUpEvent = false; 12922 break; 12923 } 12924 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 12925 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 12926 // take focus if we don't have it already and we should in 12927 // touch mode. 12928 boolean focusTaken = false; 12929 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 12930 focusTaken = requestFocus(); 12931 } 12932 12933 if (prepressed) { 12934 // The button is being released before we actually 12935 // showed it as pressed. Make it show the pressed 12936 // state now (before scheduling the click) to ensure 12937 // the user sees it. 12938 setPressed(true, x, y); 12939 } 12940 12941 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 12942 // This is a tap, so remove the longpress check 12943 removeLongPressCallback(); 12944 12945 // Only perform take click actions if we were in the pressed state 12946 if (!focusTaken) { 12947 // Use a Runnable and post this rather than calling 12948 // performClick directly. This lets other visual state 12949 // of the view update before click actions start. 12950 if (mPerformClick == null) { 12951 mPerformClick = new PerformClick(); 12952 } 12953 if (!post(mPerformClick)) { 12954 performClick(); 12955 } 12956 } 12957 } 12958 12959 if (mUnsetPressedState == null) { 12960 mUnsetPressedState = new UnsetPressedState(); 12961 } 12962 12963 if (prepressed) { 12964 postDelayed(mUnsetPressedState, 12965 ViewConfiguration.getPressedStateDuration()); 12966 } else if (!post(mUnsetPressedState)) { 12967 // If the post failed, unpress right now 12968 mUnsetPressedState.run(); 12969 } 12970 12971 removeTapCallback(); 12972 } 12973 mIgnoreNextUpEvent = false; 12974 break; 12975 12976 case MotionEvent.ACTION_DOWN: 12977 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 12978 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 12979 } 12980 mHasPerformedLongPress = false; 12981 12982 if (!clickable) { 12983 checkForLongClick(0, x, y); 12984 break; 12985 } 12986 12987 if (performButtonActionOnTouchDown(event)) { 12988 break; 12989 } 12990 12991 // Walk up the hierarchy to determine if we're inside a scrolling container. 12992 boolean isInScrollingContainer = isInScrollingContainer(); 12993 12994 // For views inside a scrolling container, delay the pressed feedback for 12995 // a short period in case this is a scroll. 12996 if (isInScrollingContainer) { 12997 mPrivateFlags |= PFLAG_PREPRESSED; 12998 if (mPendingCheckForTap == null) { 12999 mPendingCheckForTap = new CheckForTap(); 13000 } 13001 mPendingCheckForTap.x = event.getX(); 13002 mPendingCheckForTap.y = event.getY(); 13003 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 13004 } else { 13005 // Not inside a scrolling container, so show the feedback right away 13006 setPressed(true, x, y); 13007 checkForLongClick(0, x, y); 13008 } 13009 break; 13010 13011 case MotionEvent.ACTION_CANCEL: 13012 if (clickable) { 13013 setPressed(false); 13014 } 13015 removeTapCallback(); 13016 removeLongPressCallback(); 13017 mInContextButtonPress = false; 13018 mHasPerformedLongPress = false; 13019 mIgnoreNextUpEvent = false; 13020 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13021 break; 13022 13023 case MotionEvent.ACTION_MOVE: 13024 if (clickable) { 13025 drawableHotspotChanged(x, y); 13026 } 13027 13028 // Be lenient about moving outside of buttons 13029 if (!pointInView(x, y, mTouchSlop)) { 13030 // Outside button 13031 // Remove any future long press/tap checks 13032 removeTapCallback(); 13033 removeLongPressCallback(); 13034 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 13035 setPressed(false); 13036 } 13037 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13038 } 13039 break; 13040 } 13041 13042 return true; 13043 } 13044 13045 return false; 13046 } 13047 13048 /** 13049 * @hide 13050 */ 13051 public boolean isInScrollingContainer() { 13052 ViewParent p = getParent(); 13053 while (p != null && p instanceof ViewGroup) { 13054 if (((ViewGroup) p).shouldDelayChildPressedState()) { 13055 return true; 13056 } 13057 p = p.getParent(); 13058 } 13059 return false; 13060 } 13061 13062 /** 13063 * Remove the longpress detection timer. 13064 */ 13065 private void removeLongPressCallback() { 13066 if (mPendingCheckForLongPress != null) { 13067 removeCallbacks(mPendingCheckForLongPress); 13068 } 13069 } 13070 13071 /** 13072 * Remove the pending click action 13073 */ 13074 private void removePerformClickCallback() { 13075 if (mPerformClick != null) { 13076 removeCallbacks(mPerformClick); 13077 } 13078 } 13079 13080 /** 13081 * Remove the prepress detection timer. 13082 */ 13083 private void removeUnsetPressCallback() { 13084 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 13085 setPressed(false); 13086 removeCallbacks(mUnsetPressedState); 13087 } 13088 } 13089 13090 /** 13091 * Remove the tap detection timer. 13092 */ 13093 private void removeTapCallback() { 13094 if (mPendingCheckForTap != null) { 13095 mPrivateFlags &= ~PFLAG_PREPRESSED; 13096 removeCallbacks(mPendingCheckForTap); 13097 } 13098 } 13099 13100 /** 13101 * Cancels a pending long press. Your subclass can use this if you 13102 * want the context menu to come up if the user presses and holds 13103 * at the same place, but you don't want it to come up if they press 13104 * and then move around enough to cause scrolling. 13105 */ 13106 public void cancelLongPress() { 13107 removeLongPressCallback(); 13108 13109 /* 13110 * The prepressed state handled by the tap callback is a display 13111 * construct, but the tap callback will post a long press callback 13112 * less its own timeout. Remove it here. 13113 */ 13114 removeTapCallback(); 13115 } 13116 13117 /** 13118 * Remove the pending callback for sending a 13119 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 13120 */ 13121 private void removeSendViewScrolledAccessibilityEventCallback() { 13122 if (mSendViewScrolledAccessibilityEvent != null) { 13123 removeCallbacks(mSendViewScrolledAccessibilityEvent); 13124 mSendViewScrolledAccessibilityEvent.mIsPending = false; 13125 } 13126 } 13127 13128 /** 13129 * Sets the TouchDelegate for this View. 13130 */ 13131 public void setTouchDelegate(TouchDelegate delegate) { 13132 mTouchDelegate = delegate; 13133 } 13134 13135 /** 13136 * Gets the TouchDelegate for this View. 13137 */ 13138 public TouchDelegate getTouchDelegate() { 13139 return mTouchDelegate; 13140 } 13141 13142 /** 13143 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 13144 * 13145 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 13146 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 13147 * available. This method should only be called for touch events. 13148 * 13149 * <p class="note">This api is not intended for most applications. Buffered dispatch 13150 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 13151 * streams will not improve your input latency. Side effects include: increased latency, 13152 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 13153 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 13154 * you.</p> 13155 */ 13156 public final void requestUnbufferedDispatch(MotionEvent event) { 13157 final int action = event.getAction(); 13158 if (mAttachInfo == null 13159 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 13160 || !event.isTouchEvent()) { 13161 return; 13162 } 13163 mAttachInfo.mUnbufferedDispatchRequested = true; 13164 } 13165 13166 /** 13167 * Set flags controlling behavior of this view. 13168 * 13169 * @param flags Constant indicating the value which should be set 13170 * @param mask Constant indicating the bit range that should be changed 13171 */ 13172 void setFlags(int flags, int mask) { 13173 final boolean accessibilityEnabled = 13174 AccessibilityManager.getInstance(mContext).isEnabled(); 13175 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 13176 13177 int old = mViewFlags; 13178 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 13179 13180 int changed = mViewFlags ^ old; 13181 if (changed == 0) { 13182 return; 13183 } 13184 int privateFlags = mPrivateFlags; 13185 13186 // If focusable is auto, update the FOCUSABLE bit. 13187 int focusableChangedByAuto = 0; 13188 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 13189 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 13190 // Heuristic only takes into account whether view is clickable. 13191 final int newFocus; 13192 if ((mViewFlags & CLICKABLE) != 0) { 13193 newFocus = FOCUSABLE; 13194 } else { 13195 newFocus = NOT_FOCUSABLE; 13196 } 13197 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 13198 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 13199 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 13200 } 13201 13202 /* Check if the FOCUSABLE bit has changed */ 13203 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 13204 if (((old & FOCUSABLE) == FOCUSABLE) 13205 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 13206 /* Give up focus if we are no longer focusable */ 13207 clearFocus(); 13208 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 13209 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 13210 /* 13211 * Tell the view system that we are now available to take focus 13212 * if no one else already has it. 13213 */ 13214 if (mParent != null) { 13215 ViewRootImpl viewRootImpl = getViewRootImpl(); 13216 if (!sAutoFocusableOffUIThreadWontNotifyParents 13217 || focusableChangedByAuto == 0 13218 || viewRootImpl == null 13219 || viewRootImpl.mThread == Thread.currentThread()) { 13220 mParent.focusableViewAvailable(this); 13221 } 13222 } 13223 } 13224 } 13225 13226 final int newVisibility = flags & VISIBILITY_MASK; 13227 if (newVisibility == VISIBLE) { 13228 if ((changed & VISIBILITY_MASK) != 0) { 13229 /* 13230 * If this view is becoming visible, invalidate it in case it changed while 13231 * it was not visible. Marking it drawn ensures that the invalidation will 13232 * go through. 13233 */ 13234 mPrivateFlags |= PFLAG_DRAWN; 13235 invalidate(true); 13236 13237 needGlobalAttributesUpdate(true); 13238 13239 // a view becoming visible is worth notifying the parent 13240 // about in case nothing has focus. even if this specific view 13241 // isn't focusable, it may contain something that is, so let 13242 // the root view try to give this focus if nothing else does. 13243 if ((mParent != null)) { 13244 mParent.focusableViewAvailable(this); 13245 } 13246 } 13247 } 13248 13249 /* Check if the GONE bit has changed */ 13250 if ((changed & GONE) != 0) { 13251 needGlobalAttributesUpdate(false); 13252 requestLayout(); 13253 13254 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 13255 if (hasFocus()) clearFocus(); 13256 clearAccessibilityFocus(); 13257 destroyDrawingCache(); 13258 if (mParent instanceof View) { 13259 // GONE views noop invalidation, so invalidate the parent 13260 ((View) mParent).invalidate(true); 13261 } 13262 // Mark the view drawn to ensure that it gets invalidated properly the next 13263 // time it is visible and gets invalidated 13264 mPrivateFlags |= PFLAG_DRAWN; 13265 } 13266 if (mAttachInfo != null) { 13267 mAttachInfo.mViewVisibilityChanged = true; 13268 } 13269 } 13270 13271 /* Check if the VISIBLE bit has changed */ 13272 if ((changed & INVISIBLE) != 0) { 13273 needGlobalAttributesUpdate(false); 13274 /* 13275 * If this view is becoming invisible, set the DRAWN flag so that 13276 * the next invalidate() will not be skipped. 13277 */ 13278 mPrivateFlags |= PFLAG_DRAWN; 13279 13280 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 13281 // root view becoming invisible shouldn't clear focus and accessibility focus 13282 if (getRootView() != this) { 13283 if (hasFocus()) clearFocus(); 13284 clearAccessibilityFocus(); 13285 } 13286 } 13287 if (mAttachInfo != null) { 13288 mAttachInfo.mViewVisibilityChanged = true; 13289 } 13290 } 13291 13292 if ((changed & VISIBILITY_MASK) != 0) { 13293 // If the view is invisible, cleanup its display list to free up resources 13294 if (newVisibility != VISIBLE && mAttachInfo != null) { 13295 cleanupDraw(); 13296 } 13297 13298 if (mParent instanceof ViewGroup) { 13299 ((ViewGroup) mParent).onChildVisibilityChanged(this, 13300 (changed & VISIBILITY_MASK), newVisibility); 13301 ((View) mParent).invalidate(true); 13302 } else if (mParent != null) { 13303 mParent.invalidateChild(this, null); 13304 } 13305 13306 if (mAttachInfo != null) { 13307 dispatchVisibilityChanged(this, newVisibility); 13308 13309 // Aggregated visibility changes are dispatched to attached views 13310 // in visible windows where the parent is currently shown/drawn 13311 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 13312 // discounting clipping or overlapping. This makes it a good place 13313 // to change animation states. 13314 if (mParent != null && getWindowVisibility() == VISIBLE && 13315 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 13316 dispatchVisibilityAggregated(newVisibility == VISIBLE); 13317 } 13318 notifySubtreeAccessibilityStateChangedIfNeeded(); 13319 } 13320 } 13321 13322 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 13323 destroyDrawingCache(); 13324 } 13325 13326 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 13327 destroyDrawingCache(); 13328 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 13329 invalidateParentCaches(); 13330 } 13331 13332 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 13333 destroyDrawingCache(); 13334 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 13335 } 13336 13337 if ((changed & DRAW_MASK) != 0) { 13338 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 13339 if (mBackground != null 13340 || mDefaultFocusHighlight != null 13341 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 13342 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 13343 } else { 13344 mPrivateFlags |= PFLAG_SKIP_DRAW; 13345 } 13346 } else { 13347 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 13348 } 13349 requestLayout(); 13350 invalidate(true); 13351 } 13352 13353 if ((changed & KEEP_SCREEN_ON) != 0) { 13354 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 13355 mParent.recomputeViewAttributes(this); 13356 } 13357 } 13358 13359 if (accessibilityEnabled) { 13360 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 13361 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 13362 || (changed & CONTEXT_CLICKABLE) != 0) { 13363 if (oldIncludeForAccessibility != includeForAccessibility()) { 13364 notifySubtreeAccessibilityStateChangedIfNeeded(); 13365 } else { 13366 notifyViewAccessibilityStateChangedIfNeeded( 13367 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13368 } 13369 } else if ((changed & ENABLED_MASK) != 0) { 13370 notifyViewAccessibilityStateChangedIfNeeded( 13371 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13372 } 13373 } 13374 } 13375 13376 /** 13377 * Change the view's z order in the tree, so it's on top of other sibling 13378 * views. This ordering change may affect layout, if the parent container 13379 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 13380 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 13381 * method should be followed by calls to {@link #requestLayout()} and 13382 * {@link View#invalidate()} on the view's parent to force the parent to redraw 13383 * with the new child ordering. 13384 * 13385 * @see ViewGroup#bringChildToFront(View) 13386 */ 13387 public void bringToFront() { 13388 if (mParent != null) { 13389 mParent.bringChildToFront(this); 13390 } 13391 } 13392 13393 /** 13394 * This is called in response to an internal scroll in this view (i.e., the 13395 * view scrolled its own contents). This is typically as a result of 13396 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 13397 * called. 13398 * 13399 * @param l Current horizontal scroll origin. 13400 * @param t Current vertical scroll origin. 13401 * @param oldl Previous horizontal scroll origin. 13402 * @param oldt Previous vertical scroll origin. 13403 */ 13404 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 13405 notifySubtreeAccessibilityStateChangedIfNeeded(); 13406 13407 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 13408 postSendViewScrolledAccessibilityEventCallback(); 13409 } 13410 13411 mBackgroundSizeChanged = true; 13412 mDefaultFocusHighlightSizeChanged = true; 13413 if (mForegroundInfo != null) { 13414 mForegroundInfo.mBoundsChanged = true; 13415 } 13416 13417 final AttachInfo ai = mAttachInfo; 13418 if (ai != null) { 13419 ai.mViewScrollChanged = true; 13420 } 13421 13422 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 13423 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 13424 } 13425 } 13426 13427 /** 13428 * Interface definition for a callback to be invoked when the scroll 13429 * X or Y positions of a view change. 13430 * <p> 13431 * <b>Note:</b> Some views handle scrolling independently from View and may 13432 * have their own separate listeners for scroll-type events. For example, 13433 * {@link android.widget.ListView ListView} allows clients to register an 13434 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 13435 * to listen for changes in list scroll position. 13436 * 13437 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 13438 */ 13439 public interface OnScrollChangeListener { 13440 /** 13441 * Called when the scroll position of a view changes. 13442 * 13443 * @param v The view whose scroll position has changed. 13444 * @param scrollX Current horizontal scroll origin. 13445 * @param scrollY Current vertical scroll origin. 13446 * @param oldScrollX Previous horizontal scroll origin. 13447 * @param oldScrollY Previous vertical scroll origin. 13448 */ 13449 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 13450 } 13451 13452 /** 13453 * Interface definition for a callback to be invoked when the layout bounds of a view 13454 * changes due to layout processing. 13455 */ 13456 public interface OnLayoutChangeListener { 13457 /** 13458 * Called when the layout bounds of a view changes due to layout processing. 13459 * 13460 * @param v The view whose bounds have changed. 13461 * @param left The new value of the view's left property. 13462 * @param top The new value of the view's top property. 13463 * @param right The new value of the view's right property. 13464 * @param bottom The new value of the view's bottom property. 13465 * @param oldLeft The previous value of the view's left property. 13466 * @param oldTop The previous value of the view's top property. 13467 * @param oldRight The previous value of the view's right property. 13468 * @param oldBottom The previous value of the view's bottom property. 13469 */ 13470 void onLayoutChange(View v, int left, int top, int right, int bottom, 13471 int oldLeft, int oldTop, int oldRight, int oldBottom); 13472 } 13473 13474 /** 13475 * This is called during layout when the size of this view has changed. If 13476 * you were just added to the view hierarchy, you're called with the old 13477 * values of 0. 13478 * 13479 * @param w Current width of this view. 13480 * @param h Current height of this view. 13481 * @param oldw Old width of this view. 13482 * @param oldh Old height of this view. 13483 */ 13484 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 13485 } 13486 13487 /** 13488 * Called by draw to draw the child views. This may be overridden 13489 * by derived classes to gain control just before its children are drawn 13490 * (but after its own view has been drawn). 13491 * @param canvas the canvas on which to draw the view 13492 */ 13493 protected void dispatchDraw(Canvas canvas) { 13494 13495 } 13496 13497 /** 13498 * Gets the parent of this view. Note that the parent is a 13499 * ViewParent and not necessarily a View. 13500 * 13501 * @return Parent of this view. 13502 */ 13503 public final ViewParent getParent() { 13504 return mParent; 13505 } 13506 13507 /** 13508 * Set the horizontal scrolled position of your view. This will cause a call to 13509 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13510 * invalidated. 13511 * @param value the x position to scroll to 13512 */ 13513 public void setScrollX(int value) { 13514 scrollTo(value, mScrollY); 13515 } 13516 13517 /** 13518 * Set the vertical scrolled position of your view. This will cause a call to 13519 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13520 * invalidated. 13521 * @param value the y position to scroll to 13522 */ 13523 public void setScrollY(int value) { 13524 scrollTo(mScrollX, value); 13525 } 13526 13527 /** 13528 * Return the scrolled left position of this view. This is the left edge of 13529 * the displayed part of your view. You do not need to draw any pixels 13530 * farther left, since those are outside of the frame of your view on 13531 * screen. 13532 * 13533 * @return The left edge of the displayed part of your view, in pixels. 13534 */ 13535 public final int getScrollX() { 13536 return mScrollX; 13537 } 13538 13539 /** 13540 * Return the scrolled top position of this view. This is the top edge of 13541 * the displayed part of your view. You do not need to draw any pixels above 13542 * it, since those are outside of the frame of your view on screen. 13543 * 13544 * @return The top edge of the displayed part of your view, in pixels. 13545 */ 13546 public final int getScrollY() { 13547 return mScrollY; 13548 } 13549 13550 /** 13551 * Return the width of the your view. 13552 * 13553 * @return The width of your view, in pixels. 13554 */ 13555 @ViewDebug.ExportedProperty(category = "layout") 13556 public final int getWidth() { 13557 return mRight - mLeft; 13558 } 13559 13560 /** 13561 * Return the height of your view. 13562 * 13563 * @return The height of your view, in pixels. 13564 */ 13565 @ViewDebug.ExportedProperty(category = "layout") 13566 public final int getHeight() { 13567 return mBottom - mTop; 13568 } 13569 13570 /** 13571 * Return the visible drawing bounds of your view. Fills in the output 13572 * rectangle with the values from getScrollX(), getScrollY(), 13573 * getWidth(), and getHeight(). These bounds do not account for any 13574 * transformation properties currently set on the view, such as 13575 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 13576 * 13577 * @param outRect The (scrolled) drawing bounds of the view. 13578 */ 13579 public void getDrawingRect(Rect outRect) { 13580 outRect.left = mScrollX; 13581 outRect.top = mScrollY; 13582 outRect.right = mScrollX + (mRight - mLeft); 13583 outRect.bottom = mScrollY + (mBottom - mTop); 13584 } 13585 13586 /** 13587 * Like {@link #getMeasuredWidthAndState()}, but only returns the 13588 * raw width component (that is the result is masked by 13589 * {@link #MEASURED_SIZE_MASK}). 13590 * 13591 * @return The raw measured width of this view. 13592 */ 13593 public final int getMeasuredWidth() { 13594 return mMeasuredWidth & MEASURED_SIZE_MASK; 13595 } 13596 13597 /** 13598 * Return the full width measurement information for this view as computed 13599 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13600 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13601 * This should be used during measurement and layout calculations only. Use 13602 * {@link #getWidth()} to see how wide a view is after layout. 13603 * 13604 * @return The measured width of this view as a bit mask. 13605 */ 13606 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13607 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13608 name = "MEASURED_STATE_TOO_SMALL"), 13609 }) 13610 public final int getMeasuredWidthAndState() { 13611 return mMeasuredWidth; 13612 } 13613 13614 /** 13615 * Like {@link #getMeasuredHeightAndState()}, but only returns the 13616 * raw height component (that is the result is masked by 13617 * {@link #MEASURED_SIZE_MASK}). 13618 * 13619 * @return The raw measured height of this view. 13620 */ 13621 public final int getMeasuredHeight() { 13622 return mMeasuredHeight & MEASURED_SIZE_MASK; 13623 } 13624 13625 /** 13626 * Return the full height measurement information for this view as computed 13627 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13628 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13629 * This should be used during measurement and layout calculations only. Use 13630 * {@link #getHeight()} to see how wide a view is after layout. 13631 * 13632 * @return The measured height of this view as a bit mask. 13633 */ 13634 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13635 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13636 name = "MEASURED_STATE_TOO_SMALL"), 13637 }) 13638 public final int getMeasuredHeightAndState() { 13639 return mMeasuredHeight; 13640 } 13641 13642 /** 13643 * Return only the state bits of {@link #getMeasuredWidthAndState()} 13644 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 13645 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 13646 * and the height component is at the shifted bits 13647 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 13648 */ 13649 public final int getMeasuredState() { 13650 return (mMeasuredWidth&MEASURED_STATE_MASK) 13651 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 13652 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 13653 } 13654 13655 /** 13656 * The transform matrix of this view, which is calculated based on the current 13657 * rotation, scale, and pivot properties. 13658 * 13659 * @see #getRotation() 13660 * @see #getScaleX() 13661 * @see #getScaleY() 13662 * @see #getPivotX() 13663 * @see #getPivotY() 13664 * @return The current transform matrix for the view 13665 */ 13666 public Matrix getMatrix() { 13667 ensureTransformationInfo(); 13668 final Matrix matrix = mTransformationInfo.mMatrix; 13669 mRenderNode.getMatrix(matrix); 13670 return matrix; 13671 } 13672 13673 /** 13674 * Returns true if the transform matrix is the identity matrix. 13675 * Recomputes the matrix if necessary. 13676 * 13677 * @return True if the transform matrix is the identity matrix, false otherwise. 13678 */ 13679 final boolean hasIdentityMatrix() { 13680 return mRenderNode.hasIdentityMatrix(); 13681 } 13682 13683 void ensureTransformationInfo() { 13684 if (mTransformationInfo == null) { 13685 mTransformationInfo = new TransformationInfo(); 13686 } 13687 } 13688 13689 /** 13690 * Utility method to retrieve the inverse of the current mMatrix property. 13691 * We cache the matrix to avoid recalculating it when transform properties 13692 * have not changed. 13693 * 13694 * @return The inverse of the current matrix of this view. 13695 * @hide 13696 */ 13697 public final Matrix getInverseMatrix() { 13698 ensureTransformationInfo(); 13699 if (mTransformationInfo.mInverseMatrix == null) { 13700 mTransformationInfo.mInverseMatrix = new Matrix(); 13701 } 13702 final Matrix matrix = mTransformationInfo.mInverseMatrix; 13703 mRenderNode.getInverseMatrix(matrix); 13704 return matrix; 13705 } 13706 13707 /** 13708 * Gets the distance along the Z axis from the camera to this view. 13709 * 13710 * @see #setCameraDistance(float) 13711 * 13712 * @return The distance along the Z axis. 13713 */ 13714 public float getCameraDistance() { 13715 final float dpi = mResources.getDisplayMetrics().densityDpi; 13716 return -(mRenderNode.getCameraDistance() * dpi); 13717 } 13718 13719 /** 13720 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 13721 * views are drawn) from the camera to this view. The camera's distance 13722 * affects 3D transformations, for instance rotations around the X and Y 13723 * axis. If the rotationX or rotationY properties are changed and this view is 13724 * large (more than half the size of the screen), it is recommended to always 13725 * use a camera distance that's greater than the height (X axis rotation) or 13726 * the width (Y axis rotation) of this view.</p> 13727 * 13728 * <p>The distance of the camera from the view plane can have an affect on the 13729 * perspective distortion of the view when it is rotated around the x or y axis. 13730 * For example, a large distance will result in a large viewing angle, and there 13731 * will not be much perspective distortion of the view as it rotates. A short 13732 * distance may cause much more perspective distortion upon rotation, and can 13733 * also result in some drawing artifacts if the rotated view ends up partially 13734 * behind the camera (which is why the recommendation is to use a distance at 13735 * least as far as the size of the view, if the view is to be rotated.)</p> 13736 * 13737 * <p>The distance is expressed in "depth pixels." The default distance depends 13738 * on the screen density. For instance, on a medium density display, the 13739 * default distance is 1280. On a high density display, the default distance 13740 * is 1920.</p> 13741 * 13742 * <p>If you want to specify a distance that leads to visually consistent 13743 * results across various densities, use the following formula:</p> 13744 * <pre> 13745 * float scale = context.getResources().getDisplayMetrics().density; 13746 * view.setCameraDistance(distance * scale); 13747 * </pre> 13748 * 13749 * <p>The density scale factor of a high density display is 1.5, 13750 * and 1920 = 1280 * 1.5.</p> 13751 * 13752 * @param distance The distance in "depth pixels", if negative the opposite 13753 * value is used 13754 * 13755 * @see #setRotationX(float) 13756 * @see #setRotationY(float) 13757 */ 13758 public void setCameraDistance(float distance) { 13759 final float dpi = mResources.getDisplayMetrics().densityDpi; 13760 13761 invalidateViewProperty(true, false); 13762 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 13763 invalidateViewProperty(false, false); 13764 13765 invalidateParentIfNeededAndWasQuickRejected(); 13766 } 13767 13768 /** 13769 * The degrees that the view is rotated around the pivot point. 13770 * 13771 * @see #setRotation(float) 13772 * @see #getPivotX() 13773 * @see #getPivotY() 13774 * 13775 * @return The degrees of rotation. 13776 */ 13777 @ViewDebug.ExportedProperty(category = "drawing") 13778 public float getRotation() { 13779 return mRenderNode.getRotation(); 13780 } 13781 13782 /** 13783 * Sets the degrees that the view is rotated around the pivot point. Increasing values 13784 * result in clockwise rotation. 13785 * 13786 * @param rotation The degrees of rotation. 13787 * 13788 * @see #getRotation() 13789 * @see #getPivotX() 13790 * @see #getPivotY() 13791 * @see #setRotationX(float) 13792 * @see #setRotationY(float) 13793 * 13794 * @attr ref android.R.styleable#View_rotation 13795 */ 13796 public void setRotation(float rotation) { 13797 if (rotation != getRotation()) { 13798 // Double-invalidation is necessary to capture view's old and new areas 13799 invalidateViewProperty(true, false); 13800 mRenderNode.setRotation(rotation); 13801 invalidateViewProperty(false, true); 13802 13803 invalidateParentIfNeededAndWasQuickRejected(); 13804 notifySubtreeAccessibilityStateChangedIfNeeded(); 13805 } 13806 } 13807 13808 /** 13809 * The degrees that the view is rotated around the vertical axis through the pivot point. 13810 * 13811 * @see #getPivotX() 13812 * @see #getPivotY() 13813 * @see #setRotationY(float) 13814 * 13815 * @return The degrees of Y rotation. 13816 */ 13817 @ViewDebug.ExportedProperty(category = "drawing") 13818 public float getRotationY() { 13819 return mRenderNode.getRotationY(); 13820 } 13821 13822 /** 13823 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 13824 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 13825 * down the y axis. 13826 * 13827 * When rotating large views, it is recommended to adjust the camera distance 13828 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13829 * 13830 * @param rotationY The degrees of Y rotation. 13831 * 13832 * @see #getRotationY() 13833 * @see #getPivotX() 13834 * @see #getPivotY() 13835 * @see #setRotation(float) 13836 * @see #setRotationX(float) 13837 * @see #setCameraDistance(float) 13838 * 13839 * @attr ref android.R.styleable#View_rotationY 13840 */ 13841 public void setRotationY(float rotationY) { 13842 if (rotationY != getRotationY()) { 13843 invalidateViewProperty(true, false); 13844 mRenderNode.setRotationY(rotationY); 13845 invalidateViewProperty(false, true); 13846 13847 invalidateParentIfNeededAndWasQuickRejected(); 13848 notifySubtreeAccessibilityStateChangedIfNeeded(); 13849 } 13850 } 13851 13852 /** 13853 * The degrees that the view is rotated around the horizontal axis through the pivot point. 13854 * 13855 * @see #getPivotX() 13856 * @see #getPivotY() 13857 * @see #setRotationX(float) 13858 * 13859 * @return The degrees of X rotation. 13860 */ 13861 @ViewDebug.ExportedProperty(category = "drawing") 13862 public float getRotationX() { 13863 return mRenderNode.getRotationX(); 13864 } 13865 13866 /** 13867 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 13868 * Increasing values result in clockwise rotation from the viewpoint of looking down the 13869 * x axis. 13870 * 13871 * When rotating large views, it is recommended to adjust the camera distance 13872 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13873 * 13874 * @param rotationX The degrees of X rotation. 13875 * 13876 * @see #getRotationX() 13877 * @see #getPivotX() 13878 * @see #getPivotY() 13879 * @see #setRotation(float) 13880 * @see #setRotationY(float) 13881 * @see #setCameraDistance(float) 13882 * 13883 * @attr ref android.R.styleable#View_rotationX 13884 */ 13885 public void setRotationX(float rotationX) { 13886 if (rotationX != getRotationX()) { 13887 invalidateViewProperty(true, false); 13888 mRenderNode.setRotationX(rotationX); 13889 invalidateViewProperty(false, true); 13890 13891 invalidateParentIfNeededAndWasQuickRejected(); 13892 notifySubtreeAccessibilityStateChangedIfNeeded(); 13893 } 13894 } 13895 13896 /** 13897 * The amount that the view is scaled in x around the pivot point, as a proportion of 13898 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 13899 * 13900 * <p>By default, this is 1.0f. 13901 * 13902 * @see #getPivotX() 13903 * @see #getPivotY() 13904 * @return The scaling factor. 13905 */ 13906 @ViewDebug.ExportedProperty(category = "drawing") 13907 public float getScaleX() { 13908 return mRenderNode.getScaleX(); 13909 } 13910 13911 /** 13912 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 13913 * the view's unscaled width. A value of 1 means that no scaling is applied. 13914 * 13915 * @param scaleX The scaling factor. 13916 * @see #getPivotX() 13917 * @see #getPivotY() 13918 * 13919 * @attr ref android.R.styleable#View_scaleX 13920 */ 13921 public void setScaleX(float scaleX) { 13922 if (scaleX != getScaleX()) { 13923 invalidateViewProperty(true, false); 13924 mRenderNode.setScaleX(scaleX); 13925 invalidateViewProperty(false, true); 13926 13927 invalidateParentIfNeededAndWasQuickRejected(); 13928 notifySubtreeAccessibilityStateChangedIfNeeded(); 13929 } 13930 } 13931 13932 /** 13933 * The amount that the view is scaled in y around the pivot point, as a proportion of 13934 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 13935 * 13936 * <p>By default, this is 1.0f. 13937 * 13938 * @see #getPivotX() 13939 * @see #getPivotY() 13940 * @return The scaling factor. 13941 */ 13942 @ViewDebug.ExportedProperty(category = "drawing") 13943 public float getScaleY() { 13944 return mRenderNode.getScaleY(); 13945 } 13946 13947 /** 13948 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 13949 * the view's unscaled width. A value of 1 means that no scaling is applied. 13950 * 13951 * @param scaleY The scaling factor. 13952 * @see #getPivotX() 13953 * @see #getPivotY() 13954 * 13955 * @attr ref android.R.styleable#View_scaleY 13956 */ 13957 public void setScaleY(float scaleY) { 13958 if (scaleY != getScaleY()) { 13959 invalidateViewProperty(true, false); 13960 mRenderNode.setScaleY(scaleY); 13961 invalidateViewProperty(false, true); 13962 13963 invalidateParentIfNeededAndWasQuickRejected(); 13964 notifySubtreeAccessibilityStateChangedIfNeeded(); 13965 } 13966 } 13967 13968 /** 13969 * The x location of the point around which the view is {@link #setRotation(float) rotated} 13970 * and {@link #setScaleX(float) scaled}. 13971 * 13972 * @see #getRotation() 13973 * @see #getScaleX() 13974 * @see #getScaleY() 13975 * @see #getPivotY() 13976 * @return The x location of the pivot point. 13977 * 13978 * @attr ref android.R.styleable#View_transformPivotX 13979 */ 13980 @ViewDebug.ExportedProperty(category = "drawing") 13981 public float getPivotX() { 13982 return mRenderNode.getPivotX(); 13983 } 13984 13985 /** 13986 * Sets the x location of the point around which the view is 13987 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 13988 * By default, the pivot point is centered on the object. 13989 * Setting this property disables this behavior and causes the view to use only the 13990 * explicitly set pivotX and pivotY values. 13991 * 13992 * @param pivotX The x location of the pivot point. 13993 * @see #getRotation() 13994 * @see #getScaleX() 13995 * @see #getScaleY() 13996 * @see #getPivotY() 13997 * 13998 * @attr ref android.R.styleable#View_transformPivotX 13999 */ 14000 public void setPivotX(float pivotX) { 14001 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 14002 invalidateViewProperty(true, false); 14003 mRenderNode.setPivotX(pivotX); 14004 invalidateViewProperty(false, true); 14005 14006 invalidateParentIfNeededAndWasQuickRejected(); 14007 } 14008 } 14009 14010 /** 14011 * The y location of the point around which the view is {@link #setRotation(float) rotated} 14012 * and {@link #setScaleY(float) scaled}. 14013 * 14014 * @see #getRotation() 14015 * @see #getScaleX() 14016 * @see #getScaleY() 14017 * @see #getPivotY() 14018 * @return The y location of the pivot point. 14019 * 14020 * @attr ref android.R.styleable#View_transformPivotY 14021 */ 14022 @ViewDebug.ExportedProperty(category = "drawing") 14023 public float getPivotY() { 14024 return mRenderNode.getPivotY(); 14025 } 14026 14027 /** 14028 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 14029 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 14030 * Setting this property disables this behavior and causes the view to use only the 14031 * explicitly set pivotX and pivotY values. 14032 * 14033 * @param pivotY The y location of the pivot point. 14034 * @see #getRotation() 14035 * @see #getScaleX() 14036 * @see #getScaleY() 14037 * @see #getPivotY() 14038 * 14039 * @attr ref android.R.styleable#View_transformPivotY 14040 */ 14041 public void setPivotY(float pivotY) { 14042 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 14043 invalidateViewProperty(true, false); 14044 mRenderNode.setPivotY(pivotY); 14045 invalidateViewProperty(false, true); 14046 14047 invalidateParentIfNeededAndWasQuickRejected(); 14048 } 14049 } 14050 14051 /** 14052 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 14053 * completely transparent and 1 means the view is completely opaque. 14054 * 14055 * <p>By default this is 1.0f. 14056 * @return The opacity of the view. 14057 */ 14058 @ViewDebug.ExportedProperty(category = "drawing") 14059 public float getAlpha() { 14060 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 14061 } 14062 14063 /** 14064 * Sets the behavior for overlapping rendering for this view (see {@link 14065 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 14066 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 14067 * providing the value which is then used internally. That is, when {@link 14068 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 14069 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 14070 * instead. 14071 * 14072 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 14073 * instead of that returned by {@link #hasOverlappingRendering()}. 14074 * 14075 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 14076 */ 14077 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 14078 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 14079 if (hasOverlappingRendering) { 14080 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 14081 } else { 14082 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 14083 } 14084 } 14085 14086 /** 14087 * Returns the value for overlapping rendering that is used internally. This is either 14088 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 14089 * the return value of {@link #hasOverlappingRendering()}, otherwise. 14090 * 14091 * @return The value for overlapping rendering being used internally. 14092 */ 14093 public final boolean getHasOverlappingRendering() { 14094 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 14095 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 14096 hasOverlappingRendering(); 14097 } 14098 14099 /** 14100 * Returns whether this View has content which overlaps. 14101 * 14102 * <p>This function, intended to be overridden by specific View types, is an optimization when 14103 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 14104 * an offscreen buffer and then composited into place, which can be expensive. If the view has 14105 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 14106 * directly. An example of overlapping rendering is a TextView with a background image, such as 14107 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 14108 * ImageView with only the foreground image. The default implementation returns true; subclasses 14109 * should override if they have cases which can be optimized.</p> 14110 * 14111 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 14112 * necessitates that a View return true if it uses the methods internally without passing the 14113 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 14114 * 14115 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 14116 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 14117 * 14118 * @return true if the content in this view might overlap, false otherwise. 14119 */ 14120 @ViewDebug.ExportedProperty(category = "drawing") 14121 public boolean hasOverlappingRendering() { 14122 return true; 14123 } 14124 14125 /** 14126 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 14127 * completely transparent and 1 means the view is completely opaque. 14128 * 14129 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 14130 * can have significant performance implications, especially for large views. It is best to use 14131 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 14132 * 14133 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 14134 * strongly recommended for performance reasons to either override 14135 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 14136 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 14137 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 14138 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 14139 * of rendering cost, even for simple or small views. Starting with 14140 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 14141 * applied to the view at the rendering level.</p> 14142 * 14143 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 14144 * responsible for applying the opacity itself.</p> 14145 * 14146 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 14147 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 14148 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 14149 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 14150 * 14151 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 14152 * value will clip a View to its bounds, unless the View returns <code>false</code> from 14153 * {@link #hasOverlappingRendering}.</p> 14154 * 14155 * @param alpha The opacity of the view. 14156 * 14157 * @see #hasOverlappingRendering() 14158 * @see #setLayerType(int, android.graphics.Paint) 14159 * 14160 * @attr ref android.R.styleable#View_alpha 14161 */ 14162 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 14163 ensureTransformationInfo(); 14164 if (mTransformationInfo.mAlpha != alpha) { 14165 // Report visibility changes, which can affect children, to accessibility 14166 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 14167 notifySubtreeAccessibilityStateChangedIfNeeded(); 14168 } 14169 mTransformationInfo.mAlpha = alpha; 14170 if (onSetAlpha((int) (alpha * 255))) { 14171 mPrivateFlags |= PFLAG_ALPHA_SET; 14172 // subclass is handling alpha - don't optimize rendering cache invalidation 14173 invalidateParentCaches(); 14174 invalidate(true); 14175 } else { 14176 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14177 invalidateViewProperty(true, false); 14178 mRenderNode.setAlpha(getFinalAlpha()); 14179 } 14180 } 14181 } 14182 14183 /** 14184 * Faster version of setAlpha() which performs the same steps except there are 14185 * no calls to invalidate(). The caller of this function should perform proper invalidation 14186 * on the parent and this object. The return value indicates whether the subclass handles 14187 * alpha (the return value for onSetAlpha()). 14188 * 14189 * @param alpha The new value for the alpha property 14190 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 14191 * the new value for the alpha property is different from the old value 14192 */ 14193 boolean setAlphaNoInvalidation(float alpha) { 14194 ensureTransformationInfo(); 14195 if (mTransformationInfo.mAlpha != alpha) { 14196 mTransformationInfo.mAlpha = alpha; 14197 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 14198 if (subclassHandlesAlpha) { 14199 mPrivateFlags |= PFLAG_ALPHA_SET; 14200 return true; 14201 } else { 14202 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14203 mRenderNode.setAlpha(getFinalAlpha()); 14204 } 14205 } 14206 return false; 14207 } 14208 14209 /** 14210 * This property is hidden and intended only for use by the Fade transition, which 14211 * animates it to produce a visual translucency that does not side-effect (or get 14212 * affected by) the real alpha property. This value is composited with the other 14213 * alpha value (and the AlphaAnimation value, when that is present) to produce 14214 * a final visual translucency result, which is what is passed into the DisplayList. 14215 * 14216 * @hide 14217 */ 14218 public void setTransitionAlpha(float alpha) { 14219 ensureTransformationInfo(); 14220 if (mTransformationInfo.mTransitionAlpha != alpha) { 14221 mTransformationInfo.mTransitionAlpha = alpha; 14222 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14223 invalidateViewProperty(true, false); 14224 mRenderNode.setAlpha(getFinalAlpha()); 14225 } 14226 } 14227 14228 /** 14229 * Calculates the visual alpha of this view, which is a combination of the actual 14230 * alpha value and the transitionAlpha value (if set). 14231 */ 14232 private float getFinalAlpha() { 14233 if (mTransformationInfo != null) { 14234 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 14235 } 14236 return 1; 14237 } 14238 14239 /** 14240 * This property is hidden and intended only for use by the Fade transition, which 14241 * animates it to produce a visual translucency that does not side-effect (or get 14242 * affected by) the real alpha property. This value is composited with the other 14243 * alpha value (and the AlphaAnimation value, when that is present) to produce 14244 * a final visual translucency result, which is what is passed into the DisplayList. 14245 * 14246 * @hide 14247 */ 14248 @ViewDebug.ExportedProperty(category = "drawing") 14249 public float getTransitionAlpha() { 14250 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 14251 } 14252 14253 /** 14254 * Top position of this view relative to its parent. 14255 * 14256 * @return The top of this view, in pixels. 14257 */ 14258 @ViewDebug.CapturedViewProperty 14259 public final int getTop() { 14260 return mTop; 14261 } 14262 14263 /** 14264 * Sets the top position of this view relative to its parent. This method is meant to be called 14265 * by the layout system and should not generally be called otherwise, because the property 14266 * may be changed at any time by the layout. 14267 * 14268 * @param top The top of this view, in pixels. 14269 */ 14270 public final void setTop(int top) { 14271 if (top != mTop) { 14272 final boolean matrixIsIdentity = hasIdentityMatrix(); 14273 if (matrixIsIdentity) { 14274 if (mAttachInfo != null) { 14275 int minTop; 14276 int yLoc; 14277 if (top < mTop) { 14278 minTop = top; 14279 yLoc = top - mTop; 14280 } else { 14281 minTop = mTop; 14282 yLoc = 0; 14283 } 14284 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 14285 } 14286 } else { 14287 // Double-invalidation is necessary to capture view's old and new areas 14288 invalidate(true); 14289 } 14290 14291 int width = mRight - mLeft; 14292 int oldHeight = mBottom - mTop; 14293 14294 mTop = top; 14295 mRenderNode.setTop(mTop); 14296 14297 sizeChange(width, mBottom - mTop, width, oldHeight); 14298 14299 if (!matrixIsIdentity) { 14300 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14301 invalidate(true); 14302 } 14303 mBackgroundSizeChanged = true; 14304 mDefaultFocusHighlightSizeChanged = true; 14305 if (mForegroundInfo != null) { 14306 mForegroundInfo.mBoundsChanged = true; 14307 } 14308 invalidateParentIfNeeded(); 14309 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14310 // View was rejected last time it was drawn by its parent; this may have changed 14311 invalidateParentIfNeeded(); 14312 } 14313 } 14314 } 14315 14316 /** 14317 * Bottom position of this view relative to its parent. 14318 * 14319 * @return The bottom of this view, in pixels. 14320 */ 14321 @ViewDebug.CapturedViewProperty 14322 public final int getBottom() { 14323 return mBottom; 14324 } 14325 14326 /** 14327 * True if this view has changed since the last time being drawn. 14328 * 14329 * @return The dirty state of this view. 14330 */ 14331 public boolean isDirty() { 14332 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 14333 } 14334 14335 /** 14336 * Sets the bottom position of this view relative to its parent. This method is meant to be 14337 * called by the layout system and should not generally be called otherwise, because the 14338 * property may be changed at any time by the layout. 14339 * 14340 * @param bottom The bottom of this view, in pixels. 14341 */ 14342 public final void setBottom(int bottom) { 14343 if (bottom != mBottom) { 14344 final boolean matrixIsIdentity = hasIdentityMatrix(); 14345 if (matrixIsIdentity) { 14346 if (mAttachInfo != null) { 14347 int maxBottom; 14348 if (bottom < mBottom) { 14349 maxBottom = mBottom; 14350 } else { 14351 maxBottom = bottom; 14352 } 14353 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 14354 } 14355 } else { 14356 // Double-invalidation is necessary to capture view's old and new areas 14357 invalidate(true); 14358 } 14359 14360 int width = mRight - mLeft; 14361 int oldHeight = mBottom - mTop; 14362 14363 mBottom = bottom; 14364 mRenderNode.setBottom(mBottom); 14365 14366 sizeChange(width, mBottom - mTop, width, oldHeight); 14367 14368 if (!matrixIsIdentity) { 14369 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14370 invalidate(true); 14371 } 14372 mBackgroundSizeChanged = true; 14373 mDefaultFocusHighlightSizeChanged = true; 14374 if (mForegroundInfo != null) { 14375 mForegroundInfo.mBoundsChanged = true; 14376 } 14377 invalidateParentIfNeeded(); 14378 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14379 // View was rejected last time it was drawn by its parent; this may have changed 14380 invalidateParentIfNeeded(); 14381 } 14382 } 14383 } 14384 14385 /** 14386 * Left position of this view relative to its parent. 14387 * 14388 * @return The left edge of this view, in pixels. 14389 */ 14390 @ViewDebug.CapturedViewProperty 14391 public final int getLeft() { 14392 return mLeft; 14393 } 14394 14395 /** 14396 * Sets the left position of this view relative to its parent. This method is meant to be called 14397 * by the layout system and should not generally be called otherwise, because the property 14398 * may be changed at any time by the layout. 14399 * 14400 * @param left The left of this view, in pixels. 14401 */ 14402 public final void setLeft(int left) { 14403 if (left != mLeft) { 14404 final boolean matrixIsIdentity = hasIdentityMatrix(); 14405 if (matrixIsIdentity) { 14406 if (mAttachInfo != null) { 14407 int minLeft; 14408 int xLoc; 14409 if (left < mLeft) { 14410 minLeft = left; 14411 xLoc = left - mLeft; 14412 } else { 14413 minLeft = mLeft; 14414 xLoc = 0; 14415 } 14416 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 14417 } 14418 } else { 14419 // Double-invalidation is necessary to capture view's old and new areas 14420 invalidate(true); 14421 } 14422 14423 int oldWidth = mRight - mLeft; 14424 int height = mBottom - mTop; 14425 14426 mLeft = left; 14427 mRenderNode.setLeft(left); 14428 14429 sizeChange(mRight - mLeft, height, oldWidth, height); 14430 14431 if (!matrixIsIdentity) { 14432 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14433 invalidate(true); 14434 } 14435 mBackgroundSizeChanged = true; 14436 mDefaultFocusHighlightSizeChanged = true; 14437 if (mForegroundInfo != null) { 14438 mForegroundInfo.mBoundsChanged = true; 14439 } 14440 invalidateParentIfNeeded(); 14441 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14442 // View was rejected last time it was drawn by its parent; this may have changed 14443 invalidateParentIfNeeded(); 14444 } 14445 } 14446 } 14447 14448 /** 14449 * Right position of this view relative to its parent. 14450 * 14451 * @return The right edge of this view, in pixels. 14452 */ 14453 @ViewDebug.CapturedViewProperty 14454 public final int getRight() { 14455 return mRight; 14456 } 14457 14458 /** 14459 * Sets the right position of this view relative to its parent. This method is meant to be called 14460 * by the layout system and should not generally be called otherwise, because the property 14461 * may be changed at any time by the layout. 14462 * 14463 * @param right The right of this view, in pixels. 14464 */ 14465 public final void setRight(int right) { 14466 if (right != mRight) { 14467 final boolean matrixIsIdentity = hasIdentityMatrix(); 14468 if (matrixIsIdentity) { 14469 if (mAttachInfo != null) { 14470 int maxRight; 14471 if (right < mRight) { 14472 maxRight = mRight; 14473 } else { 14474 maxRight = right; 14475 } 14476 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 14477 } 14478 } else { 14479 // Double-invalidation is necessary to capture view's old and new areas 14480 invalidate(true); 14481 } 14482 14483 int oldWidth = mRight - mLeft; 14484 int height = mBottom - mTop; 14485 14486 mRight = right; 14487 mRenderNode.setRight(mRight); 14488 14489 sizeChange(mRight - mLeft, height, oldWidth, height); 14490 14491 if (!matrixIsIdentity) { 14492 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14493 invalidate(true); 14494 } 14495 mBackgroundSizeChanged = true; 14496 mDefaultFocusHighlightSizeChanged = true; 14497 if (mForegroundInfo != null) { 14498 mForegroundInfo.mBoundsChanged = true; 14499 } 14500 invalidateParentIfNeeded(); 14501 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14502 // View was rejected last time it was drawn by its parent; this may have changed 14503 invalidateParentIfNeeded(); 14504 } 14505 } 14506 } 14507 14508 /** 14509 * The visual x position of this view, in pixels. This is equivalent to the 14510 * {@link #setTranslationX(float) translationX} property plus the current 14511 * {@link #getLeft() left} property. 14512 * 14513 * @return The visual x position of this view, in pixels. 14514 */ 14515 @ViewDebug.ExportedProperty(category = "drawing") 14516 public float getX() { 14517 return mLeft + getTranslationX(); 14518 } 14519 14520 /** 14521 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 14522 * {@link #setTranslationX(float) translationX} property to be the difference between 14523 * the x value passed in and the current {@link #getLeft() left} property. 14524 * 14525 * @param x The visual x position of this view, in pixels. 14526 */ 14527 public void setX(float x) { 14528 setTranslationX(x - mLeft); 14529 } 14530 14531 /** 14532 * The visual y position of this view, in pixels. This is equivalent to the 14533 * {@link #setTranslationY(float) translationY} property plus the current 14534 * {@link #getTop() top} property. 14535 * 14536 * @return The visual y position of this view, in pixels. 14537 */ 14538 @ViewDebug.ExportedProperty(category = "drawing") 14539 public float getY() { 14540 return mTop + getTranslationY(); 14541 } 14542 14543 /** 14544 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 14545 * {@link #setTranslationY(float) translationY} property to be the difference between 14546 * the y value passed in and the current {@link #getTop() top} property. 14547 * 14548 * @param y The visual y position of this view, in pixels. 14549 */ 14550 public void setY(float y) { 14551 setTranslationY(y - mTop); 14552 } 14553 14554 /** 14555 * The visual z position of this view, in pixels. This is equivalent to the 14556 * {@link #setTranslationZ(float) translationZ} property plus the current 14557 * {@link #getElevation() elevation} property. 14558 * 14559 * @return The visual z position of this view, in pixels. 14560 */ 14561 @ViewDebug.ExportedProperty(category = "drawing") 14562 public float getZ() { 14563 return getElevation() + getTranslationZ(); 14564 } 14565 14566 /** 14567 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 14568 * {@link #setTranslationZ(float) translationZ} property to be the difference between 14569 * the x value passed in and the current {@link #getElevation() elevation} property. 14570 * 14571 * @param z The visual z position of this view, in pixels. 14572 */ 14573 public void setZ(float z) { 14574 setTranslationZ(z - getElevation()); 14575 } 14576 14577 /** 14578 * The base elevation of this view relative to its parent, in pixels. 14579 * 14580 * @return The base depth position of the view, in pixels. 14581 */ 14582 @ViewDebug.ExportedProperty(category = "drawing") 14583 public float getElevation() { 14584 return mRenderNode.getElevation(); 14585 } 14586 14587 /** 14588 * Sets the base elevation of this view, in pixels. 14589 * 14590 * @attr ref android.R.styleable#View_elevation 14591 */ 14592 public void setElevation(float elevation) { 14593 if (elevation != getElevation()) { 14594 invalidateViewProperty(true, false); 14595 mRenderNode.setElevation(elevation); 14596 invalidateViewProperty(false, true); 14597 14598 invalidateParentIfNeededAndWasQuickRejected(); 14599 } 14600 } 14601 14602 /** 14603 * The horizontal location of this view relative to its {@link #getLeft() left} position. 14604 * This position is post-layout, in addition to wherever the object's 14605 * layout placed it. 14606 * 14607 * @return The horizontal position of this view relative to its left position, in pixels. 14608 */ 14609 @ViewDebug.ExportedProperty(category = "drawing") 14610 public float getTranslationX() { 14611 return mRenderNode.getTranslationX(); 14612 } 14613 14614 /** 14615 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 14616 * This effectively positions the object post-layout, in addition to wherever the object's 14617 * layout placed it. 14618 * 14619 * @param translationX The horizontal position of this view relative to its left position, 14620 * in pixels. 14621 * 14622 * @attr ref android.R.styleable#View_translationX 14623 */ 14624 public void setTranslationX(float translationX) { 14625 if (translationX != getTranslationX()) { 14626 invalidateViewProperty(true, false); 14627 mRenderNode.setTranslationX(translationX); 14628 invalidateViewProperty(false, true); 14629 14630 invalidateParentIfNeededAndWasQuickRejected(); 14631 notifySubtreeAccessibilityStateChangedIfNeeded(); 14632 } 14633 } 14634 14635 /** 14636 * The vertical location of this view relative to its {@link #getTop() top} position. 14637 * This position is post-layout, in addition to wherever the object's 14638 * layout placed it. 14639 * 14640 * @return The vertical position of this view relative to its top position, 14641 * in pixels. 14642 */ 14643 @ViewDebug.ExportedProperty(category = "drawing") 14644 public float getTranslationY() { 14645 return mRenderNode.getTranslationY(); 14646 } 14647 14648 /** 14649 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 14650 * This effectively positions the object post-layout, in addition to wherever the object's 14651 * layout placed it. 14652 * 14653 * @param translationY The vertical position of this view relative to its top position, 14654 * in pixels. 14655 * 14656 * @attr ref android.R.styleable#View_translationY 14657 */ 14658 public void setTranslationY(float translationY) { 14659 if (translationY != getTranslationY()) { 14660 invalidateViewProperty(true, false); 14661 mRenderNode.setTranslationY(translationY); 14662 invalidateViewProperty(false, true); 14663 14664 invalidateParentIfNeededAndWasQuickRejected(); 14665 notifySubtreeAccessibilityStateChangedIfNeeded(); 14666 } 14667 } 14668 14669 /** 14670 * The depth location of this view relative to its {@link #getElevation() elevation}. 14671 * 14672 * @return The depth of this view relative to its elevation. 14673 */ 14674 @ViewDebug.ExportedProperty(category = "drawing") 14675 public float getTranslationZ() { 14676 return mRenderNode.getTranslationZ(); 14677 } 14678 14679 /** 14680 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 14681 * 14682 * @attr ref android.R.styleable#View_translationZ 14683 */ 14684 public void setTranslationZ(float translationZ) { 14685 if (translationZ != getTranslationZ()) { 14686 invalidateViewProperty(true, false); 14687 mRenderNode.setTranslationZ(translationZ); 14688 invalidateViewProperty(false, true); 14689 14690 invalidateParentIfNeededAndWasQuickRejected(); 14691 } 14692 } 14693 14694 /** @hide */ 14695 public void setAnimationMatrix(Matrix matrix) { 14696 invalidateViewProperty(true, false); 14697 mRenderNode.setAnimationMatrix(matrix); 14698 invalidateViewProperty(false, true); 14699 14700 invalidateParentIfNeededAndWasQuickRejected(); 14701 } 14702 14703 /** 14704 * Returns the current StateListAnimator if exists. 14705 * 14706 * @return StateListAnimator or null if it does not exists 14707 * @see #setStateListAnimator(android.animation.StateListAnimator) 14708 */ 14709 public StateListAnimator getStateListAnimator() { 14710 return mStateListAnimator; 14711 } 14712 14713 /** 14714 * Attaches the provided StateListAnimator to this View. 14715 * <p> 14716 * Any previously attached StateListAnimator will be detached. 14717 * 14718 * @param stateListAnimator The StateListAnimator to update the view 14719 * @see android.animation.StateListAnimator 14720 */ 14721 public void setStateListAnimator(StateListAnimator stateListAnimator) { 14722 if (mStateListAnimator == stateListAnimator) { 14723 return; 14724 } 14725 if (mStateListAnimator != null) { 14726 mStateListAnimator.setTarget(null); 14727 } 14728 mStateListAnimator = stateListAnimator; 14729 if (stateListAnimator != null) { 14730 stateListAnimator.setTarget(this); 14731 if (isAttachedToWindow()) { 14732 stateListAnimator.setState(getDrawableState()); 14733 } 14734 } 14735 } 14736 14737 /** 14738 * Returns whether the Outline should be used to clip the contents of the View. 14739 * <p> 14740 * Note that this flag will only be respected if the View's Outline returns true from 14741 * {@link Outline#canClip()}. 14742 * 14743 * @see #setOutlineProvider(ViewOutlineProvider) 14744 * @see #setClipToOutline(boolean) 14745 */ 14746 public final boolean getClipToOutline() { 14747 return mRenderNode.getClipToOutline(); 14748 } 14749 14750 /** 14751 * Sets whether the View's Outline should be used to clip the contents of the View. 14752 * <p> 14753 * Only a single non-rectangular clip can be applied on a View at any time. 14754 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 14755 * circular reveal} animation take priority over Outline clipping, and 14756 * child Outline clipping takes priority over Outline clipping done by a 14757 * parent. 14758 * <p> 14759 * Note that this flag will only be respected if the View's Outline returns true from 14760 * {@link Outline#canClip()}. 14761 * 14762 * @see #setOutlineProvider(ViewOutlineProvider) 14763 * @see #getClipToOutline() 14764 */ 14765 public void setClipToOutline(boolean clipToOutline) { 14766 damageInParent(); 14767 if (getClipToOutline() != clipToOutline) { 14768 mRenderNode.setClipToOutline(clipToOutline); 14769 } 14770 } 14771 14772 // correspond to the enum values of View_outlineProvider 14773 private static final int PROVIDER_BACKGROUND = 0; 14774 private static final int PROVIDER_NONE = 1; 14775 private static final int PROVIDER_BOUNDS = 2; 14776 private static final int PROVIDER_PADDED_BOUNDS = 3; 14777 private void setOutlineProviderFromAttribute(int providerInt) { 14778 switch (providerInt) { 14779 case PROVIDER_BACKGROUND: 14780 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 14781 break; 14782 case PROVIDER_NONE: 14783 setOutlineProvider(null); 14784 break; 14785 case PROVIDER_BOUNDS: 14786 setOutlineProvider(ViewOutlineProvider.BOUNDS); 14787 break; 14788 case PROVIDER_PADDED_BOUNDS: 14789 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 14790 break; 14791 } 14792 } 14793 14794 /** 14795 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 14796 * the shape of the shadow it casts, and enables outline clipping. 14797 * <p> 14798 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 14799 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 14800 * outline provider with this method allows this behavior to be overridden. 14801 * <p> 14802 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 14803 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 14804 * <p> 14805 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 14806 * 14807 * @see #setClipToOutline(boolean) 14808 * @see #getClipToOutline() 14809 * @see #getOutlineProvider() 14810 */ 14811 public void setOutlineProvider(ViewOutlineProvider provider) { 14812 mOutlineProvider = provider; 14813 invalidateOutline(); 14814 } 14815 14816 /** 14817 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 14818 * that defines the shape of the shadow it casts, and enables outline clipping. 14819 * 14820 * @see #setOutlineProvider(ViewOutlineProvider) 14821 */ 14822 public ViewOutlineProvider getOutlineProvider() { 14823 return mOutlineProvider; 14824 } 14825 14826 /** 14827 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 14828 * 14829 * @see #setOutlineProvider(ViewOutlineProvider) 14830 */ 14831 public void invalidateOutline() { 14832 rebuildOutline(); 14833 14834 notifySubtreeAccessibilityStateChangedIfNeeded(); 14835 invalidateViewProperty(false, false); 14836 } 14837 14838 /** 14839 * Internal version of {@link #invalidateOutline()} which invalidates the 14840 * outline without invalidating the view itself. This is intended to be called from 14841 * within methods in the View class itself which are the result of the view being 14842 * invalidated already. For example, when we are drawing the background of a View, 14843 * we invalidate the outline in case it changed in the meantime, but we do not 14844 * need to invalidate the view because we're already drawing the background as part 14845 * of drawing the view in response to an earlier invalidation of the view. 14846 */ 14847 private void rebuildOutline() { 14848 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 14849 if (mAttachInfo == null) return; 14850 14851 if (mOutlineProvider == null) { 14852 // no provider, remove outline 14853 mRenderNode.setOutline(null); 14854 } else { 14855 final Outline outline = mAttachInfo.mTmpOutline; 14856 outline.setEmpty(); 14857 outline.setAlpha(1.0f); 14858 14859 mOutlineProvider.getOutline(this, outline); 14860 mRenderNode.setOutline(outline); 14861 } 14862 } 14863 14864 /** 14865 * HierarchyViewer only 14866 * 14867 * @hide 14868 */ 14869 @ViewDebug.ExportedProperty(category = "drawing") 14870 public boolean hasShadow() { 14871 return mRenderNode.hasShadow(); 14872 } 14873 14874 14875 /** @hide */ 14876 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 14877 mRenderNode.setRevealClip(shouldClip, x, y, radius); 14878 invalidateViewProperty(false, false); 14879 } 14880 14881 /** 14882 * Hit rectangle in parent's coordinates 14883 * 14884 * @param outRect The hit rectangle of the view. 14885 */ 14886 public void getHitRect(Rect outRect) { 14887 if (hasIdentityMatrix() || mAttachInfo == null) { 14888 outRect.set(mLeft, mTop, mRight, mBottom); 14889 } else { 14890 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 14891 tmpRect.set(0, 0, getWidth(), getHeight()); 14892 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 14893 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 14894 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 14895 } 14896 } 14897 14898 /** 14899 * Determines whether the given point, in local coordinates is inside the view. 14900 */ 14901 /*package*/ final boolean pointInView(float localX, float localY) { 14902 return pointInView(localX, localY, 0); 14903 } 14904 14905 /** 14906 * Utility method to determine whether the given point, in local coordinates, 14907 * is inside the view, where the area of the view is expanded by the slop factor. 14908 * This method is called while processing touch-move events to determine if the event 14909 * is still within the view. 14910 * 14911 * @hide 14912 */ 14913 public boolean pointInView(float localX, float localY, float slop) { 14914 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 14915 localY < ((mBottom - mTop) + slop); 14916 } 14917 14918 /** 14919 * When a view has focus and the user navigates away from it, the next view is searched for 14920 * starting from the rectangle filled in by this method. 14921 * 14922 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 14923 * of the view. However, if your view maintains some idea of internal selection, 14924 * such as a cursor, or a selected row or column, you should override this method and 14925 * fill in a more specific rectangle. 14926 * 14927 * @param r The rectangle to fill in, in this view's coordinates. 14928 */ 14929 public void getFocusedRect(Rect r) { 14930 getDrawingRect(r); 14931 } 14932 14933 /** 14934 * If some part of this view is not clipped by any of its parents, then 14935 * return that area in r in global (root) coordinates. To convert r to local 14936 * coordinates (without taking possible View rotations into account), offset 14937 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 14938 * If the view is completely clipped or translated out, return false. 14939 * 14940 * @param r If true is returned, r holds the global coordinates of the 14941 * visible portion of this view. 14942 * @param globalOffset If true is returned, globalOffset holds the dx,dy 14943 * between this view and its root. globalOffet may be null. 14944 * @return true if r is non-empty (i.e. part of the view is visible at the 14945 * root level. 14946 */ 14947 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 14948 int width = mRight - mLeft; 14949 int height = mBottom - mTop; 14950 if (width > 0 && height > 0) { 14951 r.set(0, 0, width, height); 14952 if (globalOffset != null) { 14953 globalOffset.set(-mScrollX, -mScrollY); 14954 } 14955 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 14956 } 14957 return false; 14958 } 14959 14960 public final boolean getGlobalVisibleRect(Rect r) { 14961 return getGlobalVisibleRect(r, null); 14962 } 14963 14964 public final boolean getLocalVisibleRect(Rect r) { 14965 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 14966 if (getGlobalVisibleRect(r, offset)) { 14967 r.offset(-offset.x, -offset.y); // make r local 14968 return true; 14969 } 14970 return false; 14971 } 14972 14973 /** 14974 * Offset this view's vertical location by the specified number of pixels. 14975 * 14976 * @param offset the number of pixels to offset the view by 14977 */ 14978 public void offsetTopAndBottom(int offset) { 14979 if (offset != 0) { 14980 final boolean matrixIsIdentity = hasIdentityMatrix(); 14981 if (matrixIsIdentity) { 14982 if (isHardwareAccelerated()) { 14983 invalidateViewProperty(false, false); 14984 } else { 14985 final ViewParent p = mParent; 14986 if (p != null && mAttachInfo != null) { 14987 final Rect r = mAttachInfo.mTmpInvalRect; 14988 int minTop; 14989 int maxBottom; 14990 int yLoc; 14991 if (offset < 0) { 14992 minTop = mTop + offset; 14993 maxBottom = mBottom; 14994 yLoc = offset; 14995 } else { 14996 minTop = mTop; 14997 maxBottom = mBottom + offset; 14998 yLoc = 0; 14999 } 15000 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 15001 p.invalidateChild(this, r); 15002 } 15003 } 15004 } else { 15005 invalidateViewProperty(false, false); 15006 } 15007 15008 mTop += offset; 15009 mBottom += offset; 15010 mRenderNode.offsetTopAndBottom(offset); 15011 if (isHardwareAccelerated()) { 15012 invalidateViewProperty(false, false); 15013 invalidateParentIfNeededAndWasQuickRejected(); 15014 } else { 15015 if (!matrixIsIdentity) { 15016 invalidateViewProperty(false, true); 15017 } 15018 invalidateParentIfNeeded(); 15019 } 15020 notifySubtreeAccessibilityStateChangedIfNeeded(); 15021 } 15022 } 15023 15024 /** 15025 * Offset this view's horizontal location by the specified amount of pixels. 15026 * 15027 * @param offset the number of pixels to offset the view by 15028 */ 15029 public void offsetLeftAndRight(int offset) { 15030 if (offset != 0) { 15031 final boolean matrixIsIdentity = hasIdentityMatrix(); 15032 if (matrixIsIdentity) { 15033 if (isHardwareAccelerated()) { 15034 invalidateViewProperty(false, false); 15035 } else { 15036 final ViewParent p = mParent; 15037 if (p != null && mAttachInfo != null) { 15038 final Rect r = mAttachInfo.mTmpInvalRect; 15039 int minLeft; 15040 int maxRight; 15041 if (offset < 0) { 15042 minLeft = mLeft + offset; 15043 maxRight = mRight; 15044 } else { 15045 minLeft = mLeft; 15046 maxRight = mRight + offset; 15047 } 15048 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 15049 p.invalidateChild(this, r); 15050 } 15051 } 15052 } else { 15053 invalidateViewProperty(false, false); 15054 } 15055 15056 mLeft += offset; 15057 mRight += offset; 15058 mRenderNode.offsetLeftAndRight(offset); 15059 if (isHardwareAccelerated()) { 15060 invalidateViewProperty(false, false); 15061 invalidateParentIfNeededAndWasQuickRejected(); 15062 } else { 15063 if (!matrixIsIdentity) { 15064 invalidateViewProperty(false, true); 15065 } 15066 invalidateParentIfNeeded(); 15067 } 15068 notifySubtreeAccessibilityStateChangedIfNeeded(); 15069 } 15070 } 15071 15072 /** 15073 * Get the LayoutParams associated with this view. All views should have 15074 * layout parameters. These supply parameters to the <i>parent</i> of this 15075 * view specifying how it should be arranged. There are many subclasses of 15076 * ViewGroup.LayoutParams, and these correspond to the different subclasses 15077 * of ViewGroup that are responsible for arranging their children. 15078 * 15079 * This method may return null if this View is not attached to a parent 15080 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 15081 * was not invoked successfully. When a View is attached to a parent 15082 * ViewGroup, this method must not return null. 15083 * 15084 * @return The LayoutParams associated with this view, or null if no 15085 * parameters have been set yet 15086 */ 15087 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 15088 public ViewGroup.LayoutParams getLayoutParams() { 15089 return mLayoutParams; 15090 } 15091 15092 /** 15093 * Set the layout parameters associated with this view. These supply 15094 * parameters to the <i>parent</i> of this view specifying how it should be 15095 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 15096 * correspond to the different subclasses of ViewGroup that are responsible 15097 * for arranging their children. 15098 * 15099 * @param params The layout parameters for this view, cannot be null 15100 */ 15101 public void setLayoutParams(ViewGroup.LayoutParams params) { 15102 if (params == null) { 15103 throw new NullPointerException("Layout parameters cannot be null"); 15104 } 15105 mLayoutParams = params; 15106 resolveLayoutParams(); 15107 if (mParent instanceof ViewGroup) { 15108 ((ViewGroup) mParent).onSetLayoutParams(this, params); 15109 } 15110 requestLayout(); 15111 } 15112 15113 /** 15114 * Resolve the layout parameters depending on the resolved layout direction 15115 * 15116 * @hide 15117 */ 15118 public void resolveLayoutParams() { 15119 if (mLayoutParams != null) { 15120 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 15121 } 15122 } 15123 15124 /** 15125 * Set the scrolled position of your view. This will cause a call to 15126 * {@link #onScrollChanged(int, int, int, int)} and the view will be 15127 * invalidated. 15128 * @param x the x position to scroll to 15129 * @param y the y position to scroll to 15130 */ 15131 public void scrollTo(int x, int y) { 15132 if (mScrollX != x || mScrollY != y) { 15133 int oldX = mScrollX; 15134 int oldY = mScrollY; 15135 mScrollX = x; 15136 mScrollY = y; 15137 invalidateParentCaches(); 15138 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 15139 if (!awakenScrollBars()) { 15140 postInvalidateOnAnimation(); 15141 } 15142 } 15143 } 15144 15145 /** 15146 * Move the scrolled position of your view. This will cause a call to 15147 * {@link #onScrollChanged(int, int, int, int)} and the view will be 15148 * invalidated. 15149 * @param x the amount of pixels to scroll by horizontally 15150 * @param y the amount of pixels to scroll by vertically 15151 */ 15152 public void scrollBy(int x, int y) { 15153 scrollTo(mScrollX + x, mScrollY + y); 15154 } 15155 15156 /** 15157 * <p>Trigger the scrollbars to draw. When invoked this method starts an 15158 * animation to fade the scrollbars out after a default delay. If a subclass 15159 * provides animated scrolling, the start delay should equal the duration 15160 * of the scrolling animation.</p> 15161 * 15162 * <p>The animation starts only if at least one of the scrollbars is 15163 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 15164 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15165 * this method returns true, and false otherwise. If the animation is 15166 * started, this method calls {@link #invalidate()}; in that case the 15167 * caller should not call {@link #invalidate()}.</p> 15168 * 15169 * <p>This method should be invoked every time a subclass directly updates 15170 * the scroll parameters.</p> 15171 * 15172 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 15173 * and {@link #scrollTo(int, int)}.</p> 15174 * 15175 * @return true if the animation is played, false otherwise 15176 * 15177 * @see #awakenScrollBars(int) 15178 * @see #scrollBy(int, int) 15179 * @see #scrollTo(int, int) 15180 * @see #isHorizontalScrollBarEnabled() 15181 * @see #isVerticalScrollBarEnabled() 15182 * @see #setHorizontalScrollBarEnabled(boolean) 15183 * @see #setVerticalScrollBarEnabled(boolean) 15184 */ 15185 protected boolean awakenScrollBars() { 15186 return mScrollCache != null && 15187 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 15188 } 15189 15190 /** 15191 * Trigger the scrollbars to draw. 15192 * This method differs from awakenScrollBars() only in its default duration. 15193 * initialAwakenScrollBars() will show the scroll bars for longer than 15194 * usual to give the user more of a chance to notice them. 15195 * 15196 * @return true if the animation is played, false otherwise. 15197 */ 15198 private boolean initialAwakenScrollBars() { 15199 return mScrollCache != null && 15200 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 15201 } 15202 15203 /** 15204 * <p> 15205 * Trigger the scrollbars to draw. When invoked this method starts an 15206 * animation to fade the scrollbars out after a fixed delay. If a subclass 15207 * provides animated scrolling, the start delay should equal the duration of 15208 * the scrolling animation. 15209 * </p> 15210 * 15211 * <p> 15212 * The animation starts only if at least one of the scrollbars is enabled, 15213 * as specified by {@link #isHorizontalScrollBarEnabled()} and 15214 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15215 * this method returns true, and false otherwise. If the animation is 15216 * started, this method calls {@link #invalidate()}; in that case the caller 15217 * should not call {@link #invalidate()}. 15218 * </p> 15219 * 15220 * <p> 15221 * This method should be invoked every time a subclass directly updates the 15222 * scroll parameters. 15223 * </p> 15224 * 15225 * @param startDelay the delay, in milliseconds, after which the animation 15226 * should start; when the delay is 0, the animation starts 15227 * immediately 15228 * @return true if the animation is played, false otherwise 15229 * 15230 * @see #scrollBy(int, int) 15231 * @see #scrollTo(int, int) 15232 * @see #isHorizontalScrollBarEnabled() 15233 * @see #isVerticalScrollBarEnabled() 15234 * @see #setHorizontalScrollBarEnabled(boolean) 15235 * @see #setVerticalScrollBarEnabled(boolean) 15236 */ 15237 protected boolean awakenScrollBars(int startDelay) { 15238 return awakenScrollBars(startDelay, true); 15239 } 15240 15241 /** 15242 * <p> 15243 * Trigger the scrollbars to draw. When invoked this method starts an 15244 * animation to fade the scrollbars out after a fixed delay. If a subclass 15245 * provides animated scrolling, the start delay should equal the duration of 15246 * the scrolling animation. 15247 * </p> 15248 * 15249 * <p> 15250 * The animation starts only if at least one of the scrollbars is enabled, 15251 * as specified by {@link #isHorizontalScrollBarEnabled()} and 15252 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15253 * this method returns true, and false otherwise. If the animation is 15254 * started, this method calls {@link #invalidate()} if the invalidate parameter 15255 * is set to true; in that case the caller 15256 * should not call {@link #invalidate()}. 15257 * </p> 15258 * 15259 * <p> 15260 * This method should be invoked every time a subclass directly updates the 15261 * scroll parameters. 15262 * </p> 15263 * 15264 * @param startDelay the delay, in milliseconds, after which the animation 15265 * should start; when the delay is 0, the animation starts 15266 * immediately 15267 * 15268 * @param invalidate Whether this method should call invalidate 15269 * 15270 * @return true if the animation is played, false otherwise 15271 * 15272 * @see #scrollBy(int, int) 15273 * @see #scrollTo(int, int) 15274 * @see #isHorizontalScrollBarEnabled() 15275 * @see #isVerticalScrollBarEnabled() 15276 * @see #setHorizontalScrollBarEnabled(boolean) 15277 * @see #setVerticalScrollBarEnabled(boolean) 15278 */ 15279 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 15280 final ScrollabilityCache scrollCache = mScrollCache; 15281 15282 if (scrollCache == null || !scrollCache.fadeScrollBars) { 15283 return false; 15284 } 15285 15286 if (scrollCache.scrollBar == null) { 15287 scrollCache.scrollBar = new ScrollBarDrawable(); 15288 scrollCache.scrollBar.setState(getDrawableState()); 15289 scrollCache.scrollBar.setCallback(this); 15290 } 15291 15292 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 15293 15294 if (invalidate) { 15295 // Invalidate to show the scrollbars 15296 postInvalidateOnAnimation(); 15297 } 15298 15299 if (scrollCache.state == ScrollabilityCache.OFF) { 15300 // FIXME: this is copied from WindowManagerService. 15301 // We should get this value from the system when it 15302 // is possible to do so. 15303 final int KEY_REPEAT_FIRST_DELAY = 750; 15304 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 15305 } 15306 15307 // Tell mScrollCache when we should start fading. This may 15308 // extend the fade start time if one was already scheduled 15309 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 15310 scrollCache.fadeStartTime = fadeStartTime; 15311 scrollCache.state = ScrollabilityCache.ON; 15312 15313 // Schedule our fader to run, unscheduling any old ones first 15314 if (mAttachInfo != null) { 15315 mAttachInfo.mHandler.removeCallbacks(scrollCache); 15316 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 15317 } 15318 15319 return true; 15320 } 15321 15322 return false; 15323 } 15324 15325 /** 15326 * Do not invalidate views which are not visible and which are not running an animation. They 15327 * will not get drawn and they should not set dirty flags as if they will be drawn 15328 */ 15329 private boolean skipInvalidate() { 15330 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 15331 (!(mParent instanceof ViewGroup) || 15332 !((ViewGroup) mParent).isViewTransitioning(this)); 15333 } 15334 15335 /** 15336 * Mark the area defined by dirty as needing to be drawn. If the view is 15337 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 15338 * point in the future. 15339 * <p> 15340 * This must be called from a UI thread. To call from a non-UI thread, call 15341 * {@link #postInvalidate()}. 15342 * <p> 15343 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 15344 * {@code dirty}. 15345 * 15346 * @param dirty the rectangle representing the bounds of the dirty region 15347 */ 15348 public void invalidate(Rect dirty) { 15349 final int scrollX = mScrollX; 15350 final int scrollY = mScrollY; 15351 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 15352 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 15353 } 15354 15355 /** 15356 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 15357 * coordinates of the dirty rect are relative to the view. If the view is 15358 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 15359 * point in the future. 15360 * <p> 15361 * This must be called from a UI thread. To call from a non-UI thread, call 15362 * {@link #postInvalidate()}. 15363 * 15364 * @param l the left position of the dirty region 15365 * @param t the top position of the dirty region 15366 * @param r the right position of the dirty region 15367 * @param b the bottom position of the dirty region 15368 */ 15369 public void invalidate(int l, int t, int r, int b) { 15370 final int scrollX = mScrollX; 15371 final int scrollY = mScrollY; 15372 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 15373 } 15374 15375 /** 15376 * Invalidate the whole view. If the view is visible, 15377 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 15378 * the future. 15379 * <p> 15380 * This must be called from a UI thread. To call from a non-UI thread, call 15381 * {@link #postInvalidate()}. 15382 */ 15383 public void invalidate() { 15384 invalidate(true); 15385 } 15386 15387 /** 15388 * This is where the invalidate() work actually happens. A full invalidate() 15389 * causes the drawing cache to be invalidated, but this function can be 15390 * called with invalidateCache set to false to skip that invalidation step 15391 * for cases that do not need it (for example, a component that remains at 15392 * the same dimensions with the same content). 15393 * 15394 * @param invalidateCache Whether the drawing cache for this view should be 15395 * invalidated as well. This is usually true for a full 15396 * invalidate, but may be set to false if the View's contents or 15397 * dimensions have not changed. 15398 * @hide 15399 */ 15400 public void invalidate(boolean invalidateCache) { 15401 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 15402 } 15403 15404 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 15405 boolean fullInvalidate) { 15406 if (mGhostView != null) { 15407 mGhostView.invalidate(true); 15408 return; 15409 } 15410 15411 if (skipInvalidate()) { 15412 return; 15413 } 15414 15415 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 15416 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 15417 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 15418 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 15419 if (fullInvalidate) { 15420 mLastIsOpaque = isOpaque(); 15421 mPrivateFlags &= ~PFLAG_DRAWN; 15422 } 15423 15424 mPrivateFlags |= PFLAG_DIRTY; 15425 15426 if (invalidateCache) { 15427 mPrivateFlags |= PFLAG_INVALIDATED; 15428 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 15429 } 15430 15431 // Propagate the damage rectangle to the parent view. 15432 final AttachInfo ai = mAttachInfo; 15433 final ViewParent p = mParent; 15434 if (p != null && ai != null && l < r && t < b) { 15435 final Rect damage = ai.mTmpInvalRect; 15436 damage.set(l, t, r, b); 15437 p.invalidateChild(this, damage); 15438 } 15439 15440 // Damage the entire projection receiver, if necessary. 15441 if (mBackground != null && mBackground.isProjected()) { 15442 final View receiver = getProjectionReceiver(); 15443 if (receiver != null) { 15444 receiver.damageInParent(); 15445 } 15446 } 15447 } 15448 } 15449 15450 /** 15451 * @return this view's projection receiver, or {@code null} if none exists 15452 */ 15453 private View getProjectionReceiver() { 15454 ViewParent p = getParent(); 15455 while (p != null && p instanceof View) { 15456 final View v = (View) p; 15457 if (v.isProjectionReceiver()) { 15458 return v; 15459 } 15460 p = p.getParent(); 15461 } 15462 15463 return null; 15464 } 15465 15466 /** 15467 * @return whether the view is a projection receiver 15468 */ 15469 private boolean isProjectionReceiver() { 15470 return mBackground != null; 15471 } 15472 15473 /** 15474 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 15475 * set any flags or handle all of the cases handled by the default invalidation methods. 15476 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 15477 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 15478 * walk up the hierarchy, transforming the dirty rect as necessary. 15479 * 15480 * The method also handles normal invalidation logic if display list properties are not 15481 * being used in this view. The invalidateParent and forceRedraw flags are used by that 15482 * backup approach, to handle these cases used in the various property-setting methods. 15483 * 15484 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 15485 * are not being used in this view 15486 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 15487 * list properties are not being used in this view 15488 */ 15489 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 15490 if (!isHardwareAccelerated() 15491 || !mRenderNode.isValid() 15492 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 15493 if (invalidateParent) { 15494 invalidateParentCaches(); 15495 } 15496 if (forceRedraw) { 15497 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 15498 } 15499 invalidate(false); 15500 } else { 15501 damageInParent(); 15502 } 15503 } 15504 15505 /** 15506 * Tells the parent view to damage this view's bounds. 15507 * 15508 * @hide 15509 */ 15510 protected void damageInParent() { 15511 if (mParent != null && mAttachInfo != null) { 15512 mParent.onDescendantInvalidated(this, this); 15513 } 15514 } 15515 15516 /** 15517 * Utility method to transform a given Rect by the current matrix of this view. 15518 */ 15519 void transformRect(final Rect rect) { 15520 if (!getMatrix().isIdentity()) { 15521 RectF boundingRect = mAttachInfo.mTmpTransformRect; 15522 boundingRect.set(rect); 15523 getMatrix().mapRect(boundingRect); 15524 rect.set((int) Math.floor(boundingRect.left), 15525 (int) Math.floor(boundingRect.top), 15526 (int) Math.ceil(boundingRect.right), 15527 (int) Math.ceil(boundingRect.bottom)); 15528 } 15529 } 15530 15531 /** 15532 * Used to indicate that the parent of this view should clear its caches. This functionality 15533 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15534 * which is necessary when various parent-managed properties of the view change, such as 15535 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 15536 * clears the parent caches and does not causes an invalidate event. 15537 * 15538 * @hide 15539 */ 15540 protected void invalidateParentCaches() { 15541 if (mParent instanceof View) { 15542 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 15543 } 15544 } 15545 15546 /** 15547 * Used to indicate that the parent of this view should be invalidated. This functionality 15548 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15549 * which is necessary when various parent-managed properties of the view change, such as 15550 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 15551 * an invalidation event to the parent. 15552 * 15553 * @hide 15554 */ 15555 protected void invalidateParentIfNeeded() { 15556 if (isHardwareAccelerated() && mParent instanceof View) { 15557 ((View) mParent).invalidate(true); 15558 } 15559 } 15560 15561 /** 15562 * @hide 15563 */ 15564 protected void invalidateParentIfNeededAndWasQuickRejected() { 15565 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 15566 // View was rejected last time it was drawn by its parent; this may have changed 15567 invalidateParentIfNeeded(); 15568 } 15569 } 15570 15571 /** 15572 * Indicates whether this View is opaque. An opaque View guarantees that it will 15573 * draw all the pixels overlapping its bounds using a fully opaque color. 15574 * 15575 * Subclasses of View should override this method whenever possible to indicate 15576 * whether an instance is opaque. Opaque Views are treated in a special way by 15577 * the View hierarchy, possibly allowing it to perform optimizations during 15578 * invalidate/draw passes. 15579 * 15580 * @return True if this View is guaranteed to be fully opaque, false otherwise. 15581 */ 15582 @ViewDebug.ExportedProperty(category = "drawing") 15583 public boolean isOpaque() { 15584 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 15585 getFinalAlpha() >= 1.0f; 15586 } 15587 15588 /** 15589 * @hide 15590 */ 15591 protected void computeOpaqueFlags() { 15592 // Opaque if: 15593 // - Has a background 15594 // - Background is opaque 15595 // - Doesn't have scrollbars or scrollbars overlay 15596 15597 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 15598 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 15599 } else { 15600 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 15601 } 15602 15603 final int flags = mViewFlags; 15604 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 15605 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 15606 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 15607 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 15608 } else { 15609 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 15610 } 15611 } 15612 15613 /** 15614 * @hide 15615 */ 15616 protected boolean hasOpaqueScrollbars() { 15617 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 15618 } 15619 15620 /** 15621 * @return A handler associated with the thread running the View. This 15622 * handler can be used to pump events in the UI events queue. 15623 */ 15624 public Handler getHandler() { 15625 final AttachInfo attachInfo = mAttachInfo; 15626 if (attachInfo != null) { 15627 return attachInfo.mHandler; 15628 } 15629 return null; 15630 } 15631 15632 /** 15633 * Returns the queue of runnable for this view. 15634 * 15635 * @return the queue of runnables for this view 15636 */ 15637 private HandlerActionQueue getRunQueue() { 15638 if (mRunQueue == null) { 15639 mRunQueue = new HandlerActionQueue(); 15640 } 15641 return mRunQueue; 15642 } 15643 15644 /** 15645 * Gets the view root associated with the View. 15646 * @return The view root, or null if none. 15647 * @hide 15648 */ 15649 public ViewRootImpl getViewRootImpl() { 15650 if (mAttachInfo != null) { 15651 return mAttachInfo.mViewRootImpl; 15652 } 15653 return null; 15654 } 15655 15656 /** 15657 * @hide 15658 */ 15659 public ThreadedRenderer getThreadedRenderer() { 15660 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 15661 } 15662 15663 /** 15664 * <p>Causes the Runnable to be added to the message queue. 15665 * The runnable will be run on the user interface thread.</p> 15666 * 15667 * @param action The Runnable that will be executed. 15668 * 15669 * @return Returns true if the Runnable was successfully placed in to the 15670 * message queue. Returns false on failure, usually because the 15671 * looper processing the message queue is exiting. 15672 * 15673 * @see #postDelayed 15674 * @see #removeCallbacks 15675 */ 15676 public boolean post(Runnable action) { 15677 final AttachInfo attachInfo = mAttachInfo; 15678 if (attachInfo != null) { 15679 return attachInfo.mHandler.post(action); 15680 } 15681 15682 // Postpone the runnable until we know on which thread it needs to run. 15683 // Assume that the runnable will be successfully placed after attach. 15684 getRunQueue().post(action); 15685 return true; 15686 } 15687 15688 /** 15689 * <p>Causes the Runnable to be added to the message queue, to be run 15690 * after the specified amount of time elapses. 15691 * The runnable will be run on the user interface thread.</p> 15692 * 15693 * @param action The Runnable that will be executed. 15694 * @param delayMillis The delay (in milliseconds) until the Runnable 15695 * will be executed. 15696 * 15697 * @return true if the Runnable was successfully placed in to the 15698 * message queue. Returns false on failure, usually because the 15699 * looper processing the message queue is exiting. Note that a 15700 * result of true does not mean the Runnable will be processed -- 15701 * if the looper is quit before the delivery time of the message 15702 * occurs then the message will be dropped. 15703 * 15704 * @see #post 15705 * @see #removeCallbacks 15706 */ 15707 public boolean postDelayed(Runnable action, long delayMillis) { 15708 final AttachInfo attachInfo = mAttachInfo; 15709 if (attachInfo != null) { 15710 return attachInfo.mHandler.postDelayed(action, delayMillis); 15711 } 15712 15713 // Postpone the runnable until we know on which thread it needs to run. 15714 // Assume that the runnable will be successfully placed after attach. 15715 getRunQueue().postDelayed(action, delayMillis); 15716 return true; 15717 } 15718 15719 /** 15720 * <p>Causes the Runnable to execute on the next animation time step. 15721 * The runnable will be run on the user interface thread.</p> 15722 * 15723 * @param action The Runnable that will be executed. 15724 * 15725 * @see #postOnAnimationDelayed 15726 * @see #removeCallbacks 15727 */ 15728 public void postOnAnimation(Runnable action) { 15729 final AttachInfo attachInfo = mAttachInfo; 15730 if (attachInfo != null) { 15731 attachInfo.mViewRootImpl.mChoreographer.postCallback( 15732 Choreographer.CALLBACK_ANIMATION, action, null); 15733 } else { 15734 // Postpone the runnable until we know 15735 // on which thread it needs to run. 15736 getRunQueue().post(action); 15737 } 15738 } 15739 15740 /** 15741 * <p>Causes the Runnable to execute on the next animation time step, 15742 * after the specified amount of time elapses. 15743 * The runnable will be run on the user interface thread.</p> 15744 * 15745 * @param action The Runnable that will be executed. 15746 * @param delayMillis The delay (in milliseconds) until the Runnable 15747 * will be executed. 15748 * 15749 * @see #postOnAnimation 15750 * @see #removeCallbacks 15751 */ 15752 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 15753 final AttachInfo attachInfo = mAttachInfo; 15754 if (attachInfo != null) { 15755 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 15756 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 15757 } else { 15758 // Postpone the runnable until we know 15759 // on which thread it needs to run. 15760 getRunQueue().postDelayed(action, delayMillis); 15761 } 15762 } 15763 15764 /** 15765 * <p>Removes the specified Runnable from the message queue.</p> 15766 * 15767 * @param action The Runnable to remove from the message handling queue 15768 * 15769 * @return true if this view could ask the Handler to remove the Runnable, 15770 * false otherwise. When the returned value is true, the Runnable 15771 * may or may not have been actually removed from the message queue 15772 * (for instance, if the Runnable was not in the queue already.) 15773 * 15774 * @see #post 15775 * @see #postDelayed 15776 * @see #postOnAnimation 15777 * @see #postOnAnimationDelayed 15778 */ 15779 public boolean removeCallbacks(Runnable action) { 15780 if (action != null) { 15781 final AttachInfo attachInfo = mAttachInfo; 15782 if (attachInfo != null) { 15783 attachInfo.mHandler.removeCallbacks(action); 15784 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 15785 Choreographer.CALLBACK_ANIMATION, action, null); 15786 } 15787 getRunQueue().removeCallbacks(action); 15788 } 15789 return true; 15790 } 15791 15792 /** 15793 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 15794 * Use this to invalidate the View from a non-UI thread.</p> 15795 * 15796 * <p>This method can be invoked from outside of the UI thread 15797 * only when this View is attached to a window.</p> 15798 * 15799 * @see #invalidate() 15800 * @see #postInvalidateDelayed(long) 15801 */ 15802 public void postInvalidate() { 15803 postInvalidateDelayed(0); 15804 } 15805 15806 /** 15807 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15808 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 15809 * 15810 * <p>This method can be invoked from outside of the UI thread 15811 * only when this View is attached to a window.</p> 15812 * 15813 * @param left The left coordinate of the rectangle to invalidate. 15814 * @param top The top coordinate of the rectangle to invalidate. 15815 * @param right The right coordinate of the rectangle to invalidate. 15816 * @param bottom The bottom coordinate of the rectangle to invalidate. 15817 * 15818 * @see #invalidate(int, int, int, int) 15819 * @see #invalidate(Rect) 15820 * @see #postInvalidateDelayed(long, int, int, int, int) 15821 */ 15822 public void postInvalidate(int left, int top, int right, int bottom) { 15823 postInvalidateDelayed(0, left, top, right, bottom); 15824 } 15825 15826 /** 15827 * <p>Cause an invalidate to happen on a subsequent cycle through the event 15828 * loop. Waits for the specified amount of time.</p> 15829 * 15830 * <p>This method can be invoked from outside of the UI thread 15831 * only when this View is attached to a window.</p> 15832 * 15833 * @param delayMilliseconds the duration in milliseconds to delay the 15834 * invalidation by 15835 * 15836 * @see #invalidate() 15837 * @see #postInvalidate() 15838 */ 15839 public void postInvalidateDelayed(long delayMilliseconds) { 15840 // We try only with the AttachInfo because there's no point in invalidating 15841 // if we are not attached to our window 15842 final AttachInfo attachInfo = mAttachInfo; 15843 if (attachInfo != null) { 15844 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 15845 } 15846 } 15847 15848 /** 15849 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15850 * through the event loop. Waits for the specified amount of time.</p> 15851 * 15852 * <p>This method can be invoked from outside of the UI thread 15853 * only when this View is attached to a window.</p> 15854 * 15855 * @param delayMilliseconds the duration in milliseconds to delay the 15856 * invalidation by 15857 * @param left The left coordinate of the rectangle to invalidate. 15858 * @param top The top coordinate of the rectangle to invalidate. 15859 * @param right The right coordinate of the rectangle to invalidate. 15860 * @param bottom The bottom coordinate of the rectangle to invalidate. 15861 * 15862 * @see #invalidate(int, int, int, int) 15863 * @see #invalidate(Rect) 15864 * @see #postInvalidate(int, int, int, int) 15865 */ 15866 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 15867 int right, int bottom) { 15868 15869 // We try only with the AttachInfo because there's no point in invalidating 15870 // if we are not attached to our window 15871 final AttachInfo attachInfo = mAttachInfo; 15872 if (attachInfo != null) { 15873 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15874 info.target = this; 15875 info.left = left; 15876 info.top = top; 15877 info.right = right; 15878 info.bottom = bottom; 15879 15880 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 15881 } 15882 } 15883 15884 /** 15885 * <p>Cause an invalidate to happen on the next animation time step, typically the 15886 * next display frame.</p> 15887 * 15888 * <p>This method can be invoked from outside of the UI thread 15889 * only when this View is attached to a window.</p> 15890 * 15891 * @see #invalidate() 15892 */ 15893 public void postInvalidateOnAnimation() { 15894 // We try only with the AttachInfo because there's no point in invalidating 15895 // if we are not attached to our window 15896 final AttachInfo attachInfo = mAttachInfo; 15897 if (attachInfo != null) { 15898 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 15899 } 15900 } 15901 15902 /** 15903 * <p>Cause an invalidate of the specified area to happen on the next animation 15904 * time step, typically the next display frame.</p> 15905 * 15906 * <p>This method can be invoked from outside of the UI thread 15907 * only when this View is attached to a window.</p> 15908 * 15909 * @param left The left coordinate of the rectangle to invalidate. 15910 * @param top The top coordinate of the rectangle to invalidate. 15911 * @param right The right coordinate of the rectangle to invalidate. 15912 * @param bottom The bottom coordinate of the rectangle to invalidate. 15913 * 15914 * @see #invalidate(int, int, int, int) 15915 * @see #invalidate(Rect) 15916 */ 15917 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 15918 // We try only with the AttachInfo because there's no point in invalidating 15919 // if we are not attached to our window 15920 final AttachInfo attachInfo = mAttachInfo; 15921 if (attachInfo != null) { 15922 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15923 info.target = this; 15924 info.left = left; 15925 info.top = top; 15926 info.right = right; 15927 info.bottom = bottom; 15928 15929 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 15930 } 15931 } 15932 15933 /** 15934 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 15935 * This event is sent at most once every 15936 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 15937 */ 15938 private void postSendViewScrolledAccessibilityEventCallback() { 15939 if (mSendViewScrolledAccessibilityEvent == null) { 15940 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 15941 } 15942 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 15943 mSendViewScrolledAccessibilityEvent.mIsPending = true; 15944 postDelayed(mSendViewScrolledAccessibilityEvent, 15945 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 15946 } 15947 } 15948 15949 /** 15950 * Called by a parent to request that a child update its values for mScrollX 15951 * and mScrollY if necessary. This will typically be done if the child is 15952 * animating a scroll using a {@link android.widget.Scroller Scroller} 15953 * object. 15954 */ 15955 public void computeScroll() { 15956 } 15957 15958 /** 15959 * <p>Indicate whether the horizontal edges are faded when the view is 15960 * scrolled horizontally.</p> 15961 * 15962 * @return true if the horizontal edges should are faded on scroll, false 15963 * otherwise 15964 * 15965 * @see #setHorizontalFadingEdgeEnabled(boolean) 15966 * 15967 * @attr ref android.R.styleable#View_requiresFadingEdge 15968 */ 15969 public boolean isHorizontalFadingEdgeEnabled() { 15970 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 15971 } 15972 15973 /** 15974 * <p>Define whether the horizontal edges should be faded when this view 15975 * is scrolled horizontally.</p> 15976 * 15977 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 15978 * be faded when the view is scrolled 15979 * horizontally 15980 * 15981 * @see #isHorizontalFadingEdgeEnabled() 15982 * 15983 * @attr ref android.R.styleable#View_requiresFadingEdge 15984 */ 15985 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 15986 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 15987 if (horizontalFadingEdgeEnabled) { 15988 initScrollCache(); 15989 } 15990 15991 mViewFlags ^= FADING_EDGE_HORIZONTAL; 15992 } 15993 } 15994 15995 /** 15996 * <p>Indicate whether the vertical edges are faded when the view is 15997 * scrolled horizontally.</p> 15998 * 15999 * @return true if the vertical edges should are faded on scroll, false 16000 * otherwise 16001 * 16002 * @see #setVerticalFadingEdgeEnabled(boolean) 16003 * 16004 * @attr ref android.R.styleable#View_requiresFadingEdge 16005 */ 16006 public boolean isVerticalFadingEdgeEnabled() { 16007 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 16008 } 16009 16010 /** 16011 * <p>Define whether the vertical edges should be faded when this view 16012 * is scrolled vertically.</p> 16013 * 16014 * @param verticalFadingEdgeEnabled true if the vertical edges should 16015 * be faded when the view is scrolled 16016 * vertically 16017 * 16018 * @see #isVerticalFadingEdgeEnabled() 16019 * 16020 * @attr ref android.R.styleable#View_requiresFadingEdge 16021 */ 16022 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 16023 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 16024 if (verticalFadingEdgeEnabled) { 16025 initScrollCache(); 16026 } 16027 16028 mViewFlags ^= FADING_EDGE_VERTICAL; 16029 } 16030 } 16031 16032 /** 16033 * Returns the strength, or intensity, of the top faded edge. The strength is 16034 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16035 * returns 0.0 or 1.0 but no value in between. 16036 * 16037 * Subclasses should override this method to provide a smoother fade transition 16038 * when scrolling occurs. 16039 * 16040 * @return the intensity of the top fade as a float between 0.0f and 1.0f 16041 */ 16042 protected float getTopFadingEdgeStrength() { 16043 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 16044 } 16045 16046 /** 16047 * Returns the strength, or intensity, of the bottom faded edge. The strength is 16048 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16049 * returns 0.0 or 1.0 but no value in between. 16050 * 16051 * Subclasses should override this method to provide a smoother fade transition 16052 * when scrolling occurs. 16053 * 16054 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 16055 */ 16056 protected float getBottomFadingEdgeStrength() { 16057 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 16058 computeVerticalScrollRange() ? 1.0f : 0.0f; 16059 } 16060 16061 /** 16062 * Returns the strength, or intensity, of the left faded edge. The strength is 16063 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16064 * returns 0.0 or 1.0 but no value in between. 16065 * 16066 * Subclasses should override this method to provide a smoother fade transition 16067 * when scrolling occurs. 16068 * 16069 * @return the intensity of the left fade as a float between 0.0f and 1.0f 16070 */ 16071 protected float getLeftFadingEdgeStrength() { 16072 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 16073 } 16074 16075 /** 16076 * Returns the strength, or intensity, of the right faded edge. The strength is 16077 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16078 * returns 0.0 or 1.0 but no value in between. 16079 * 16080 * Subclasses should override this method to provide a smoother fade transition 16081 * when scrolling occurs. 16082 * 16083 * @return the intensity of the right fade as a float between 0.0f and 1.0f 16084 */ 16085 protected float getRightFadingEdgeStrength() { 16086 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 16087 computeHorizontalScrollRange() ? 1.0f : 0.0f; 16088 } 16089 16090 /** 16091 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 16092 * scrollbar is not drawn by default.</p> 16093 * 16094 * @return true if the horizontal scrollbar should be painted, false 16095 * otherwise 16096 * 16097 * @see #setHorizontalScrollBarEnabled(boolean) 16098 */ 16099 public boolean isHorizontalScrollBarEnabled() { 16100 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 16101 } 16102 16103 /** 16104 * <p>Define whether the horizontal scrollbar should be drawn or not. The 16105 * scrollbar is not drawn by default.</p> 16106 * 16107 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 16108 * be painted 16109 * 16110 * @see #isHorizontalScrollBarEnabled() 16111 */ 16112 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 16113 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 16114 mViewFlags ^= SCROLLBARS_HORIZONTAL; 16115 computeOpaqueFlags(); 16116 resolvePadding(); 16117 } 16118 } 16119 16120 /** 16121 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 16122 * scrollbar is not drawn by default.</p> 16123 * 16124 * @return true if the vertical scrollbar should be painted, false 16125 * otherwise 16126 * 16127 * @see #setVerticalScrollBarEnabled(boolean) 16128 */ 16129 public boolean isVerticalScrollBarEnabled() { 16130 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 16131 } 16132 16133 /** 16134 * <p>Define whether the vertical scrollbar should be drawn or not. The 16135 * scrollbar is not drawn by default.</p> 16136 * 16137 * @param verticalScrollBarEnabled true if the vertical scrollbar should 16138 * be painted 16139 * 16140 * @see #isVerticalScrollBarEnabled() 16141 */ 16142 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 16143 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 16144 mViewFlags ^= SCROLLBARS_VERTICAL; 16145 computeOpaqueFlags(); 16146 resolvePadding(); 16147 } 16148 } 16149 16150 /** 16151 * @hide 16152 */ 16153 protected void recomputePadding() { 16154 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 16155 } 16156 16157 /** 16158 * Define whether scrollbars will fade when the view is not scrolling. 16159 * 16160 * @param fadeScrollbars whether to enable fading 16161 * 16162 * @attr ref android.R.styleable#View_fadeScrollbars 16163 */ 16164 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 16165 initScrollCache(); 16166 final ScrollabilityCache scrollabilityCache = mScrollCache; 16167 scrollabilityCache.fadeScrollBars = fadeScrollbars; 16168 if (fadeScrollbars) { 16169 scrollabilityCache.state = ScrollabilityCache.OFF; 16170 } else { 16171 scrollabilityCache.state = ScrollabilityCache.ON; 16172 } 16173 } 16174 16175 /** 16176 * 16177 * Returns true if scrollbars will fade when this view is not scrolling 16178 * 16179 * @return true if scrollbar fading is enabled 16180 * 16181 * @attr ref android.R.styleable#View_fadeScrollbars 16182 */ 16183 public boolean isScrollbarFadingEnabled() { 16184 return mScrollCache != null && mScrollCache.fadeScrollBars; 16185 } 16186 16187 /** 16188 * 16189 * Returns the delay before scrollbars fade. 16190 * 16191 * @return the delay before scrollbars fade 16192 * 16193 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 16194 */ 16195 public int getScrollBarDefaultDelayBeforeFade() { 16196 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 16197 mScrollCache.scrollBarDefaultDelayBeforeFade; 16198 } 16199 16200 /** 16201 * Define the delay before scrollbars fade. 16202 * 16203 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 16204 * 16205 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 16206 */ 16207 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 16208 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 16209 } 16210 16211 /** 16212 * 16213 * Returns the scrollbar fade duration. 16214 * 16215 * @return the scrollbar fade duration, in milliseconds 16216 * 16217 * @attr ref android.R.styleable#View_scrollbarFadeDuration 16218 */ 16219 public int getScrollBarFadeDuration() { 16220 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 16221 mScrollCache.scrollBarFadeDuration; 16222 } 16223 16224 /** 16225 * Define the scrollbar fade duration. 16226 * 16227 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 16228 * 16229 * @attr ref android.R.styleable#View_scrollbarFadeDuration 16230 */ 16231 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 16232 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 16233 } 16234 16235 /** 16236 * 16237 * Returns the scrollbar size. 16238 * 16239 * @return the scrollbar size 16240 * 16241 * @attr ref android.R.styleable#View_scrollbarSize 16242 */ 16243 public int getScrollBarSize() { 16244 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 16245 mScrollCache.scrollBarSize; 16246 } 16247 16248 /** 16249 * Define the scrollbar size. 16250 * 16251 * @param scrollBarSize - the scrollbar size 16252 * 16253 * @attr ref android.R.styleable#View_scrollbarSize 16254 */ 16255 public void setScrollBarSize(int scrollBarSize) { 16256 getScrollCache().scrollBarSize = scrollBarSize; 16257 } 16258 16259 /** 16260 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 16261 * inset. When inset, they add to the padding of the view. And the scrollbars 16262 * can be drawn inside the padding area or on the edge of the view. For example, 16263 * if a view has a background drawable and you want to draw the scrollbars 16264 * inside the padding specified by the drawable, you can use 16265 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 16266 * appear at the edge of the view, ignoring the padding, then you can use 16267 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 16268 * @param style the style of the scrollbars. Should be one of 16269 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 16270 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 16271 * @see #SCROLLBARS_INSIDE_OVERLAY 16272 * @see #SCROLLBARS_INSIDE_INSET 16273 * @see #SCROLLBARS_OUTSIDE_OVERLAY 16274 * @see #SCROLLBARS_OUTSIDE_INSET 16275 * 16276 * @attr ref android.R.styleable#View_scrollbarStyle 16277 */ 16278 public void setScrollBarStyle(@ScrollBarStyle int style) { 16279 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 16280 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 16281 computeOpaqueFlags(); 16282 resolvePadding(); 16283 } 16284 } 16285 16286 /** 16287 * <p>Returns the current scrollbar style.</p> 16288 * @return the current scrollbar style 16289 * @see #SCROLLBARS_INSIDE_OVERLAY 16290 * @see #SCROLLBARS_INSIDE_INSET 16291 * @see #SCROLLBARS_OUTSIDE_OVERLAY 16292 * @see #SCROLLBARS_OUTSIDE_INSET 16293 * 16294 * @attr ref android.R.styleable#View_scrollbarStyle 16295 */ 16296 @ViewDebug.ExportedProperty(mapping = { 16297 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 16298 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 16299 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 16300 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 16301 }) 16302 @ScrollBarStyle 16303 public int getScrollBarStyle() { 16304 return mViewFlags & SCROLLBARS_STYLE_MASK; 16305 } 16306 16307 /** 16308 * <p>Compute the horizontal range that the horizontal scrollbar 16309 * represents.</p> 16310 * 16311 * <p>The range is expressed in arbitrary units that must be the same as the 16312 * units used by {@link #computeHorizontalScrollExtent()} and 16313 * {@link #computeHorizontalScrollOffset()}.</p> 16314 * 16315 * <p>The default range is the drawing width of this view.</p> 16316 * 16317 * @return the total horizontal range represented by the horizontal 16318 * scrollbar 16319 * 16320 * @see #computeHorizontalScrollExtent() 16321 * @see #computeHorizontalScrollOffset() 16322 * @see android.widget.ScrollBarDrawable 16323 */ 16324 protected int computeHorizontalScrollRange() { 16325 return getWidth(); 16326 } 16327 16328 /** 16329 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 16330 * within the horizontal range. This value is used to compute the position 16331 * of the thumb within the scrollbar's track.</p> 16332 * 16333 * <p>The range is expressed in arbitrary units that must be the same as the 16334 * units used by {@link #computeHorizontalScrollRange()} and 16335 * {@link #computeHorizontalScrollExtent()}.</p> 16336 * 16337 * <p>The default offset is the scroll offset of this view.</p> 16338 * 16339 * @return the horizontal offset of the scrollbar's thumb 16340 * 16341 * @see #computeHorizontalScrollRange() 16342 * @see #computeHorizontalScrollExtent() 16343 * @see android.widget.ScrollBarDrawable 16344 */ 16345 protected int computeHorizontalScrollOffset() { 16346 return mScrollX; 16347 } 16348 16349 /** 16350 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 16351 * within the horizontal range. This value is used to compute the length 16352 * of the thumb within the scrollbar's track.</p> 16353 * 16354 * <p>The range is expressed in arbitrary units that must be the same as the 16355 * units used by {@link #computeHorizontalScrollRange()} and 16356 * {@link #computeHorizontalScrollOffset()}.</p> 16357 * 16358 * <p>The default extent is the drawing width of this view.</p> 16359 * 16360 * @return the horizontal extent of the scrollbar's thumb 16361 * 16362 * @see #computeHorizontalScrollRange() 16363 * @see #computeHorizontalScrollOffset() 16364 * @see android.widget.ScrollBarDrawable 16365 */ 16366 protected int computeHorizontalScrollExtent() { 16367 return getWidth(); 16368 } 16369 16370 /** 16371 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 16372 * 16373 * <p>The range is expressed in arbitrary units that must be the same as the 16374 * units used by {@link #computeVerticalScrollExtent()} and 16375 * {@link #computeVerticalScrollOffset()}.</p> 16376 * 16377 * @return the total vertical range represented by the vertical scrollbar 16378 * 16379 * <p>The default range is the drawing height of this view.</p> 16380 * 16381 * @see #computeVerticalScrollExtent() 16382 * @see #computeVerticalScrollOffset() 16383 * @see android.widget.ScrollBarDrawable 16384 */ 16385 protected int computeVerticalScrollRange() { 16386 return getHeight(); 16387 } 16388 16389 /** 16390 * <p>Compute the vertical offset of the vertical scrollbar's thumb 16391 * within the horizontal range. This value is used to compute the position 16392 * of the thumb within the scrollbar's track.</p> 16393 * 16394 * <p>The range is expressed in arbitrary units that must be the same as the 16395 * units used by {@link #computeVerticalScrollRange()} and 16396 * {@link #computeVerticalScrollExtent()}.</p> 16397 * 16398 * <p>The default offset is the scroll offset of this view.</p> 16399 * 16400 * @return the vertical offset of the scrollbar's thumb 16401 * 16402 * @see #computeVerticalScrollRange() 16403 * @see #computeVerticalScrollExtent() 16404 * @see android.widget.ScrollBarDrawable 16405 */ 16406 protected int computeVerticalScrollOffset() { 16407 return mScrollY; 16408 } 16409 16410 /** 16411 * <p>Compute the vertical extent of the vertical scrollbar's thumb 16412 * within the vertical range. This value is used to compute the length 16413 * of the thumb within the scrollbar's track.</p> 16414 * 16415 * <p>The range is expressed in arbitrary units that must be the same as the 16416 * units used by {@link #computeVerticalScrollRange()} and 16417 * {@link #computeVerticalScrollOffset()}.</p> 16418 * 16419 * <p>The default extent is the drawing height of this view.</p> 16420 * 16421 * @return the vertical extent of the scrollbar's thumb 16422 * 16423 * @see #computeVerticalScrollRange() 16424 * @see #computeVerticalScrollOffset() 16425 * @see android.widget.ScrollBarDrawable 16426 */ 16427 protected int computeVerticalScrollExtent() { 16428 return getHeight(); 16429 } 16430 16431 /** 16432 * Check if this view can be scrolled horizontally in a certain direction. 16433 * 16434 * @param direction Negative to check scrolling left, positive to check scrolling right. 16435 * @return true if this view can be scrolled in the specified direction, false otherwise. 16436 */ 16437 public boolean canScrollHorizontally(int direction) { 16438 final int offset = computeHorizontalScrollOffset(); 16439 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 16440 if (range == 0) return false; 16441 if (direction < 0) { 16442 return offset > 0; 16443 } else { 16444 return offset < range - 1; 16445 } 16446 } 16447 16448 /** 16449 * Check if this view can be scrolled vertically in a certain direction. 16450 * 16451 * @param direction Negative to check scrolling up, positive to check scrolling down. 16452 * @return true if this view can be scrolled in the specified direction, false otherwise. 16453 */ 16454 public boolean canScrollVertically(int direction) { 16455 final int offset = computeVerticalScrollOffset(); 16456 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 16457 if (range == 0) return false; 16458 if (direction < 0) { 16459 return offset > 0; 16460 } else { 16461 return offset < range - 1; 16462 } 16463 } 16464 16465 void getScrollIndicatorBounds(@NonNull Rect out) { 16466 out.left = mScrollX; 16467 out.right = mScrollX + mRight - mLeft; 16468 out.top = mScrollY; 16469 out.bottom = mScrollY + mBottom - mTop; 16470 } 16471 16472 private void onDrawScrollIndicators(Canvas c) { 16473 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 16474 // No scroll indicators enabled. 16475 return; 16476 } 16477 16478 final Drawable dr = mScrollIndicatorDrawable; 16479 if (dr == null) { 16480 // Scroll indicators aren't supported here. 16481 return; 16482 } 16483 16484 final int h = dr.getIntrinsicHeight(); 16485 final int w = dr.getIntrinsicWidth(); 16486 final Rect rect = mAttachInfo.mTmpInvalRect; 16487 getScrollIndicatorBounds(rect); 16488 16489 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 16490 final boolean canScrollUp = canScrollVertically(-1); 16491 if (canScrollUp) { 16492 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 16493 dr.draw(c); 16494 } 16495 } 16496 16497 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 16498 final boolean canScrollDown = canScrollVertically(1); 16499 if (canScrollDown) { 16500 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 16501 dr.draw(c); 16502 } 16503 } 16504 16505 final int leftRtl; 16506 final int rightRtl; 16507 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 16508 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 16509 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 16510 } else { 16511 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 16512 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 16513 } 16514 16515 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 16516 if ((mPrivateFlags3 & leftMask) != 0) { 16517 final boolean canScrollLeft = canScrollHorizontally(-1); 16518 if (canScrollLeft) { 16519 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 16520 dr.draw(c); 16521 } 16522 } 16523 16524 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 16525 if ((mPrivateFlags3 & rightMask) != 0) { 16526 final boolean canScrollRight = canScrollHorizontally(1); 16527 if (canScrollRight) { 16528 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 16529 dr.draw(c); 16530 } 16531 } 16532 } 16533 16534 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 16535 @Nullable Rect touchBounds) { 16536 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16537 if (bounds == null) { 16538 return; 16539 } 16540 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16541 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16542 && !isVerticalScrollBarHidden(); 16543 final int size = getHorizontalScrollbarHeight(); 16544 final int verticalScrollBarGap = drawVerticalScrollBar ? 16545 getVerticalScrollbarWidth() : 0; 16546 final int width = mRight - mLeft; 16547 final int height = mBottom - mTop; 16548 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 16549 bounds.left = mScrollX + (mPaddingLeft & inside); 16550 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 16551 bounds.bottom = bounds.top + size; 16552 16553 if (touchBounds == null) { 16554 return; 16555 } 16556 if (touchBounds != bounds) { 16557 touchBounds.set(bounds); 16558 } 16559 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16560 if (touchBounds.height() < minTouchTarget) { 16561 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16562 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 16563 touchBounds.top = touchBounds.bottom - minTouchTarget; 16564 } 16565 if (touchBounds.width() < minTouchTarget) { 16566 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16567 touchBounds.left -= adjust; 16568 touchBounds.right = touchBounds.left + minTouchTarget; 16569 } 16570 } 16571 16572 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 16573 if (mRoundScrollbarRenderer == null) { 16574 getStraightVerticalScrollBarBounds(bounds, touchBounds); 16575 } else { 16576 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 16577 } 16578 } 16579 16580 private void getRoundVerticalScrollBarBounds(Rect bounds) { 16581 final int width = mRight - mLeft; 16582 final int height = mBottom - mTop; 16583 // Do not take padding into account as we always want the scrollbars 16584 // to hug the screen for round wearable devices. 16585 bounds.left = mScrollX; 16586 bounds.top = mScrollY; 16587 bounds.right = bounds.left + width; 16588 bounds.bottom = mScrollY + height; 16589 } 16590 16591 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 16592 @Nullable Rect touchBounds) { 16593 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16594 if (bounds == null) { 16595 return; 16596 } 16597 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16598 final int size = getVerticalScrollbarWidth(); 16599 int verticalScrollbarPosition = mVerticalScrollbarPosition; 16600 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 16601 verticalScrollbarPosition = isLayoutRtl() ? 16602 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 16603 } 16604 final int width = mRight - mLeft; 16605 final int height = mBottom - mTop; 16606 switch (verticalScrollbarPosition) { 16607 default: 16608 case SCROLLBAR_POSITION_RIGHT: 16609 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 16610 break; 16611 case SCROLLBAR_POSITION_LEFT: 16612 bounds.left = mScrollX + (mUserPaddingLeft & inside); 16613 break; 16614 } 16615 bounds.top = mScrollY + (mPaddingTop & inside); 16616 bounds.right = bounds.left + size; 16617 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 16618 16619 if (touchBounds == null) { 16620 return; 16621 } 16622 if (touchBounds != bounds) { 16623 touchBounds.set(bounds); 16624 } 16625 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16626 if (touchBounds.width() < minTouchTarget) { 16627 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16628 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 16629 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 16630 touchBounds.left = touchBounds.right - minTouchTarget; 16631 } else { 16632 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 16633 touchBounds.right = touchBounds.left + minTouchTarget; 16634 } 16635 } 16636 if (touchBounds.height() < minTouchTarget) { 16637 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16638 touchBounds.top -= adjust; 16639 touchBounds.bottom = touchBounds.top + minTouchTarget; 16640 } 16641 } 16642 16643 /** 16644 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 16645 * scrollbars are painted only if they have been awakened first.</p> 16646 * 16647 * @param canvas the canvas on which to draw the scrollbars 16648 * 16649 * @see #awakenScrollBars(int) 16650 */ 16651 protected final void onDrawScrollBars(Canvas canvas) { 16652 // scrollbars are drawn only when the animation is running 16653 final ScrollabilityCache cache = mScrollCache; 16654 16655 if (cache != null) { 16656 16657 int state = cache.state; 16658 16659 if (state == ScrollabilityCache.OFF) { 16660 return; 16661 } 16662 16663 boolean invalidate = false; 16664 16665 if (state == ScrollabilityCache.FADING) { 16666 // We're fading -- get our fade interpolation 16667 if (cache.interpolatorValues == null) { 16668 cache.interpolatorValues = new float[1]; 16669 } 16670 16671 float[] values = cache.interpolatorValues; 16672 16673 // Stops the animation if we're done 16674 if (cache.scrollBarInterpolator.timeToValues(values) == 16675 Interpolator.Result.FREEZE_END) { 16676 cache.state = ScrollabilityCache.OFF; 16677 } else { 16678 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 16679 } 16680 16681 // This will make the scroll bars inval themselves after 16682 // drawing. We only want this when we're fading so that 16683 // we prevent excessive redraws 16684 invalidate = true; 16685 } else { 16686 // We're just on -- but we may have been fading before so 16687 // reset alpha 16688 cache.scrollBar.mutate().setAlpha(255); 16689 } 16690 16691 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 16692 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16693 && !isVerticalScrollBarHidden(); 16694 16695 // Fork out the scroll bar drawing for round wearable devices. 16696 if (mRoundScrollbarRenderer != null) { 16697 if (drawVerticalScrollBar) { 16698 final Rect bounds = cache.mScrollBarBounds; 16699 getVerticalScrollBarBounds(bounds, null); 16700 mRoundScrollbarRenderer.drawRoundScrollbars( 16701 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 16702 if (invalidate) { 16703 invalidate(); 16704 } 16705 } 16706 // Do not draw horizontal scroll bars for round wearable devices. 16707 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 16708 final ScrollBarDrawable scrollBar = cache.scrollBar; 16709 16710 if (drawHorizontalScrollBar) { 16711 scrollBar.setParameters(computeHorizontalScrollRange(), 16712 computeHorizontalScrollOffset(), 16713 computeHorizontalScrollExtent(), false); 16714 final Rect bounds = cache.mScrollBarBounds; 16715 getHorizontalScrollBarBounds(bounds, null); 16716 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16717 bounds.right, bounds.bottom); 16718 if (invalidate) { 16719 invalidate(bounds); 16720 } 16721 } 16722 16723 if (drawVerticalScrollBar) { 16724 scrollBar.setParameters(computeVerticalScrollRange(), 16725 computeVerticalScrollOffset(), 16726 computeVerticalScrollExtent(), true); 16727 final Rect bounds = cache.mScrollBarBounds; 16728 getVerticalScrollBarBounds(bounds, null); 16729 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16730 bounds.right, bounds.bottom); 16731 if (invalidate) { 16732 invalidate(bounds); 16733 } 16734 } 16735 } 16736 } 16737 } 16738 16739 /** 16740 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 16741 * FastScroller is visible. 16742 * @return whether to temporarily hide the vertical scrollbar 16743 * @hide 16744 */ 16745 protected boolean isVerticalScrollBarHidden() { 16746 return false; 16747 } 16748 16749 /** 16750 * <p>Draw the horizontal scrollbar if 16751 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 16752 * 16753 * @param canvas the canvas on which to draw the scrollbar 16754 * @param scrollBar the scrollbar's drawable 16755 * 16756 * @see #isHorizontalScrollBarEnabled() 16757 * @see #computeHorizontalScrollRange() 16758 * @see #computeHorizontalScrollExtent() 16759 * @see #computeHorizontalScrollOffset() 16760 * @see android.widget.ScrollBarDrawable 16761 * @hide 16762 */ 16763 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 16764 int l, int t, int r, int b) { 16765 scrollBar.setBounds(l, t, r, b); 16766 scrollBar.draw(canvas); 16767 } 16768 16769 /** 16770 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 16771 * returns true.</p> 16772 * 16773 * @param canvas the canvas on which to draw the scrollbar 16774 * @param scrollBar the scrollbar's drawable 16775 * 16776 * @see #isVerticalScrollBarEnabled() 16777 * @see #computeVerticalScrollRange() 16778 * @see #computeVerticalScrollExtent() 16779 * @see #computeVerticalScrollOffset() 16780 * @see android.widget.ScrollBarDrawable 16781 * @hide 16782 */ 16783 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 16784 int l, int t, int r, int b) { 16785 scrollBar.setBounds(l, t, r, b); 16786 scrollBar.draw(canvas); 16787 } 16788 16789 /** 16790 * Implement this to do your drawing. 16791 * 16792 * @param canvas the canvas on which the background will be drawn 16793 */ 16794 protected void onDraw(Canvas canvas) { 16795 } 16796 16797 /* 16798 * Caller is responsible for calling requestLayout if necessary. 16799 * (This allows addViewInLayout to not request a new layout.) 16800 */ 16801 void assignParent(ViewParent parent) { 16802 if (mParent == null) { 16803 mParent = parent; 16804 } else if (parent == null) { 16805 mParent = null; 16806 } else { 16807 throw new RuntimeException("view " + this + " being added, but" 16808 + " it already has a parent"); 16809 } 16810 } 16811 16812 /** 16813 * This is called when the view is attached to a window. At this point it 16814 * has a Surface and will start drawing. Note that this function is 16815 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 16816 * however it may be called any time before the first onDraw -- including 16817 * before or after {@link #onMeasure(int, int)}. 16818 * 16819 * @see #onDetachedFromWindow() 16820 */ 16821 @CallSuper 16822 protected void onAttachedToWindow() { 16823 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 16824 mParent.requestTransparentRegion(this); 16825 } 16826 16827 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 16828 16829 jumpDrawablesToCurrentState(); 16830 16831 resetSubtreeAccessibilityStateChanged(); 16832 16833 // rebuild, since Outline not maintained while View is detached 16834 rebuildOutline(); 16835 16836 if (isFocused()) { 16837 InputMethodManager imm = InputMethodManager.peekInstance(); 16838 if (imm != null) { 16839 imm.focusIn(this); 16840 } 16841 } 16842 } 16843 16844 /** 16845 * Resolve all RTL related properties. 16846 * 16847 * @return true if resolution of RTL properties has been done 16848 * 16849 * @hide 16850 */ 16851 public boolean resolveRtlPropertiesIfNeeded() { 16852 if (!needRtlPropertiesResolution()) return false; 16853 16854 // Order is important here: LayoutDirection MUST be resolved first 16855 if (!isLayoutDirectionResolved()) { 16856 resolveLayoutDirection(); 16857 resolveLayoutParams(); 16858 } 16859 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 16860 if (!isTextDirectionResolved()) { 16861 resolveTextDirection(); 16862 } 16863 if (!isTextAlignmentResolved()) { 16864 resolveTextAlignment(); 16865 } 16866 // Should resolve Drawables before Padding because we need the layout direction of the 16867 // Drawable to correctly resolve Padding. 16868 if (!areDrawablesResolved()) { 16869 resolveDrawables(); 16870 } 16871 if (!isPaddingResolved()) { 16872 resolvePadding(); 16873 } 16874 onRtlPropertiesChanged(getLayoutDirection()); 16875 return true; 16876 } 16877 16878 /** 16879 * Reset resolution of all RTL related properties. 16880 * 16881 * @hide 16882 */ 16883 public void resetRtlProperties() { 16884 resetResolvedLayoutDirection(); 16885 resetResolvedTextDirection(); 16886 resetResolvedTextAlignment(); 16887 resetResolvedPadding(); 16888 resetResolvedDrawables(); 16889 } 16890 16891 /** 16892 * @see #onScreenStateChanged(int) 16893 */ 16894 void dispatchScreenStateChanged(int screenState) { 16895 onScreenStateChanged(screenState); 16896 } 16897 16898 /** 16899 * This method is called whenever the state of the screen this view is 16900 * attached to changes. A state change will usually occurs when the screen 16901 * turns on or off (whether it happens automatically or the user does it 16902 * manually.) 16903 * 16904 * @param screenState The new state of the screen. Can be either 16905 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 16906 */ 16907 public void onScreenStateChanged(int screenState) { 16908 } 16909 16910 /** 16911 * @see #onMovedToDisplay(int, Configuration) 16912 */ 16913 void dispatchMovedToDisplay(Display display, Configuration config) { 16914 mAttachInfo.mDisplay = display; 16915 mAttachInfo.mDisplayState = display.getState(); 16916 onMovedToDisplay(display.getDisplayId(), config); 16917 } 16918 16919 /** 16920 * Called by the system when the hosting activity is moved from one display to another without 16921 * recreation. This means that the activity is declared to handle all changes to configuration 16922 * that happened when it was switched to another display, so it wasn't destroyed and created 16923 * again. 16924 * 16925 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 16926 * applied configuration actually changed. It is up to app developer to choose whether to handle 16927 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 16928 * call. 16929 * 16930 * <p>Use this callback to track changes to the displays if some functionality relies on an 16931 * association with some display properties. 16932 * 16933 * @param displayId The id of the display to which the view was moved. 16934 * @param config Configuration of the resources on new display after move. 16935 * 16936 * @see #onConfigurationChanged(Configuration) 16937 * @hide 16938 */ 16939 public void onMovedToDisplay(int displayId, Configuration config) { 16940 } 16941 16942 /** 16943 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 16944 */ 16945 private boolean hasRtlSupport() { 16946 return mContext.getApplicationInfo().hasRtlSupport(); 16947 } 16948 16949 /** 16950 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 16951 * RTL not supported) 16952 */ 16953 private boolean isRtlCompatibilityMode() { 16954 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 16955 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 16956 } 16957 16958 /** 16959 * @return true if RTL properties need resolution. 16960 * 16961 */ 16962 private boolean needRtlPropertiesResolution() { 16963 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 16964 } 16965 16966 /** 16967 * Called when any RTL property (layout direction or text direction or text alignment) has 16968 * been changed. 16969 * 16970 * Subclasses need to override this method to take care of cached information that depends on the 16971 * resolved layout direction, or to inform child views that inherit their layout direction. 16972 * 16973 * The default implementation does nothing. 16974 * 16975 * @param layoutDirection the direction of the layout 16976 * 16977 * @see #LAYOUT_DIRECTION_LTR 16978 * @see #LAYOUT_DIRECTION_RTL 16979 */ 16980 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 16981 } 16982 16983 /** 16984 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 16985 * that the parent directionality can and will be resolved before its children. 16986 * 16987 * @return true if resolution has been done, false otherwise. 16988 * 16989 * @hide 16990 */ 16991 public boolean resolveLayoutDirection() { 16992 // Clear any previous layout direction resolution 16993 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 16994 16995 if (hasRtlSupport()) { 16996 // Set resolved depending on layout direction 16997 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 16998 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 16999 case LAYOUT_DIRECTION_INHERIT: 17000 // We cannot resolve yet. LTR is by default and let the resolution happen again 17001 // later to get the correct resolved value 17002 if (!canResolveLayoutDirection()) return false; 17003 17004 // Parent has not yet resolved, LTR is still the default 17005 try { 17006 if (!mParent.isLayoutDirectionResolved()) return false; 17007 17008 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 17009 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17010 } 17011 } catch (AbstractMethodError e) { 17012 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 17013 " does not fully implement ViewParent", e); 17014 } 17015 break; 17016 case LAYOUT_DIRECTION_RTL: 17017 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17018 break; 17019 case LAYOUT_DIRECTION_LOCALE: 17020 if((LAYOUT_DIRECTION_RTL == 17021 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 17022 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17023 } 17024 break; 17025 default: 17026 // Nothing to do, LTR by default 17027 } 17028 } 17029 17030 // Set to resolved 17031 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 17032 return true; 17033 } 17034 17035 /** 17036 * Check if layout direction resolution can be done. 17037 * 17038 * @return true if layout direction resolution can be done otherwise return false. 17039 */ 17040 public boolean canResolveLayoutDirection() { 17041 switch (getRawLayoutDirection()) { 17042 case LAYOUT_DIRECTION_INHERIT: 17043 if (mParent != null) { 17044 try { 17045 return mParent.canResolveLayoutDirection(); 17046 } catch (AbstractMethodError e) { 17047 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 17048 " does not fully implement ViewParent", e); 17049 } 17050 } 17051 return false; 17052 17053 default: 17054 return true; 17055 } 17056 } 17057 17058 /** 17059 * Reset the resolved layout direction. Layout direction will be resolved during a call to 17060 * {@link #onMeasure(int, int)}. 17061 * 17062 * @hide 17063 */ 17064 public void resetResolvedLayoutDirection() { 17065 // Reset the current resolved bits 17066 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 17067 } 17068 17069 /** 17070 * @return true if the layout direction is inherited. 17071 * 17072 * @hide 17073 */ 17074 public boolean isLayoutDirectionInherited() { 17075 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 17076 } 17077 17078 /** 17079 * @return true if layout direction has been resolved. 17080 */ 17081 public boolean isLayoutDirectionResolved() { 17082 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 17083 } 17084 17085 /** 17086 * Return if padding has been resolved 17087 * 17088 * @hide 17089 */ 17090 boolean isPaddingResolved() { 17091 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 17092 } 17093 17094 /** 17095 * Resolves padding depending on layout direction, if applicable, and 17096 * recomputes internal padding values to adjust for scroll bars. 17097 * 17098 * @hide 17099 */ 17100 public void resolvePadding() { 17101 final int resolvedLayoutDirection = getLayoutDirection(); 17102 17103 if (!isRtlCompatibilityMode()) { 17104 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 17105 // If start / end padding are defined, they will be resolved (hence overriding) to 17106 // left / right or right / left depending on the resolved layout direction. 17107 // If start / end padding are not defined, use the left / right ones. 17108 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 17109 Rect padding = sThreadLocal.get(); 17110 if (padding == null) { 17111 padding = new Rect(); 17112 sThreadLocal.set(padding); 17113 } 17114 mBackground.getPadding(padding); 17115 if (!mLeftPaddingDefined) { 17116 mUserPaddingLeftInitial = padding.left; 17117 } 17118 if (!mRightPaddingDefined) { 17119 mUserPaddingRightInitial = padding.right; 17120 } 17121 } 17122 switch (resolvedLayoutDirection) { 17123 case LAYOUT_DIRECTION_RTL: 17124 if (mUserPaddingStart != UNDEFINED_PADDING) { 17125 mUserPaddingRight = mUserPaddingStart; 17126 } else { 17127 mUserPaddingRight = mUserPaddingRightInitial; 17128 } 17129 if (mUserPaddingEnd != UNDEFINED_PADDING) { 17130 mUserPaddingLeft = mUserPaddingEnd; 17131 } else { 17132 mUserPaddingLeft = mUserPaddingLeftInitial; 17133 } 17134 break; 17135 case LAYOUT_DIRECTION_LTR: 17136 default: 17137 if (mUserPaddingStart != UNDEFINED_PADDING) { 17138 mUserPaddingLeft = mUserPaddingStart; 17139 } else { 17140 mUserPaddingLeft = mUserPaddingLeftInitial; 17141 } 17142 if (mUserPaddingEnd != UNDEFINED_PADDING) { 17143 mUserPaddingRight = mUserPaddingEnd; 17144 } else { 17145 mUserPaddingRight = mUserPaddingRightInitial; 17146 } 17147 } 17148 17149 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 17150 } 17151 17152 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 17153 onRtlPropertiesChanged(resolvedLayoutDirection); 17154 17155 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 17156 } 17157 17158 /** 17159 * Reset the resolved layout direction. 17160 * 17161 * @hide 17162 */ 17163 public void resetResolvedPadding() { 17164 resetResolvedPaddingInternal(); 17165 } 17166 17167 /** 17168 * Used when we only want to reset *this* view's padding and not trigger overrides 17169 * in ViewGroup that reset children too. 17170 */ 17171 void resetResolvedPaddingInternal() { 17172 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 17173 } 17174 17175 /** 17176 * This is called when the view is detached from a window. At this point it 17177 * no longer has a surface for drawing. 17178 * 17179 * @see #onAttachedToWindow() 17180 */ 17181 @CallSuper 17182 protected void onDetachedFromWindow() { 17183 } 17184 17185 /** 17186 * This is a framework-internal mirror of onDetachedFromWindow() that's called 17187 * after onDetachedFromWindow(). 17188 * 17189 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 17190 * The super method should be called at the end of the overridden method to ensure 17191 * subclasses are destroyed first 17192 * 17193 * @hide 17194 */ 17195 @CallSuper 17196 protected void onDetachedFromWindowInternal() { 17197 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 17198 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 17199 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 17200 17201 removeUnsetPressCallback(); 17202 removeLongPressCallback(); 17203 removePerformClickCallback(); 17204 removeSendViewScrolledAccessibilityEventCallback(); 17205 stopNestedScroll(); 17206 17207 // Anything that started animating right before detach should already 17208 // be in its final state when re-attached. 17209 jumpDrawablesToCurrentState(); 17210 17211 destroyDrawingCache(); 17212 17213 cleanupDraw(); 17214 mCurrentAnimation = null; 17215 17216 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 17217 hideTooltip(); 17218 } 17219 } 17220 17221 private void cleanupDraw() { 17222 resetDisplayList(); 17223 if (mAttachInfo != null) { 17224 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 17225 } 17226 } 17227 17228 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 17229 } 17230 17231 /** 17232 * @return The number of times this view has been attached to a window 17233 */ 17234 protected int getWindowAttachCount() { 17235 return mWindowAttachCount; 17236 } 17237 17238 /** 17239 * Retrieve a unique token identifying the window this view is attached to. 17240 * @return Return the window's token for use in 17241 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 17242 */ 17243 public IBinder getWindowToken() { 17244 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 17245 } 17246 17247 /** 17248 * Retrieve the {@link WindowId} for the window this view is 17249 * currently attached to. 17250 */ 17251 public WindowId getWindowId() { 17252 if (mAttachInfo == null) { 17253 return null; 17254 } 17255 if (mAttachInfo.mWindowId == null) { 17256 try { 17257 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 17258 mAttachInfo.mWindowToken); 17259 mAttachInfo.mWindowId = new WindowId( 17260 mAttachInfo.mIWindowId); 17261 } catch (RemoteException e) { 17262 } 17263 } 17264 return mAttachInfo.mWindowId; 17265 } 17266 17267 /** 17268 * Retrieve a unique token identifying the top-level "real" window of 17269 * the window that this view is attached to. That is, this is like 17270 * {@link #getWindowToken}, except if the window this view in is a panel 17271 * window (attached to another containing window), then the token of 17272 * the containing window is returned instead. 17273 * 17274 * @return Returns the associated window token, either 17275 * {@link #getWindowToken()} or the containing window's token. 17276 */ 17277 public IBinder getApplicationWindowToken() { 17278 AttachInfo ai = mAttachInfo; 17279 if (ai != null) { 17280 IBinder appWindowToken = ai.mPanelParentWindowToken; 17281 if (appWindowToken == null) { 17282 appWindowToken = ai.mWindowToken; 17283 } 17284 return appWindowToken; 17285 } 17286 return null; 17287 } 17288 17289 /** 17290 * Gets the logical display to which the view's window has been attached. 17291 * 17292 * @return The logical display, or null if the view is not currently attached to a window. 17293 */ 17294 public Display getDisplay() { 17295 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 17296 } 17297 17298 /** 17299 * Retrieve private session object this view hierarchy is using to 17300 * communicate with the window manager. 17301 * @return the session object to communicate with the window manager 17302 */ 17303 /*package*/ IWindowSession getWindowSession() { 17304 return mAttachInfo != null ? mAttachInfo.mSession : null; 17305 } 17306 17307 /** 17308 * Return the visibility value of the least visible component passed. 17309 */ 17310 int combineVisibility(int vis1, int vis2) { 17311 // This works because VISIBLE < INVISIBLE < GONE. 17312 return Math.max(vis1, vis2); 17313 } 17314 17315 /** 17316 * @param info the {@link android.view.View.AttachInfo} to associated with 17317 * this view 17318 */ 17319 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 17320 mAttachInfo = info; 17321 if (mOverlay != null) { 17322 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 17323 } 17324 mWindowAttachCount++; 17325 // We will need to evaluate the drawable state at least once. 17326 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 17327 if (mFloatingTreeObserver != null) { 17328 info.mTreeObserver.merge(mFloatingTreeObserver); 17329 mFloatingTreeObserver = null; 17330 } 17331 17332 registerPendingFrameMetricsObservers(); 17333 17334 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 17335 mAttachInfo.mScrollContainers.add(this); 17336 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 17337 } 17338 // Transfer all pending runnables. 17339 if (mRunQueue != null) { 17340 mRunQueue.executeActions(info.mHandler); 17341 mRunQueue = null; 17342 } 17343 performCollectViewAttributes(mAttachInfo, visibility); 17344 onAttachedToWindow(); 17345 17346 ListenerInfo li = mListenerInfo; 17347 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 17348 li != null ? li.mOnAttachStateChangeListeners : null; 17349 if (listeners != null && listeners.size() > 0) { 17350 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 17351 // perform the dispatching. The iterator is a safe guard against listeners that 17352 // could mutate the list by calling the various add/remove methods. This prevents 17353 // the array from being modified while we iterate it. 17354 for (OnAttachStateChangeListener listener : listeners) { 17355 listener.onViewAttachedToWindow(this); 17356 } 17357 } 17358 17359 int vis = info.mWindowVisibility; 17360 if (vis != GONE) { 17361 onWindowVisibilityChanged(vis); 17362 if (isShown()) { 17363 // Calling onVisibilityAggregated directly here since the subtree will also 17364 // receive dispatchAttachedToWindow and this same call 17365 onVisibilityAggregated(vis == VISIBLE); 17366 } 17367 } 17368 17369 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 17370 // As all views in the subtree will already receive dispatchAttachedToWindow 17371 // traversing the subtree again here is not desired. 17372 onVisibilityChanged(this, visibility); 17373 17374 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 17375 // If nobody has evaluated the drawable state yet, then do it now. 17376 refreshDrawableState(); 17377 } 17378 needGlobalAttributesUpdate(false); 17379 17380 notifyEnterOrExitForAutoFillIfNeeded(true); 17381 } 17382 17383 void dispatchDetachedFromWindow() { 17384 AttachInfo info = mAttachInfo; 17385 if (info != null) { 17386 int vis = info.mWindowVisibility; 17387 if (vis != GONE) { 17388 onWindowVisibilityChanged(GONE); 17389 if (isShown()) { 17390 // Invoking onVisibilityAggregated directly here since the subtree 17391 // will also receive detached from window 17392 onVisibilityAggregated(false); 17393 } 17394 } 17395 } 17396 17397 onDetachedFromWindow(); 17398 onDetachedFromWindowInternal(); 17399 17400 InputMethodManager imm = InputMethodManager.peekInstance(); 17401 if (imm != null) { 17402 imm.onViewDetachedFromWindow(this); 17403 } 17404 17405 ListenerInfo li = mListenerInfo; 17406 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 17407 li != null ? li.mOnAttachStateChangeListeners : null; 17408 if (listeners != null && listeners.size() > 0) { 17409 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 17410 // perform the dispatching. The iterator is a safe guard against listeners that 17411 // could mutate the list by calling the various add/remove methods. This prevents 17412 // the array from being modified while we iterate it. 17413 for (OnAttachStateChangeListener listener : listeners) { 17414 listener.onViewDetachedFromWindow(this); 17415 } 17416 } 17417 17418 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 17419 mAttachInfo.mScrollContainers.remove(this); 17420 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 17421 } 17422 17423 mAttachInfo = null; 17424 if (mOverlay != null) { 17425 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 17426 } 17427 17428 notifyEnterOrExitForAutoFillIfNeeded(false); 17429 } 17430 17431 /** 17432 * Cancel any deferred high-level input events that were previously posted to the event queue. 17433 * 17434 * <p>Many views post high-level events such as click handlers to the event queue 17435 * to run deferred in order to preserve a desired user experience - clearing visible 17436 * pressed states before executing, etc. This method will abort any events of this nature 17437 * that are currently in flight.</p> 17438 * 17439 * <p>Custom views that generate their own high-level deferred input events should override 17440 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 17441 * 17442 * <p>This will also cancel pending input events for any child views.</p> 17443 * 17444 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 17445 * This will not impact newer events posted after this call that may occur as a result of 17446 * lower-level input events still waiting in the queue. If you are trying to prevent 17447 * double-submitted events for the duration of some sort of asynchronous transaction 17448 * you should also take other steps to protect against unexpected double inputs e.g. calling 17449 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 17450 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 17451 */ 17452 public final void cancelPendingInputEvents() { 17453 dispatchCancelPendingInputEvents(); 17454 } 17455 17456 /** 17457 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 17458 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 17459 */ 17460 void dispatchCancelPendingInputEvents() { 17461 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 17462 onCancelPendingInputEvents(); 17463 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 17464 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 17465 " did not call through to super.onCancelPendingInputEvents()"); 17466 } 17467 } 17468 17469 /** 17470 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 17471 * a parent view. 17472 * 17473 * <p>This method is responsible for removing any pending high-level input events that were 17474 * posted to the event queue to run later. Custom view classes that post their own deferred 17475 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 17476 * {@link android.os.Handler} should override this method, call 17477 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 17478 * </p> 17479 */ 17480 public void onCancelPendingInputEvents() { 17481 removePerformClickCallback(); 17482 cancelLongPress(); 17483 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 17484 } 17485 17486 /** 17487 * Store this view hierarchy's frozen state into the given container. 17488 * 17489 * @param container The SparseArray in which to save the view's state. 17490 * 17491 * @see #restoreHierarchyState(android.util.SparseArray) 17492 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17493 * @see #onSaveInstanceState() 17494 */ 17495 public void saveHierarchyState(SparseArray<Parcelable> container) { 17496 dispatchSaveInstanceState(container); 17497 } 17498 17499 /** 17500 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 17501 * this view and its children. May be overridden to modify how freezing happens to a 17502 * view's children; for example, some views may want to not store state for their children. 17503 * 17504 * @param container The SparseArray in which to save the view's state. 17505 * 17506 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17507 * @see #saveHierarchyState(android.util.SparseArray) 17508 * @see #onSaveInstanceState() 17509 */ 17510 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 17511 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 17512 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17513 Parcelable state = onSaveInstanceState(); 17514 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17515 throw new IllegalStateException( 17516 "Derived class did not call super.onSaveInstanceState()"); 17517 } 17518 if (state != null) { 17519 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 17520 // + ": " + state); 17521 container.put(mID, state); 17522 } 17523 } 17524 } 17525 17526 /** 17527 * Hook allowing a view to generate a representation of its internal state 17528 * that can later be used to create a new instance with that same state. 17529 * This state should only contain information that is not persistent or can 17530 * not be reconstructed later. For example, you will never store your 17531 * current position on screen because that will be computed again when a 17532 * new instance of the view is placed in its view hierarchy. 17533 * <p> 17534 * Some examples of things you may store here: the current cursor position 17535 * in a text view (but usually not the text itself since that is stored in a 17536 * content provider or other persistent storage), the currently selected 17537 * item in a list view. 17538 * 17539 * @return Returns a Parcelable object containing the view's current dynamic 17540 * state, or null if there is nothing interesting to save. 17541 * @see #onRestoreInstanceState(android.os.Parcelable) 17542 * @see #saveHierarchyState(android.util.SparseArray) 17543 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17544 * @see #setSaveEnabled(boolean) 17545 */ 17546 @CallSuper 17547 @Nullable protected Parcelable onSaveInstanceState() { 17548 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17549 if (mStartActivityRequestWho != null || isAutofilled() 17550 || mAccessibilityViewId > LAST_APP_ACCESSIBILITY_ID) { 17551 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 17552 17553 if (mStartActivityRequestWho != null) { 17554 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 17555 } 17556 17557 if (isAutofilled()) { 17558 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 17559 } 17560 17561 if (mAccessibilityViewId > LAST_APP_ACCESSIBILITY_ID) { 17562 state.mSavedData |= BaseSavedState.ACCESSIBILITY_ID; 17563 } 17564 17565 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 17566 state.mIsAutofilled = isAutofilled(); 17567 state.mAccessibilityViewId = mAccessibilityViewId; 17568 return state; 17569 } 17570 return BaseSavedState.EMPTY_STATE; 17571 } 17572 17573 /** 17574 * Restore this view hierarchy's frozen state from the given container. 17575 * 17576 * @param container The SparseArray which holds previously frozen states. 17577 * 17578 * @see #saveHierarchyState(android.util.SparseArray) 17579 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17580 * @see #onRestoreInstanceState(android.os.Parcelable) 17581 */ 17582 public void restoreHierarchyState(SparseArray<Parcelable> container) { 17583 dispatchRestoreInstanceState(container); 17584 } 17585 17586 /** 17587 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 17588 * state for this view and its children. May be overridden to modify how restoring 17589 * happens to a view's children; for example, some views may want to not store state 17590 * for their children. 17591 * 17592 * @param container The SparseArray which holds previously saved state. 17593 * 17594 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17595 * @see #restoreHierarchyState(android.util.SparseArray) 17596 * @see #onRestoreInstanceState(android.os.Parcelable) 17597 */ 17598 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 17599 if (mID != NO_ID) { 17600 Parcelable state = container.get(mID); 17601 if (state != null) { 17602 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 17603 // + ": " + state); 17604 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17605 onRestoreInstanceState(state); 17606 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17607 throw new IllegalStateException( 17608 "Derived class did not call super.onRestoreInstanceState()"); 17609 } 17610 } 17611 } 17612 } 17613 17614 /** 17615 * Hook allowing a view to re-apply a representation of its internal state that had previously 17616 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 17617 * null state. 17618 * 17619 * @param state The frozen state that had previously been returned by 17620 * {@link #onSaveInstanceState}. 17621 * 17622 * @see #onSaveInstanceState() 17623 * @see #restoreHierarchyState(android.util.SparseArray) 17624 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17625 */ 17626 @CallSuper 17627 protected void onRestoreInstanceState(Parcelable state) { 17628 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17629 if (state != null && !(state instanceof AbsSavedState)) { 17630 throw new IllegalArgumentException("Wrong state class, expecting View State but " 17631 + "received " + state.getClass().toString() + " instead. This usually happens " 17632 + "when two views of different type have the same id in the same hierarchy. " 17633 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 17634 + "other views do not use the same id."); 17635 } 17636 if (state != null && state instanceof BaseSavedState) { 17637 BaseSavedState baseState = (BaseSavedState) state; 17638 17639 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 17640 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 17641 } 17642 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 17643 setAutofilled(baseState.mIsAutofilled); 17644 } 17645 if ((baseState.mSavedData & BaseSavedState.ACCESSIBILITY_ID) != 0) { 17646 mAccessibilityViewId = baseState.mAccessibilityViewId; 17647 } 17648 } 17649 } 17650 17651 /** 17652 * <p>Return the time at which the drawing of the view hierarchy started.</p> 17653 * 17654 * @return the drawing start time in milliseconds 17655 */ 17656 public long getDrawingTime() { 17657 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 17658 } 17659 17660 /** 17661 * <p>Enables or disables the duplication of the parent's state into this view. When 17662 * duplication is enabled, this view gets its drawable state from its parent rather 17663 * than from its own internal properties.</p> 17664 * 17665 * <p>Note: in the current implementation, setting this property to true after the 17666 * view was added to a ViewGroup might have no effect at all. This property should 17667 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 17668 * 17669 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 17670 * property is enabled, an exception will be thrown.</p> 17671 * 17672 * <p>Note: if the child view uses and updates additional states which are unknown to the 17673 * parent, these states should not be affected by this method.</p> 17674 * 17675 * @param enabled True to enable duplication of the parent's drawable state, false 17676 * to disable it. 17677 * 17678 * @see #getDrawableState() 17679 * @see #isDuplicateParentStateEnabled() 17680 */ 17681 public void setDuplicateParentStateEnabled(boolean enabled) { 17682 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 17683 } 17684 17685 /** 17686 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 17687 * 17688 * @return True if this view's drawable state is duplicated from the parent, 17689 * false otherwise 17690 * 17691 * @see #getDrawableState() 17692 * @see #setDuplicateParentStateEnabled(boolean) 17693 */ 17694 public boolean isDuplicateParentStateEnabled() { 17695 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 17696 } 17697 17698 /** 17699 * <p>Specifies the type of layer backing this view. The layer can be 17700 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17701 * {@link #LAYER_TYPE_HARDWARE}.</p> 17702 * 17703 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17704 * instance that controls how the layer is composed on screen. The following 17705 * properties of the paint are taken into account when composing the layer:</p> 17706 * <ul> 17707 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17708 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17709 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17710 * </ul> 17711 * 17712 * <p>If this view has an alpha value set to < 1.0 by calling 17713 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 17714 * by this view's alpha value.</p> 17715 * 17716 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 17717 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 17718 * for more information on when and how to use layers.</p> 17719 * 17720 * @param layerType The type of layer to use with this view, must be one of 17721 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17722 * {@link #LAYER_TYPE_HARDWARE} 17723 * @param paint The paint used to compose the layer. This argument is optional 17724 * and can be null. It is ignored when the layer type is 17725 * {@link #LAYER_TYPE_NONE} 17726 * 17727 * @see #getLayerType() 17728 * @see #LAYER_TYPE_NONE 17729 * @see #LAYER_TYPE_SOFTWARE 17730 * @see #LAYER_TYPE_HARDWARE 17731 * @see #setAlpha(float) 17732 * 17733 * @attr ref android.R.styleable#View_layerType 17734 */ 17735 public void setLayerType(int layerType, @Nullable Paint paint) { 17736 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 17737 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 17738 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 17739 } 17740 17741 boolean typeChanged = mRenderNode.setLayerType(layerType); 17742 17743 if (!typeChanged) { 17744 setLayerPaint(paint); 17745 return; 17746 } 17747 17748 if (layerType != LAYER_TYPE_SOFTWARE) { 17749 // Destroy any previous software drawing cache if present 17750 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 17751 // drawing cache created in View#draw when drawing to a SW canvas. 17752 destroyDrawingCache(); 17753 } 17754 17755 mLayerType = layerType; 17756 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 17757 mRenderNode.setLayerPaint(mLayerPaint); 17758 17759 // draw() behaves differently if we are on a layer, so we need to 17760 // invalidate() here 17761 invalidateParentCaches(); 17762 invalidate(true); 17763 } 17764 17765 /** 17766 * Updates the {@link Paint} object used with the current layer (used only if the current 17767 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 17768 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 17769 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 17770 * ensure that the view gets redrawn immediately. 17771 * 17772 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17773 * instance that controls how the layer is composed on screen. The following 17774 * properties of the paint are taken into account when composing the layer:</p> 17775 * <ul> 17776 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17777 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17778 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17779 * </ul> 17780 * 17781 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 17782 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 17783 * 17784 * @param paint The paint used to compose the layer. This argument is optional 17785 * and can be null. It is ignored when the layer type is 17786 * {@link #LAYER_TYPE_NONE} 17787 * 17788 * @see #setLayerType(int, android.graphics.Paint) 17789 */ 17790 public void setLayerPaint(@Nullable Paint paint) { 17791 int layerType = getLayerType(); 17792 if (layerType != LAYER_TYPE_NONE) { 17793 mLayerPaint = paint; 17794 if (layerType == LAYER_TYPE_HARDWARE) { 17795 if (mRenderNode.setLayerPaint(paint)) { 17796 invalidateViewProperty(false, false); 17797 } 17798 } else { 17799 invalidate(); 17800 } 17801 } 17802 } 17803 17804 /** 17805 * Indicates what type of layer is currently associated with this view. By default 17806 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 17807 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 17808 * for more information on the different types of layers. 17809 * 17810 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17811 * {@link #LAYER_TYPE_HARDWARE} 17812 * 17813 * @see #setLayerType(int, android.graphics.Paint) 17814 * @see #buildLayer() 17815 * @see #LAYER_TYPE_NONE 17816 * @see #LAYER_TYPE_SOFTWARE 17817 * @see #LAYER_TYPE_HARDWARE 17818 */ 17819 public int getLayerType() { 17820 return mLayerType; 17821 } 17822 17823 /** 17824 * Forces this view's layer to be created and this view to be rendered 17825 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 17826 * invoking this method will have no effect. 17827 * 17828 * This method can for instance be used to render a view into its layer before 17829 * starting an animation. If this view is complex, rendering into the layer 17830 * before starting the animation will avoid skipping frames. 17831 * 17832 * @throws IllegalStateException If this view is not attached to a window 17833 * 17834 * @see #setLayerType(int, android.graphics.Paint) 17835 */ 17836 public void buildLayer() { 17837 if (mLayerType == LAYER_TYPE_NONE) return; 17838 17839 final AttachInfo attachInfo = mAttachInfo; 17840 if (attachInfo == null) { 17841 throw new IllegalStateException("This view must be attached to a window first"); 17842 } 17843 17844 if (getWidth() == 0 || getHeight() == 0) { 17845 return; 17846 } 17847 17848 switch (mLayerType) { 17849 case LAYER_TYPE_HARDWARE: 17850 updateDisplayListIfDirty(); 17851 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 17852 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 17853 } 17854 break; 17855 case LAYER_TYPE_SOFTWARE: 17856 buildDrawingCache(true); 17857 break; 17858 } 17859 } 17860 17861 /** 17862 * Destroys all hardware rendering resources. This method is invoked 17863 * when the system needs to reclaim resources. Upon execution of this 17864 * method, you should free any OpenGL resources created by the view. 17865 * 17866 * Note: you <strong>must</strong> call 17867 * <code>super.destroyHardwareResources()</code> when overriding 17868 * this method. 17869 * 17870 * @hide 17871 */ 17872 @CallSuper 17873 protected void destroyHardwareResources() { 17874 if (mOverlay != null) { 17875 mOverlay.getOverlayView().destroyHardwareResources(); 17876 } 17877 if (mGhostView != null) { 17878 mGhostView.destroyHardwareResources(); 17879 } 17880 } 17881 17882 /** 17883 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 17884 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 17885 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 17886 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 17887 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 17888 * null.</p> 17889 * 17890 * <p>Enabling the drawing cache is similar to 17891 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 17892 * acceleration is turned off. When hardware acceleration is turned on, enabling the 17893 * drawing cache has no effect on rendering because the system uses a different mechanism 17894 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 17895 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 17896 * for information on how to enable software and hardware layers.</p> 17897 * 17898 * <p>This API can be used to manually generate 17899 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 17900 * {@link #getDrawingCache()}.</p> 17901 * 17902 * @param enabled true to enable the drawing cache, false otherwise 17903 * 17904 * @see #isDrawingCacheEnabled() 17905 * @see #getDrawingCache() 17906 * @see #buildDrawingCache() 17907 * @see #setLayerType(int, android.graphics.Paint) 17908 */ 17909 public void setDrawingCacheEnabled(boolean enabled) { 17910 mCachingFailed = false; 17911 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 17912 } 17913 17914 /** 17915 * <p>Indicates whether the drawing cache is enabled for this view.</p> 17916 * 17917 * @return true if the drawing cache is enabled 17918 * 17919 * @see #setDrawingCacheEnabled(boolean) 17920 * @see #getDrawingCache() 17921 */ 17922 @ViewDebug.ExportedProperty(category = "drawing") 17923 public boolean isDrawingCacheEnabled() { 17924 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 17925 } 17926 17927 /** 17928 * Debugging utility which recursively outputs the dirty state of a view and its 17929 * descendants. 17930 * 17931 * @hide 17932 */ 17933 @SuppressWarnings({"UnusedDeclaration"}) 17934 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 17935 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 17936 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 17937 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 17938 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 17939 if (clear) { 17940 mPrivateFlags &= clearMask; 17941 } 17942 if (this instanceof ViewGroup) { 17943 ViewGroup parent = (ViewGroup) this; 17944 final int count = parent.getChildCount(); 17945 for (int i = 0; i < count; i++) { 17946 final View child = parent.getChildAt(i); 17947 child.outputDirtyFlags(indent + " ", clear, clearMask); 17948 } 17949 } 17950 } 17951 17952 /** 17953 * This method is used by ViewGroup to cause its children to restore or recreate their 17954 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 17955 * to recreate its own display list, which would happen if it went through the normal 17956 * draw/dispatchDraw mechanisms. 17957 * 17958 * @hide 17959 */ 17960 protected void dispatchGetDisplayList() {} 17961 17962 /** 17963 * A view that is not attached or hardware accelerated cannot create a display list. 17964 * This method checks these conditions and returns the appropriate result. 17965 * 17966 * @return true if view has the ability to create a display list, false otherwise. 17967 * 17968 * @hide 17969 */ 17970 public boolean canHaveDisplayList() { 17971 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 17972 } 17973 17974 /** 17975 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 17976 * @hide 17977 */ 17978 @NonNull 17979 public RenderNode updateDisplayListIfDirty() { 17980 final RenderNode renderNode = mRenderNode; 17981 if (!canHaveDisplayList()) { 17982 // can't populate RenderNode, don't try 17983 return renderNode; 17984 } 17985 17986 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 17987 || !renderNode.isValid() 17988 || (mRecreateDisplayList)) { 17989 // Don't need to recreate the display list, just need to tell our 17990 // children to restore/recreate theirs 17991 if (renderNode.isValid() 17992 && !mRecreateDisplayList) { 17993 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 17994 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17995 dispatchGetDisplayList(); 17996 17997 return renderNode; // no work needed 17998 } 17999 18000 // If we got here, we're recreating it. Mark it as such to ensure that 18001 // we copy in child display lists into ours in drawChild() 18002 mRecreateDisplayList = true; 18003 18004 int width = mRight - mLeft; 18005 int height = mBottom - mTop; 18006 int layerType = getLayerType(); 18007 18008 final DisplayListCanvas canvas = renderNode.start(width, height); 18009 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 18010 18011 try { 18012 if (layerType == LAYER_TYPE_SOFTWARE) { 18013 buildDrawingCache(true); 18014 Bitmap cache = getDrawingCache(true); 18015 if (cache != null) { 18016 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 18017 } 18018 } else { 18019 computeScroll(); 18020 18021 canvas.translate(-mScrollX, -mScrollY); 18022 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18023 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18024 18025 // Fast path for layouts with no backgrounds 18026 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18027 dispatchDraw(canvas); 18028 drawAutofilledHighlight(canvas); 18029 if (mOverlay != null && !mOverlay.isEmpty()) { 18030 mOverlay.getOverlayView().draw(canvas); 18031 } 18032 if (debugDraw()) { 18033 debugDrawFocus(canvas); 18034 } 18035 } else { 18036 draw(canvas); 18037 } 18038 } 18039 } finally { 18040 renderNode.end(canvas); 18041 setDisplayListProperties(renderNode); 18042 } 18043 } else { 18044 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18045 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18046 } 18047 return renderNode; 18048 } 18049 18050 private void resetDisplayList() { 18051 mRenderNode.discardDisplayList(); 18052 if (mBackgroundRenderNode != null) { 18053 mBackgroundRenderNode.discardDisplayList(); 18054 } 18055 } 18056 18057 /** 18058 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 18059 * 18060 * @return A non-scaled bitmap representing this view or null if cache is disabled. 18061 * 18062 * @see #getDrawingCache(boolean) 18063 */ 18064 public Bitmap getDrawingCache() { 18065 return getDrawingCache(false); 18066 } 18067 18068 /** 18069 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 18070 * is null when caching is disabled. If caching is enabled and the cache is not ready, 18071 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 18072 * draw from the cache when the cache is enabled. To benefit from the cache, you must 18073 * request the drawing cache by calling this method and draw it on screen if the 18074 * returned bitmap is not null.</p> 18075 * 18076 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 18077 * this method will create a bitmap of the same size as this view. Because this bitmap 18078 * will be drawn scaled by the parent ViewGroup, the result on screen might show 18079 * scaling artifacts. To avoid such artifacts, you should call this method by setting 18080 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 18081 * size than the view. This implies that your application must be able to handle this 18082 * size.</p> 18083 * 18084 * @param autoScale Indicates whether the generated bitmap should be scaled based on 18085 * the current density of the screen when the application is in compatibility 18086 * mode. 18087 * 18088 * @return A bitmap representing this view or null if cache is disabled. 18089 * 18090 * @see #setDrawingCacheEnabled(boolean) 18091 * @see #isDrawingCacheEnabled() 18092 * @see #buildDrawingCache(boolean) 18093 * @see #destroyDrawingCache() 18094 */ 18095 public Bitmap getDrawingCache(boolean autoScale) { 18096 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 18097 return null; 18098 } 18099 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 18100 buildDrawingCache(autoScale); 18101 } 18102 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 18103 } 18104 18105 /** 18106 * <p>Frees the resources used by the drawing cache. If you call 18107 * {@link #buildDrawingCache()} manually without calling 18108 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 18109 * should cleanup the cache with this method afterwards.</p> 18110 * 18111 * @see #setDrawingCacheEnabled(boolean) 18112 * @see #buildDrawingCache() 18113 * @see #getDrawingCache() 18114 */ 18115 public void destroyDrawingCache() { 18116 if (mDrawingCache != null) { 18117 mDrawingCache.recycle(); 18118 mDrawingCache = null; 18119 } 18120 if (mUnscaledDrawingCache != null) { 18121 mUnscaledDrawingCache.recycle(); 18122 mUnscaledDrawingCache = null; 18123 } 18124 } 18125 18126 /** 18127 * Setting a solid background color for the drawing cache's bitmaps will improve 18128 * performance and memory usage. Note, though that this should only be used if this 18129 * view will always be drawn on top of a solid color. 18130 * 18131 * @param color The background color to use for the drawing cache's bitmap 18132 * 18133 * @see #setDrawingCacheEnabled(boolean) 18134 * @see #buildDrawingCache() 18135 * @see #getDrawingCache() 18136 */ 18137 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 18138 if (color != mDrawingCacheBackgroundColor) { 18139 mDrawingCacheBackgroundColor = color; 18140 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18141 } 18142 } 18143 18144 /** 18145 * @see #setDrawingCacheBackgroundColor(int) 18146 * 18147 * @return The background color to used for the drawing cache's bitmap 18148 */ 18149 @ColorInt 18150 public int getDrawingCacheBackgroundColor() { 18151 return mDrawingCacheBackgroundColor; 18152 } 18153 18154 /** 18155 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 18156 * 18157 * @see #buildDrawingCache(boolean) 18158 */ 18159 public void buildDrawingCache() { 18160 buildDrawingCache(false); 18161 } 18162 18163 /** 18164 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 18165 * 18166 * <p>If you call {@link #buildDrawingCache()} manually without calling 18167 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 18168 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 18169 * 18170 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 18171 * this method will create a bitmap of the same size as this view. Because this bitmap 18172 * will be drawn scaled by the parent ViewGroup, the result on screen might show 18173 * scaling artifacts. To avoid such artifacts, you should call this method by setting 18174 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 18175 * size than the view. This implies that your application must be able to handle this 18176 * size.</p> 18177 * 18178 * <p>You should avoid calling this method when hardware acceleration is enabled. If 18179 * you do not need the drawing cache bitmap, calling this method will increase memory 18180 * usage and cause the view to be rendered in software once, thus negatively impacting 18181 * performance.</p> 18182 * 18183 * @see #getDrawingCache() 18184 * @see #destroyDrawingCache() 18185 */ 18186 public void buildDrawingCache(boolean autoScale) { 18187 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 18188 mDrawingCache == null : mUnscaledDrawingCache == null)) { 18189 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 18190 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 18191 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 18192 } 18193 try { 18194 buildDrawingCacheImpl(autoScale); 18195 } finally { 18196 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 18197 } 18198 } 18199 } 18200 18201 /** 18202 * private, internal implementation of buildDrawingCache, used to enable tracing 18203 */ 18204 private void buildDrawingCacheImpl(boolean autoScale) { 18205 mCachingFailed = false; 18206 18207 int width = mRight - mLeft; 18208 int height = mBottom - mTop; 18209 18210 final AttachInfo attachInfo = mAttachInfo; 18211 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 18212 18213 if (autoScale && scalingRequired) { 18214 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 18215 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 18216 } 18217 18218 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 18219 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 18220 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 18221 18222 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 18223 final long drawingCacheSize = 18224 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 18225 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 18226 if (width > 0 && height > 0) { 18227 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 18228 + " too large to fit into a software layer (or drawing cache), needs " 18229 + projectedBitmapSize + " bytes, only " 18230 + drawingCacheSize + " available"); 18231 } 18232 destroyDrawingCache(); 18233 mCachingFailed = true; 18234 return; 18235 } 18236 18237 boolean clear = true; 18238 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 18239 18240 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 18241 Bitmap.Config quality; 18242 if (!opaque) { 18243 // Never pick ARGB_4444 because it looks awful 18244 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 18245 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 18246 case DRAWING_CACHE_QUALITY_AUTO: 18247 case DRAWING_CACHE_QUALITY_LOW: 18248 case DRAWING_CACHE_QUALITY_HIGH: 18249 default: 18250 quality = Bitmap.Config.ARGB_8888; 18251 break; 18252 } 18253 } else { 18254 // Optimization for translucent windows 18255 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 18256 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 18257 } 18258 18259 // Try to cleanup memory 18260 if (bitmap != null) bitmap.recycle(); 18261 18262 try { 18263 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 18264 width, height, quality); 18265 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 18266 if (autoScale) { 18267 mDrawingCache = bitmap; 18268 } else { 18269 mUnscaledDrawingCache = bitmap; 18270 } 18271 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 18272 } catch (OutOfMemoryError e) { 18273 // If there is not enough memory to create the bitmap cache, just 18274 // ignore the issue as bitmap caches are not required to draw the 18275 // view hierarchy 18276 if (autoScale) { 18277 mDrawingCache = null; 18278 } else { 18279 mUnscaledDrawingCache = null; 18280 } 18281 mCachingFailed = true; 18282 return; 18283 } 18284 18285 clear = drawingCacheBackgroundColor != 0; 18286 } 18287 18288 Canvas canvas; 18289 if (attachInfo != null) { 18290 canvas = attachInfo.mCanvas; 18291 if (canvas == null) { 18292 canvas = new Canvas(); 18293 } 18294 canvas.setBitmap(bitmap); 18295 // Temporarily clobber the cached Canvas in case one of our children 18296 // is also using a drawing cache. Without this, the children would 18297 // steal the canvas by attaching their own bitmap to it and bad, bad 18298 // thing would happen (invisible views, corrupted drawings, etc.) 18299 attachInfo.mCanvas = null; 18300 } else { 18301 // This case should hopefully never or seldom happen 18302 canvas = new Canvas(bitmap); 18303 } 18304 18305 if (clear) { 18306 bitmap.eraseColor(drawingCacheBackgroundColor); 18307 } 18308 18309 computeScroll(); 18310 final int restoreCount = canvas.save(); 18311 18312 if (autoScale && scalingRequired) { 18313 final float scale = attachInfo.mApplicationScale; 18314 canvas.scale(scale, scale); 18315 } 18316 18317 canvas.translate(-mScrollX, -mScrollY); 18318 18319 mPrivateFlags |= PFLAG_DRAWN; 18320 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 18321 mLayerType != LAYER_TYPE_NONE) { 18322 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 18323 } 18324 18325 // Fast path for layouts with no backgrounds 18326 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18327 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18328 dispatchDraw(canvas); 18329 drawAutofilledHighlight(canvas); 18330 if (mOverlay != null && !mOverlay.isEmpty()) { 18331 mOverlay.getOverlayView().draw(canvas); 18332 } 18333 } else { 18334 draw(canvas); 18335 } 18336 18337 canvas.restoreToCount(restoreCount); 18338 canvas.setBitmap(null); 18339 18340 if (attachInfo != null) { 18341 // Restore the cached Canvas for our siblings 18342 attachInfo.mCanvas = canvas; 18343 } 18344 } 18345 18346 /** 18347 * Create a snapshot of the view into a bitmap. We should probably make 18348 * some form of this public, but should think about the API. 18349 * 18350 * @hide 18351 */ 18352 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 18353 int width = mRight - mLeft; 18354 int height = mBottom - mTop; 18355 18356 final AttachInfo attachInfo = mAttachInfo; 18357 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 18358 width = (int) ((width * scale) + 0.5f); 18359 height = (int) ((height * scale) + 0.5f); 18360 18361 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 18362 width > 0 ? width : 1, height > 0 ? height : 1, quality); 18363 if (bitmap == null) { 18364 throw new OutOfMemoryError(); 18365 } 18366 18367 Resources resources = getResources(); 18368 if (resources != null) { 18369 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 18370 } 18371 18372 Canvas canvas; 18373 if (attachInfo != null) { 18374 canvas = attachInfo.mCanvas; 18375 if (canvas == null) { 18376 canvas = new Canvas(); 18377 } 18378 canvas.setBitmap(bitmap); 18379 // Temporarily clobber the cached Canvas in case one of our children 18380 // is also using a drawing cache. Without this, the children would 18381 // steal the canvas by attaching their own bitmap to it and bad, bad 18382 // things would happen (invisible views, corrupted drawings, etc.) 18383 attachInfo.mCanvas = null; 18384 } else { 18385 // This case should hopefully never or seldom happen 18386 canvas = new Canvas(bitmap); 18387 } 18388 boolean enabledHwBitmapsInSwMode = canvas.isHwBitmapsInSwModeEnabled(); 18389 canvas.setHwBitmapsInSwModeEnabled(true); 18390 if ((backgroundColor & 0xff000000) != 0) { 18391 bitmap.eraseColor(backgroundColor); 18392 } 18393 18394 computeScroll(); 18395 final int restoreCount = canvas.save(); 18396 canvas.scale(scale, scale); 18397 canvas.translate(-mScrollX, -mScrollY); 18398 18399 // Temporarily remove the dirty mask 18400 int flags = mPrivateFlags; 18401 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18402 18403 // Fast path for layouts with no backgrounds 18404 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18405 dispatchDraw(canvas); 18406 drawAutofilledHighlight(canvas); 18407 if (mOverlay != null && !mOverlay.isEmpty()) { 18408 mOverlay.getOverlayView().draw(canvas); 18409 } 18410 } else { 18411 draw(canvas); 18412 } 18413 18414 mPrivateFlags = flags; 18415 18416 canvas.restoreToCount(restoreCount); 18417 canvas.setBitmap(null); 18418 canvas.setHwBitmapsInSwModeEnabled(enabledHwBitmapsInSwMode); 18419 18420 if (attachInfo != null) { 18421 // Restore the cached Canvas for our siblings 18422 attachInfo.mCanvas = canvas; 18423 } 18424 18425 return bitmap; 18426 } 18427 18428 /** 18429 * Indicates whether this View is currently in edit mode. A View is usually 18430 * in edit mode when displayed within a developer tool. For instance, if 18431 * this View is being drawn by a visual user interface builder, this method 18432 * should return true. 18433 * 18434 * Subclasses should check the return value of this method to provide 18435 * different behaviors if their normal behavior might interfere with the 18436 * host environment. For instance: the class spawns a thread in its 18437 * constructor, the drawing code relies on device-specific features, etc. 18438 * 18439 * This method is usually checked in the drawing code of custom widgets. 18440 * 18441 * @return True if this View is in edit mode, false otherwise. 18442 */ 18443 public boolean isInEditMode() { 18444 return false; 18445 } 18446 18447 /** 18448 * If the View draws content inside its padding and enables fading edges, 18449 * it needs to support padding offsets. Padding offsets are added to the 18450 * fading edges to extend the length of the fade so that it covers pixels 18451 * drawn inside the padding. 18452 * 18453 * Subclasses of this class should override this method if they need 18454 * to draw content inside the padding. 18455 * 18456 * @return True if padding offset must be applied, false otherwise. 18457 * 18458 * @see #getLeftPaddingOffset() 18459 * @see #getRightPaddingOffset() 18460 * @see #getTopPaddingOffset() 18461 * @see #getBottomPaddingOffset() 18462 * 18463 * @since CURRENT 18464 */ 18465 protected boolean isPaddingOffsetRequired() { 18466 return false; 18467 } 18468 18469 /** 18470 * Amount by which to extend the left fading region. Called only when 18471 * {@link #isPaddingOffsetRequired()} returns true. 18472 * 18473 * @return The left padding offset in pixels. 18474 * 18475 * @see #isPaddingOffsetRequired() 18476 * 18477 * @since CURRENT 18478 */ 18479 protected int getLeftPaddingOffset() { 18480 return 0; 18481 } 18482 18483 /** 18484 * Amount by which to extend the right fading region. Called only when 18485 * {@link #isPaddingOffsetRequired()} returns true. 18486 * 18487 * @return The right padding offset in pixels. 18488 * 18489 * @see #isPaddingOffsetRequired() 18490 * 18491 * @since CURRENT 18492 */ 18493 protected int getRightPaddingOffset() { 18494 return 0; 18495 } 18496 18497 /** 18498 * Amount by which to extend the top fading region. Called only when 18499 * {@link #isPaddingOffsetRequired()} returns true. 18500 * 18501 * @return The top padding offset in pixels. 18502 * 18503 * @see #isPaddingOffsetRequired() 18504 * 18505 * @since CURRENT 18506 */ 18507 protected int getTopPaddingOffset() { 18508 return 0; 18509 } 18510 18511 /** 18512 * Amount by which to extend the bottom fading region. Called only when 18513 * {@link #isPaddingOffsetRequired()} returns true. 18514 * 18515 * @return The bottom padding offset in pixels. 18516 * 18517 * @see #isPaddingOffsetRequired() 18518 * 18519 * @since CURRENT 18520 */ 18521 protected int getBottomPaddingOffset() { 18522 return 0; 18523 } 18524 18525 /** 18526 * @hide 18527 * @param offsetRequired 18528 */ 18529 protected int getFadeTop(boolean offsetRequired) { 18530 int top = mPaddingTop; 18531 if (offsetRequired) top += getTopPaddingOffset(); 18532 return top; 18533 } 18534 18535 /** 18536 * @hide 18537 * @param offsetRequired 18538 */ 18539 protected int getFadeHeight(boolean offsetRequired) { 18540 int padding = mPaddingTop; 18541 if (offsetRequired) padding += getTopPaddingOffset(); 18542 return mBottom - mTop - mPaddingBottom - padding; 18543 } 18544 18545 /** 18546 * <p>Indicates whether this view is attached to a hardware accelerated 18547 * window or not.</p> 18548 * 18549 * <p>Even if this method returns true, it does not mean that every call 18550 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 18551 * accelerated {@link android.graphics.Canvas}. For instance, if this view 18552 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 18553 * window is hardware accelerated, 18554 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 18555 * return false, and this method will return true.</p> 18556 * 18557 * @return True if the view is attached to a window and the window is 18558 * hardware accelerated; false in any other case. 18559 */ 18560 @ViewDebug.ExportedProperty(category = "drawing") 18561 public boolean isHardwareAccelerated() { 18562 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 18563 } 18564 18565 /** 18566 * Sets a rectangular area on this view to which the view will be clipped 18567 * when it is drawn. Setting the value to null will remove the clip bounds 18568 * and the view will draw normally, using its full bounds. 18569 * 18570 * @param clipBounds The rectangular area, in the local coordinates of 18571 * this view, to which future drawing operations will be clipped. 18572 */ 18573 public void setClipBounds(Rect clipBounds) { 18574 if (clipBounds == mClipBounds 18575 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 18576 return; 18577 } 18578 if (clipBounds != null) { 18579 if (mClipBounds == null) { 18580 mClipBounds = new Rect(clipBounds); 18581 } else { 18582 mClipBounds.set(clipBounds); 18583 } 18584 } else { 18585 mClipBounds = null; 18586 } 18587 mRenderNode.setClipBounds(mClipBounds); 18588 invalidateViewProperty(false, false); 18589 } 18590 18591 /** 18592 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 18593 * 18594 * @return A copy of the current clip bounds if clip bounds are set, 18595 * otherwise null. 18596 */ 18597 public Rect getClipBounds() { 18598 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 18599 } 18600 18601 18602 /** 18603 * Populates an output rectangle with the clip bounds of the view, 18604 * returning {@code true} if successful or {@code false} if the view's 18605 * clip bounds are {@code null}. 18606 * 18607 * @param outRect rectangle in which to place the clip bounds of the view 18608 * @return {@code true} if successful or {@code false} if the view's 18609 * clip bounds are {@code null} 18610 */ 18611 public boolean getClipBounds(Rect outRect) { 18612 if (mClipBounds != null) { 18613 outRect.set(mClipBounds); 18614 return true; 18615 } 18616 return false; 18617 } 18618 18619 /** 18620 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 18621 * case of an active Animation being run on the view. 18622 */ 18623 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 18624 Animation a, boolean scalingRequired) { 18625 Transformation invalidationTransform; 18626 final int flags = parent.mGroupFlags; 18627 final boolean initialized = a.isInitialized(); 18628 if (!initialized) { 18629 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 18630 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 18631 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 18632 onAnimationStart(); 18633 } 18634 18635 final Transformation t = parent.getChildTransformation(); 18636 boolean more = a.getTransformation(drawingTime, t, 1f); 18637 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 18638 if (parent.mInvalidationTransformation == null) { 18639 parent.mInvalidationTransformation = new Transformation(); 18640 } 18641 invalidationTransform = parent.mInvalidationTransformation; 18642 a.getTransformation(drawingTime, invalidationTransform, 1f); 18643 } else { 18644 invalidationTransform = t; 18645 } 18646 18647 if (more) { 18648 if (!a.willChangeBounds()) { 18649 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 18650 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 18651 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 18652 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 18653 // The child need to draw an animation, potentially offscreen, so 18654 // make sure we do not cancel invalidate requests 18655 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18656 parent.invalidate(mLeft, mTop, mRight, mBottom); 18657 } 18658 } else { 18659 if (parent.mInvalidateRegion == null) { 18660 parent.mInvalidateRegion = new RectF(); 18661 } 18662 final RectF region = parent.mInvalidateRegion; 18663 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 18664 invalidationTransform); 18665 18666 // The child need to draw an animation, potentially offscreen, so 18667 // make sure we do not cancel invalidate requests 18668 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18669 18670 final int left = mLeft + (int) region.left; 18671 final int top = mTop + (int) region.top; 18672 parent.invalidate(left, top, left + (int) (region.width() + .5f), 18673 top + (int) (region.height() + .5f)); 18674 } 18675 } 18676 return more; 18677 } 18678 18679 /** 18680 * This method is called by getDisplayList() when a display list is recorded for a View. 18681 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 18682 */ 18683 void setDisplayListProperties(RenderNode renderNode) { 18684 if (renderNode != null) { 18685 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 18686 renderNode.setClipToBounds(mParent instanceof ViewGroup 18687 && ((ViewGroup) mParent).getClipChildren()); 18688 18689 float alpha = 1; 18690 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 18691 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18692 ViewGroup parentVG = (ViewGroup) mParent; 18693 final Transformation t = parentVG.getChildTransformation(); 18694 if (parentVG.getChildStaticTransformation(this, t)) { 18695 final int transformType = t.getTransformationType(); 18696 if (transformType != Transformation.TYPE_IDENTITY) { 18697 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 18698 alpha = t.getAlpha(); 18699 } 18700 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 18701 renderNode.setStaticMatrix(t.getMatrix()); 18702 } 18703 } 18704 } 18705 } 18706 if (mTransformationInfo != null) { 18707 alpha *= getFinalAlpha(); 18708 if (alpha < 1) { 18709 final int multipliedAlpha = (int) (255 * alpha); 18710 if (onSetAlpha(multipliedAlpha)) { 18711 alpha = 1; 18712 } 18713 } 18714 renderNode.setAlpha(alpha); 18715 } else if (alpha < 1) { 18716 renderNode.setAlpha(alpha); 18717 } 18718 } 18719 } 18720 18721 /** 18722 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 18723 * 18724 * This is where the View specializes rendering behavior based on layer type, 18725 * and hardware acceleration. 18726 */ 18727 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 18728 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 18729 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 18730 * 18731 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 18732 * HW accelerated, it can't handle drawing RenderNodes. 18733 */ 18734 boolean drawingWithRenderNode = mAttachInfo != null 18735 && mAttachInfo.mHardwareAccelerated 18736 && hardwareAcceleratedCanvas; 18737 18738 boolean more = false; 18739 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 18740 final int parentFlags = parent.mGroupFlags; 18741 18742 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 18743 parent.getChildTransformation().clear(); 18744 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18745 } 18746 18747 Transformation transformToApply = null; 18748 boolean concatMatrix = false; 18749 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 18750 final Animation a = getAnimation(); 18751 if (a != null) { 18752 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 18753 concatMatrix = a.willChangeTransformationMatrix(); 18754 if (concatMatrix) { 18755 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18756 } 18757 transformToApply = parent.getChildTransformation(); 18758 } else { 18759 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 18760 // No longer animating: clear out old animation matrix 18761 mRenderNode.setAnimationMatrix(null); 18762 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18763 } 18764 if (!drawingWithRenderNode 18765 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18766 final Transformation t = parent.getChildTransformation(); 18767 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 18768 if (hasTransform) { 18769 final int transformType = t.getTransformationType(); 18770 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 18771 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 18772 } 18773 } 18774 } 18775 18776 concatMatrix |= !childHasIdentityMatrix; 18777 18778 // Sets the flag as early as possible to allow draw() implementations 18779 // to call invalidate() successfully when doing animations 18780 mPrivateFlags |= PFLAG_DRAWN; 18781 18782 if (!concatMatrix && 18783 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 18784 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 18785 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 18786 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 18787 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 18788 return more; 18789 } 18790 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 18791 18792 if (hardwareAcceleratedCanvas) { 18793 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 18794 // retain the flag's value temporarily in the mRecreateDisplayList flag 18795 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 18796 mPrivateFlags &= ~PFLAG_INVALIDATED; 18797 } 18798 18799 RenderNode renderNode = null; 18800 Bitmap cache = null; 18801 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 18802 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 18803 if (layerType != LAYER_TYPE_NONE) { 18804 // If not drawing with RenderNode, treat HW layers as SW 18805 layerType = LAYER_TYPE_SOFTWARE; 18806 buildDrawingCache(true); 18807 } 18808 cache = getDrawingCache(true); 18809 } 18810 18811 if (drawingWithRenderNode) { 18812 // Delay getting the display list until animation-driven alpha values are 18813 // set up and possibly passed on to the view 18814 renderNode = updateDisplayListIfDirty(); 18815 if (!renderNode.isValid()) { 18816 // Uncommon, but possible. If a view is removed from the hierarchy during the call 18817 // to getDisplayList(), the display list will be marked invalid and we should not 18818 // try to use it again. 18819 renderNode = null; 18820 drawingWithRenderNode = false; 18821 } 18822 } 18823 18824 int sx = 0; 18825 int sy = 0; 18826 if (!drawingWithRenderNode) { 18827 computeScroll(); 18828 sx = mScrollX; 18829 sy = mScrollY; 18830 } 18831 18832 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 18833 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 18834 18835 int restoreTo = -1; 18836 if (!drawingWithRenderNode || transformToApply != null) { 18837 restoreTo = canvas.save(); 18838 } 18839 if (offsetForScroll) { 18840 canvas.translate(mLeft - sx, mTop - sy); 18841 } else { 18842 if (!drawingWithRenderNode) { 18843 canvas.translate(mLeft, mTop); 18844 } 18845 if (scalingRequired) { 18846 if (drawingWithRenderNode) { 18847 // TODO: Might not need this if we put everything inside the DL 18848 restoreTo = canvas.save(); 18849 } 18850 // mAttachInfo cannot be null, otherwise scalingRequired == false 18851 final float scale = 1.0f / mAttachInfo.mApplicationScale; 18852 canvas.scale(scale, scale); 18853 } 18854 } 18855 18856 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 18857 if (transformToApply != null 18858 || alpha < 1 18859 || !hasIdentityMatrix() 18860 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18861 if (transformToApply != null || !childHasIdentityMatrix) { 18862 int transX = 0; 18863 int transY = 0; 18864 18865 if (offsetForScroll) { 18866 transX = -sx; 18867 transY = -sy; 18868 } 18869 18870 if (transformToApply != null) { 18871 if (concatMatrix) { 18872 if (drawingWithRenderNode) { 18873 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 18874 } else { 18875 // Undo the scroll translation, apply the transformation matrix, 18876 // then redo the scroll translate to get the correct result. 18877 canvas.translate(-transX, -transY); 18878 canvas.concat(transformToApply.getMatrix()); 18879 canvas.translate(transX, transY); 18880 } 18881 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18882 } 18883 18884 float transformAlpha = transformToApply.getAlpha(); 18885 if (transformAlpha < 1) { 18886 alpha *= transformAlpha; 18887 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18888 } 18889 } 18890 18891 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 18892 canvas.translate(-transX, -transY); 18893 canvas.concat(getMatrix()); 18894 canvas.translate(transX, transY); 18895 } 18896 } 18897 18898 // Deal with alpha if it is or used to be <1 18899 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18900 if (alpha < 1) { 18901 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 18902 } else { 18903 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 18904 } 18905 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18906 if (!drawingWithDrawingCache) { 18907 final int multipliedAlpha = (int) (255 * alpha); 18908 if (!onSetAlpha(multipliedAlpha)) { 18909 if (drawingWithRenderNode) { 18910 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 18911 } else if (layerType == LAYER_TYPE_NONE) { 18912 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 18913 multipliedAlpha); 18914 } 18915 } else { 18916 // Alpha is handled by the child directly, clobber the layer's alpha 18917 mPrivateFlags |= PFLAG_ALPHA_SET; 18918 } 18919 } 18920 } 18921 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 18922 onSetAlpha(255); 18923 mPrivateFlags &= ~PFLAG_ALPHA_SET; 18924 } 18925 18926 if (!drawingWithRenderNode) { 18927 // apply clips directly, since RenderNode won't do it for this draw 18928 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 18929 if (offsetForScroll) { 18930 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 18931 } else { 18932 if (!scalingRequired || cache == null) { 18933 canvas.clipRect(0, 0, getWidth(), getHeight()); 18934 } else { 18935 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 18936 } 18937 } 18938 } 18939 18940 if (mClipBounds != null) { 18941 // clip bounds ignore scroll 18942 canvas.clipRect(mClipBounds); 18943 } 18944 } 18945 18946 if (!drawingWithDrawingCache) { 18947 if (drawingWithRenderNode) { 18948 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18949 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18950 } else { 18951 // Fast path for layouts with no backgrounds 18952 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18953 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18954 dispatchDraw(canvas); 18955 } else { 18956 draw(canvas); 18957 } 18958 } 18959 } else if (cache != null) { 18960 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18961 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 18962 // no layer paint, use temporary paint to draw bitmap 18963 Paint cachePaint = parent.mCachePaint; 18964 if (cachePaint == null) { 18965 cachePaint = new Paint(); 18966 cachePaint.setDither(false); 18967 parent.mCachePaint = cachePaint; 18968 } 18969 cachePaint.setAlpha((int) (alpha * 255)); 18970 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 18971 } else { 18972 // use layer paint to draw the bitmap, merging the two alphas, but also restore 18973 int layerPaintAlpha = mLayerPaint.getAlpha(); 18974 if (alpha < 1) { 18975 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 18976 } 18977 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 18978 if (alpha < 1) { 18979 mLayerPaint.setAlpha(layerPaintAlpha); 18980 } 18981 } 18982 } 18983 18984 if (restoreTo >= 0) { 18985 canvas.restoreToCount(restoreTo); 18986 } 18987 18988 if (a != null && !more) { 18989 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 18990 onSetAlpha(255); 18991 } 18992 parent.finishAnimatingView(this, a); 18993 } 18994 18995 if (more && hardwareAcceleratedCanvas) { 18996 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 18997 // alpha animations should cause the child to recreate its display list 18998 invalidate(true); 18999 } 19000 } 19001 19002 mRecreateDisplayList = false; 19003 19004 return more; 19005 } 19006 19007 static Paint getDebugPaint() { 19008 if (sDebugPaint == null) { 19009 sDebugPaint = new Paint(); 19010 sDebugPaint.setAntiAlias(false); 19011 } 19012 return sDebugPaint; 19013 } 19014 19015 final int dipsToPixels(int dips) { 19016 float scale = getContext().getResources().getDisplayMetrics().density; 19017 return (int) (dips * scale + 0.5f); 19018 } 19019 19020 final private void debugDrawFocus(Canvas canvas) { 19021 if (isFocused()) { 19022 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 19023 final int l = mScrollX; 19024 final int r = l + mRight - mLeft; 19025 final int t = mScrollY; 19026 final int b = t + mBottom - mTop; 19027 19028 final Paint paint = getDebugPaint(); 19029 paint.setColor(DEBUG_CORNERS_COLOR); 19030 19031 // Draw squares in corners. 19032 paint.setStyle(Paint.Style.FILL); 19033 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 19034 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 19035 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 19036 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 19037 19038 // Draw big X across the view. 19039 paint.setStyle(Paint.Style.STROKE); 19040 canvas.drawLine(l, t, r, b, paint); 19041 canvas.drawLine(l, b, r, t, paint); 19042 } 19043 } 19044 19045 /** 19046 * Manually render this view (and all of its children) to the given Canvas. 19047 * The view must have already done a full layout before this function is 19048 * called. When implementing a view, implement 19049 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 19050 * If you do need to override this method, call the superclass version. 19051 * 19052 * @param canvas The Canvas to which the View is rendered. 19053 */ 19054 @CallSuper 19055 public void draw(Canvas canvas) { 19056 final int privateFlags = mPrivateFlags; 19057 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 19058 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 19059 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 19060 19061 /* 19062 * Draw traversal performs several drawing steps which must be executed 19063 * in the appropriate order: 19064 * 19065 * 1. Draw the background 19066 * 2. If necessary, save the canvas' layers to prepare for fading 19067 * 3. Draw view's content 19068 * 4. Draw children 19069 * 5. If necessary, draw the fading edges and restore layers 19070 * 6. Draw decorations (scrollbars for instance) 19071 */ 19072 19073 // Step 1, draw the background, if needed 19074 int saveCount; 19075 19076 if (!dirtyOpaque) { 19077 drawBackground(canvas); 19078 } 19079 19080 // skip step 2 & 5 if possible (common case) 19081 final int viewFlags = mViewFlags; 19082 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 19083 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 19084 if (!verticalEdges && !horizontalEdges) { 19085 // Step 3, draw the content 19086 if (!dirtyOpaque) onDraw(canvas); 19087 19088 // Step 4, draw the children 19089 dispatchDraw(canvas); 19090 19091 drawAutofilledHighlight(canvas); 19092 19093 // Overlay is part of the content and draws beneath Foreground 19094 if (mOverlay != null && !mOverlay.isEmpty()) { 19095 mOverlay.getOverlayView().dispatchDraw(canvas); 19096 } 19097 19098 // Step 6, draw decorations (foreground, scrollbars) 19099 onDrawForeground(canvas); 19100 19101 // Step 7, draw the default focus highlight 19102 drawDefaultFocusHighlight(canvas); 19103 19104 if (debugDraw()) { 19105 debugDrawFocus(canvas); 19106 } 19107 19108 // we're done... 19109 return; 19110 } 19111 19112 /* 19113 * Here we do the full fledged routine... 19114 * (this is an uncommon case where speed matters less, 19115 * this is why we repeat some of the tests that have been 19116 * done above) 19117 */ 19118 19119 boolean drawTop = false; 19120 boolean drawBottom = false; 19121 boolean drawLeft = false; 19122 boolean drawRight = false; 19123 19124 float topFadeStrength = 0.0f; 19125 float bottomFadeStrength = 0.0f; 19126 float leftFadeStrength = 0.0f; 19127 float rightFadeStrength = 0.0f; 19128 19129 // Step 2, save the canvas' layers 19130 int paddingLeft = mPaddingLeft; 19131 19132 final boolean offsetRequired = isPaddingOffsetRequired(); 19133 if (offsetRequired) { 19134 paddingLeft += getLeftPaddingOffset(); 19135 } 19136 19137 int left = mScrollX + paddingLeft; 19138 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 19139 int top = mScrollY + getFadeTop(offsetRequired); 19140 int bottom = top + getFadeHeight(offsetRequired); 19141 19142 if (offsetRequired) { 19143 right += getRightPaddingOffset(); 19144 bottom += getBottomPaddingOffset(); 19145 } 19146 19147 final ScrollabilityCache scrollabilityCache = mScrollCache; 19148 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 19149 int length = (int) fadeHeight; 19150 19151 // clip the fade length if top and bottom fades overlap 19152 // overlapping fades produce odd-looking artifacts 19153 if (verticalEdges && (top + length > bottom - length)) { 19154 length = (bottom - top) / 2; 19155 } 19156 19157 // also clip horizontal fades if necessary 19158 if (horizontalEdges && (left + length > right - length)) { 19159 length = (right - left) / 2; 19160 } 19161 19162 if (verticalEdges) { 19163 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 19164 drawTop = topFadeStrength * fadeHeight > 1.0f; 19165 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 19166 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 19167 } 19168 19169 if (horizontalEdges) { 19170 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 19171 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 19172 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 19173 drawRight = rightFadeStrength * fadeHeight > 1.0f; 19174 } 19175 19176 saveCount = canvas.getSaveCount(); 19177 19178 int solidColor = getSolidColor(); 19179 if (solidColor == 0) { 19180 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 19181 19182 if (drawTop) { 19183 canvas.saveLayer(left, top, right, top + length, null, flags); 19184 } 19185 19186 if (drawBottom) { 19187 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 19188 } 19189 19190 if (drawLeft) { 19191 canvas.saveLayer(left, top, left + length, bottom, null, flags); 19192 } 19193 19194 if (drawRight) { 19195 canvas.saveLayer(right - length, top, right, bottom, null, flags); 19196 } 19197 } else { 19198 scrollabilityCache.setFadeColor(solidColor); 19199 } 19200 19201 // Step 3, draw the content 19202 if (!dirtyOpaque) onDraw(canvas); 19203 19204 // Step 4, draw the children 19205 dispatchDraw(canvas); 19206 19207 // Step 5, draw the fade effect and restore layers 19208 final Paint p = scrollabilityCache.paint; 19209 final Matrix matrix = scrollabilityCache.matrix; 19210 final Shader fade = scrollabilityCache.shader; 19211 19212 if (drawTop) { 19213 matrix.setScale(1, fadeHeight * topFadeStrength); 19214 matrix.postTranslate(left, top); 19215 fade.setLocalMatrix(matrix); 19216 p.setShader(fade); 19217 canvas.drawRect(left, top, right, top + length, p); 19218 } 19219 19220 if (drawBottom) { 19221 matrix.setScale(1, fadeHeight * bottomFadeStrength); 19222 matrix.postRotate(180); 19223 matrix.postTranslate(left, bottom); 19224 fade.setLocalMatrix(matrix); 19225 p.setShader(fade); 19226 canvas.drawRect(left, bottom - length, right, bottom, p); 19227 } 19228 19229 if (drawLeft) { 19230 matrix.setScale(1, fadeHeight * leftFadeStrength); 19231 matrix.postRotate(-90); 19232 matrix.postTranslate(left, top); 19233 fade.setLocalMatrix(matrix); 19234 p.setShader(fade); 19235 canvas.drawRect(left, top, left + length, bottom, p); 19236 } 19237 19238 if (drawRight) { 19239 matrix.setScale(1, fadeHeight * rightFadeStrength); 19240 matrix.postRotate(90); 19241 matrix.postTranslate(right, top); 19242 fade.setLocalMatrix(matrix); 19243 p.setShader(fade); 19244 canvas.drawRect(right - length, top, right, bottom, p); 19245 } 19246 19247 canvas.restoreToCount(saveCount); 19248 19249 drawAutofilledHighlight(canvas); 19250 19251 // Overlay is part of the content and draws beneath Foreground 19252 if (mOverlay != null && !mOverlay.isEmpty()) { 19253 mOverlay.getOverlayView().dispatchDraw(canvas); 19254 } 19255 19256 // Step 6, draw decorations (foreground, scrollbars) 19257 onDrawForeground(canvas); 19258 19259 if (debugDraw()) { 19260 debugDrawFocus(canvas); 19261 } 19262 } 19263 19264 /** 19265 * Draws the background onto the specified canvas. 19266 * 19267 * @param canvas Canvas on which to draw the background 19268 */ 19269 private void drawBackground(Canvas canvas) { 19270 final Drawable background = mBackground; 19271 if (background == null) { 19272 return; 19273 } 19274 19275 setBackgroundBounds(); 19276 19277 // Attempt to use a display list if requested. 19278 if (canvas.isHardwareAccelerated() && mAttachInfo != null 19279 && mAttachInfo.mThreadedRenderer != null) { 19280 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 19281 19282 final RenderNode renderNode = mBackgroundRenderNode; 19283 if (renderNode != null && renderNode.isValid()) { 19284 setBackgroundRenderNodeProperties(renderNode); 19285 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 19286 return; 19287 } 19288 } 19289 19290 final int scrollX = mScrollX; 19291 final int scrollY = mScrollY; 19292 if ((scrollX | scrollY) == 0) { 19293 background.draw(canvas); 19294 } else { 19295 canvas.translate(scrollX, scrollY); 19296 background.draw(canvas); 19297 canvas.translate(-scrollX, -scrollY); 19298 } 19299 } 19300 19301 /** 19302 * Sets the correct background bounds and rebuilds the outline, if needed. 19303 * <p/> 19304 * This is called by LayoutLib. 19305 */ 19306 void setBackgroundBounds() { 19307 if (mBackgroundSizeChanged && mBackground != null) { 19308 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 19309 mBackgroundSizeChanged = false; 19310 rebuildOutline(); 19311 } 19312 } 19313 19314 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 19315 renderNode.setTranslationX(mScrollX); 19316 renderNode.setTranslationY(mScrollY); 19317 } 19318 19319 /** 19320 * Creates a new display list or updates the existing display list for the 19321 * specified Drawable. 19322 * 19323 * @param drawable Drawable for which to create a display list 19324 * @param renderNode Existing RenderNode, or {@code null} 19325 * @return A valid display list for the specified drawable 19326 */ 19327 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 19328 if (renderNode == null) { 19329 renderNode = RenderNode.create(drawable.getClass().getName(), this); 19330 } 19331 19332 final Rect bounds = drawable.getBounds(); 19333 final int width = bounds.width(); 19334 final int height = bounds.height(); 19335 final DisplayListCanvas canvas = renderNode.start(width, height); 19336 19337 // Reverse left/top translation done by drawable canvas, which will 19338 // instead be applied by rendernode's LTRB bounds below. This way, the 19339 // drawable's bounds match with its rendernode bounds and its content 19340 // will lie within those bounds in the rendernode tree. 19341 canvas.translate(-bounds.left, -bounds.top); 19342 19343 try { 19344 drawable.draw(canvas); 19345 } finally { 19346 renderNode.end(canvas); 19347 } 19348 19349 // Set up drawable properties that are view-independent. 19350 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 19351 renderNode.setProjectBackwards(drawable.isProjected()); 19352 renderNode.setProjectionReceiver(true); 19353 renderNode.setClipToBounds(false); 19354 return renderNode; 19355 } 19356 19357 /** 19358 * Returns the overlay for this view, creating it if it does not yet exist. 19359 * Adding drawables to the overlay will cause them to be displayed whenever 19360 * the view itself is redrawn. Objects in the overlay should be actively 19361 * managed: remove them when they should not be displayed anymore. The 19362 * overlay will always have the same size as its host view. 19363 * 19364 * <p>Note: Overlays do not currently work correctly with {@link 19365 * SurfaceView} or {@link TextureView}; contents in overlays for these 19366 * types of views may not display correctly.</p> 19367 * 19368 * @return The ViewOverlay object for this view. 19369 * @see ViewOverlay 19370 */ 19371 public ViewOverlay getOverlay() { 19372 if (mOverlay == null) { 19373 mOverlay = new ViewOverlay(mContext, this); 19374 } 19375 return mOverlay; 19376 } 19377 19378 /** 19379 * Override this if your view is known to always be drawn on top of a solid color background, 19380 * and needs to draw fading edges. Returning a non-zero color enables the view system to 19381 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 19382 * should be set to 0xFF. 19383 * 19384 * @see #setVerticalFadingEdgeEnabled(boolean) 19385 * @see #setHorizontalFadingEdgeEnabled(boolean) 19386 * 19387 * @return The known solid color background for this view, or 0 if the color may vary 19388 */ 19389 @ViewDebug.ExportedProperty(category = "drawing") 19390 @ColorInt 19391 public int getSolidColor() { 19392 return 0; 19393 } 19394 19395 /** 19396 * Build a human readable string representation of the specified view flags. 19397 * 19398 * @param flags the view flags to convert to a string 19399 * @return a String representing the supplied flags 19400 */ 19401 private static String printFlags(int flags) { 19402 String output = ""; 19403 int numFlags = 0; 19404 if ((flags & FOCUSABLE) == FOCUSABLE) { 19405 output += "TAKES_FOCUS"; 19406 numFlags++; 19407 } 19408 19409 switch (flags & VISIBILITY_MASK) { 19410 case INVISIBLE: 19411 if (numFlags > 0) { 19412 output += " "; 19413 } 19414 output += "INVISIBLE"; 19415 // USELESS HERE numFlags++; 19416 break; 19417 case GONE: 19418 if (numFlags > 0) { 19419 output += " "; 19420 } 19421 output += "GONE"; 19422 // USELESS HERE numFlags++; 19423 break; 19424 default: 19425 break; 19426 } 19427 return output; 19428 } 19429 19430 /** 19431 * Build a human readable string representation of the specified private 19432 * view flags. 19433 * 19434 * @param privateFlags the private view flags to convert to a string 19435 * @return a String representing the supplied flags 19436 */ 19437 private static String printPrivateFlags(int privateFlags) { 19438 String output = ""; 19439 int numFlags = 0; 19440 19441 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 19442 output += "WANTS_FOCUS"; 19443 numFlags++; 19444 } 19445 19446 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 19447 if (numFlags > 0) { 19448 output += " "; 19449 } 19450 output += "FOCUSED"; 19451 numFlags++; 19452 } 19453 19454 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 19455 if (numFlags > 0) { 19456 output += " "; 19457 } 19458 output += "SELECTED"; 19459 numFlags++; 19460 } 19461 19462 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 19463 if (numFlags > 0) { 19464 output += " "; 19465 } 19466 output += "IS_ROOT_NAMESPACE"; 19467 numFlags++; 19468 } 19469 19470 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 19471 if (numFlags > 0) { 19472 output += " "; 19473 } 19474 output += "HAS_BOUNDS"; 19475 numFlags++; 19476 } 19477 19478 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 19479 if (numFlags > 0) { 19480 output += " "; 19481 } 19482 output += "DRAWN"; 19483 // USELESS HERE numFlags++; 19484 } 19485 return output; 19486 } 19487 19488 /** 19489 * <p>Indicates whether or not this view's layout will be requested during 19490 * the next hierarchy layout pass.</p> 19491 * 19492 * @return true if the layout will be forced during next layout pass 19493 */ 19494 public boolean isLayoutRequested() { 19495 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 19496 } 19497 19498 /** 19499 * Return true if o is a ViewGroup that is laying out using optical bounds. 19500 * @hide 19501 */ 19502 public static boolean isLayoutModeOptical(Object o) { 19503 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 19504 } 19505 19506 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 19507 Insets parentInsets = mParent instanceof View ? 19508 ((View) mParent).getOpticalInsets() : Insets.NONE; 19509 Insets childInsets = getOpticalInsets(); 19510 return setFrame( 19511 left + parentInsets.left - childInsets.left, 19512 top + parentInsets.top - childInsets.top, 19513 right + parentInsets.left + childInsets.right, 19514 bottom + parentInsets.top + childInsets.bottom); 19515 } 19516 19517 /** 19518 * Assign a size and position to a view and all of its 19519 * descendants 19520 * 19521 * <p>This is the second phase of the layout mechanism. 19522 * (The first is measuring). In this phase, each parent calls 19523 * layout on all of its children to position them. 19524 * This is typically done using the child measurements 19525 * that were stored in the measure pass().</p> 19526 * 19527 * <p>Derived classes should not override this method. 19528 * Derived classes with children should override 19529 * onLayout. In that method, they should 19530 * call layout on each of their children.</p> 19531 * 19532 * @param l Left position, relative to parent 19533 * @param t Top position, relative to parent 19534 * @param r Right position, relative to parent 19535 * @param b Bottom position, relative to parent 19536 */ 19537 @SuppressWarnings({"unchecked"}) 19538 public void layout(int l, int t, int r, int b) { 19539 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 19540 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 19541 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 19542 } 19543 19544 int oldL = mLeft; 19545 int oldT = mTop; 19546 int oldB = mBottom; 19547 int oldR = mRight; 19548 19549 boolean changed = isLayoutModeOptical(mParent) ? 19550 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 19551 19552 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 19553 onLayout(changed, l, t, r, b); 19554 19555 if (shouldDrawRoundScrollbar()) { 19556 if(mRoundScrollbarRenderer == null) { 19557 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 19558 } 19559 } else { 19560 mRoundScrollbarRenderer = null; 19561 } 19562 19563 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 19564 19565 ListenerInfo li = mListenerInfo; 19566 if (li != null && li.mOnLayoutChangeListeners != null) { 19567 ArrayList<OnLayoutChangeListener> listenersCopy = 19568 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 19569 int numListeners = listenersCopy.size(); 19570 for (int i = 0; i < numListeners; ++i) { 19571 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 19572 } 19573 } 19574 } 19575 19576 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 19577 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 19578 19579 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 19580 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 19581 notifyEnterOrExitForAutoFillIfNeeded(true); 19582 } 19583 } 19584 19585 /** 19586 * Called from layout when this view should 19587 * assign a size and position to each of its children. 19588 * 19589 * Derived classes with children should override 19590 * this method and call layout on each of 19591 * their children. 19592 * @param changed This is a new size or position for this view 19593 * @param left Left position, relative to parent 19594 * @param top Top position, relative to parent 19595 * @param right Right position, relative to parent 19596 * @param bottom Bottom position, relative to parent 19597 */ 19598 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 19599 } 19600 19601 /** 19602 * Assign a size and position to this view. 19603 * 19604 * This is called from layout. 19605 * 19606 * @param left Left position, relative to parent 19607 * @param top Top position, relative to parent 19608 * @param right Right position, relative to parent 19609 * @param bottom Bottom position, relative to parent 19610 * @return true if the new size and position are different than the 19611 * previous ones 19612 * {@hide} 19613 */ 19614 protected boolean setFrame(int left, int top, int right, int bottom) { 19615 boolean changed = false; 19616 19617 if (DBG) { 19618 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 19619 + right + "," + bottom + ")"); 19620 } 19621 19622 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 19623 changed = true; 19624 19625 // Remember our drawn bit 19626 int drawn = mPrivateFlags & PFLAG_DRAWN; 19627 19628 int oldWidth = mRight - mLeft; 19629 int oldHeight = mBottom - mTop; 19630 int newWidth = right - left; 19631 int newHeight = bottom - top; 19632 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 19633 19634 // Invalidate our old position 19635 invalidate(sizeChanged); 19636 19637 mLeft = left; 19638 mTop = top; 19639 mRight = right; 19640 mBottom = bottom; 19641 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 19642 19643 mPrivateFlags |= PFLAG_HAS_BOUNDS; 19644 19645 19646 if (sizeChanged) { 19647 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 19648 } 19649 19650 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 19651 // If we are visible, force the DRAWN bit to on so that 19652 // this invalidate will go through (at least to our parent). 19653 // This is because someone may have invalidated this view 19654 // before this call to setFrame came in, thereby clearing 19655 // the DRAWN bit. 19656 mPrivateFlags |= PFLAG_DRAWN; 19657 invalidate(sizeChanged); 19658 // parent display list may need to be recreated based on a change in the bounds 19659 // of any child 19660 invalidateParentCaches(); 19661 } 19662 19663 // Reset drawn bit to original value (invalidate turns it off) 19664 mPrivateFlags |= drawn; 19665 19666 mBackgroundSizeChanged = true; 19667 mDefaultFocusHighlightSizeChanged = true; 19668 if (mForegroundInfo != null) { 19669 mForegroundInfo.mBoundsChanged = true; 19670 } 19671 19672 notifySubtreeAccessibilityStateChangedIfNeeded(); 19673 } 19674 return changed; 19675 } 19676 19677 /** 19678 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 19679 * @hide 19680 */ 19681 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 19682 setFrame(left, top, right, bottom); 19683 } 19684 19685 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 19686 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 19687 if (mOverlay != null) { 19688 mOverlay.getOverlayView().setRight(newWidth); 19689 mOverlay.getOverlayView().setBottom(newHeight); 19690 } 19691 rebuildOutline(); 19692 } 19693 19694 /** 19695 * Finalize inflating a view from XML. This is called as the last phase 19696 * of inflation, after all child views have been added. 19697 * 19698 * <p>Even if the subclass overrides onFinishInflate, they should always be 19699 * sure to call the super method, so that we get called. 19700 */ 19701 @CallSuper 19702 protected void onFinishInflate() { 19703 } 19704 19705 /** 19706 * Returns the resources associated with this view. 19707 * 19708 * @return Resources object. 19709 */ 19710 public Resources getResources() { 19711 return mResources; 19712 } 19713 19714 /** 19715 * Invalidates the specified Drawable. 19716 * 19717 * @param drawable the drawable to invalidate 19718 */ 19719 @Override 19720 public void invalidateDrawable(@NonNull Drawable drawable) { 19721 if (verifyDrawable(drawable)) { 19722 final Rect dirty = drawable.getDirtyBounds(); 19723 final int scrollX = mScrollX; 19724 final int scrollY = mScrollY; 19725 19726 invalidate(dirty.left + scrollX, dirty.top + scrollY, 19727 dirty.right + scrollX, dirty.bottom + scrollY); 19728 rebuildOutline(); 19729 } 19730 } 19731 19732 /** 19733 * Schedules an action on a drawable to occur at a specified time. 19734 * 19735 * @param who the recipient of the action 19736 * @param what the action to run on the drawable 19737 * @param when the time at which the action must occur. Uses the 19738 * {@link SystemClock#uptimeMillis} timebase. 19739 */ 19740 @Override 19741 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 19742 if (verifyDrawable(who) && what != null) { 19743 final long delay = when - SystemClock.uptimeMillis(); 19744 if (mAttachInfo != null) { 19745 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 19746 Choreographer.CALLBACK_ANIMATION, what, who, 19747 Choreographer.subtractFrameDelay(delay)); 19748 } else { 19749 // Postpone the runnable until we know 19750 // on which thread it needs to run. 19751 getRunQueue().postDelayed(what, delay); 19752 } 19753 } 19754 } 19755 19756 /** 19757 * Cancels a scheduled action on a drawable. 19758 * 19759 * @param who the recipient of the action 19760 * @param what the action to cancel 19761 */ 19762 @Override 19763 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 19764 if (verifyDrawable(who) && what != null) { 19765 if (mAttachInfo != null) { 19766 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19767 Choreographer.CALLBACK_ANIMATION, what, who); 19768 } 19769 getRunQueue().removeCallbacks(what); 19770 } 19771 } 19772 19773 /** 19774 * Unschedule any events associated with the given Drawable. This can be 19775 * used when selecting a new Drawable into a view, so that the previous 19776 * one is completely unscheduled. 19777 * 19778 * @param who The Drawable to unschedule. 19779 * 19780 * @see #drawableStateChanged 19781 */ 19782 public void unscheduleDrawable(Drawable who) { 19783 if (mAttachInfo != null && who != null) { 19784 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19785 Choreographer.CALLBACK_ANIMATION, null, who); 19786 } 19787 } 19788 19789 /** 19790 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 19791 * that the View directionality can and will be resolved before its Drawables. 19792 * 19793 * Will call {@link View#onResolveDrawables} when resolution is done. 19794 * 19795 * @hide 19796 */ 19797 protected void resolveDrawables() { 19798 // Drawables resolution may need to happen before resolving the layout direction (which is 19799 // done only during the measure() call). 19800 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 19801 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 19802 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 19803 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 19804 // direction to be resolved as its resolved value will be the same as its raw value. 19805 if (!isLayoutDirectionResolved() && 19806 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 19807 return; 19808 } 19809 19810 final int layoutDirection = isLayoutDirectionResolved() ? 19811 getLayoutDirection() : getRawLayoutDirection(); 19812 19813 if (mBackground != null) { 19814 mBackground.setLayoutDirection(layoutDirection); 19815 } 19816 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19817 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 19818 } 19819 if (mDefaultFocusHighlight != null) { 19820 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 19821 } 19822 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 19823 onResolveDrawables(layoutDirection); 19824 } 19825 19826 boolean areDrawablesResolved() { 19827 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 19828 } 19829 19830 /** 19831 * Called when layout direction has been resolved. 19832 * 19833 * The default implementation does nothing. 19834 * 19835 * @param layoutDirection The resolved layout direction. 19836 * 19837 * @see #LAYOUT_DIRECTION_LTR 19838 * @see #LAYOUT_DIRECTION_RTL 19839 * 19840 * @hide 19841 */ 19842 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 19843 } 19844 19845 /** 19846 * @hide 19847 */ 19848 protected void resetResolvedDrawables() { 19849 resetResolvedDrawablesInternal(); 19850 } 19851 19852 void resetResolvedDrawablesInternal() { 19853 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 19854 } 19855 19856 /** 19857 * If your view subclass is displaying its own Drawable objects, it should 19858 * override this function and return true for any Drawable it is 19859 * displaying. This allows animations for those drawables to be 19860 * scheduled. 19861 * 19862 * <p>Be sure to call through to the super class when overriding this 19863 * function. 19864 * 19865 * @param who The Drawable to verify. Return true if it is one you are 19866 * displaying, else return the result of calling through to the 19867 * super class. 19868 * 19869 * @return boolean If true than the Drawable is being displayed in the 19870 * view; else false and it is not allowed to animate. 19871 * 19872 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 19873 * @see #drawableStateChanged() 19874 */ 19875 @CallSuper 19876 protected boolean verifyDrawable(@NonNull Drawable who) { 19877 // Avoid verifying the scroll bar drawable so that we don't end up in 19878 // an invalidation loop. This effectively prevents the scroll bar 19879 // drawable from triggering invalidations and scheduling runnables. 19880 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 19881 || (mDefaultFocusHighlight == who); 19882 } 19883 19884 /** 19885 * This function is called whenever the state of the view changes in such 19886 * a way that it impacts the state of drawables being shown. 19887 * <p> 19888 * If the View has a StateListAnimator, it will also be called to run necessary state 19889 * change animations. 19890 * <p> 19891 * Be sure to call through to the superclass when overriding this function. 19892 * 19893 * @see Drawable#setState(int[]) 19894 */ 19895 @CallSuper 19896 protected void drawableStateChanged() { 19897 final int[] state = getDrawableState(); 19898 boolean changed = false; 19899 19900 final Drawable bg = mBackground; 19901 if (bg != null && bg.isStateful()) { 19902 changed |= bg.setState(state); 19903 } 19904 19905 final Drawable hl = mDefaultFocusHighlight; 19906 if (hl != null && hl.isStateful()) { 19907 changed |= hl.setState(state); 19908 } 19909 19910 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19911 if (fg != null && fg.isStateful()) { 19912 changed |= fg.setState(state); 19913 } 19914 19915 if (mScrollCache != null) { 19916 final Drawable scrollBar = mScrollCache.scrollBar; 19917 if (scrollBar != null && scrollBar.isStateful()) { 19918 changed |= scrollBar.setState(state) 19919 && mScrollCache.state != ScrollabilityCache.OFF; 19920 } 19921 } 19922 19923 if (mStateListAnimator != null) { 19924 mStateListAnimator.setState(state); 19925 } 19926 19927 if (changed) { 19928 invalidate(); 19929 } 19930 } 19931 19932 /** 19933 * This function is called whenever the view hotspot changes and needs to 19934 * be propagated to drawables or child views managed by the view. 19935 * <p> 19936 * Dispatching to child views is handled by 19937 * {@link #dispatchDrawableHotspotChanged(float, float)}. 19938 * <p> 19939 * Be sure to call through to the superclass when overriding this function. 19940 * 19941 * @param x hotspot x coordinate 19942 * @param y hotspot y coordinate 19943 */ 19944 @CallSuper 19945 public void drawableHotspotChanged(float x, float y) { 19946 if (mBackground != null) { 19947 mBackground.setHotspot(x, y); 19948 } 19949 if (mDefaultFocusHighlight != null) { 19950 mDefaultFocusHighlight.setHotspot(x, y); 19951 } 19952 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19953 mForegroundInfo.mDrawable.setHotspot(x, y); 19954 } 19955 19956 dispatchDrawableHotspotChanged(x, y); 19957 } 19958 19959 /** 19960 * Dispatches drawableHotspotChanged to all of this View's children. 19961 * 19962 * @param x hotspot x coordinate 19963 * @param y hotspot y coordinate 19964 * @see #drawableHotspotChanged(float, float) 19965 */ 19966 public void dispatchDrawableHotspotChanged(float x, float y) { 19967 } 19968 19969 /** 19970 * Call this to force a view to update its drawable state. This will cause 19971 * drawableStateChanged to be called on this view. Views that are interested 19972 * in the new state should call getDrawableState. 19973 * 19974 * @see #drawableStateChanged 19975 * @see #getDrawableState 19976 */ 19977 public void refreshDrawableState() { 19978 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 19979 drawableStateChanged(); 19980 19981 ViewParent parent = mParent; 19982 if (parent != null) { 19983 parent.childDrawableStateChanged(this); 19984 } 19985 } 19986 19987 /** 19988 * Create a default focus highlight if it doesn't exist. 19989 * @return a default focus highlight. 19990 */ 19991 private Drawable getDefaultFocusHighlightDrawable() { 19992 if (mDefaultFocusHighlightCache == null) { 19993 if (mContext != null) { 19994 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 19995 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 19996 mDefaultFocusHighlightCache = ta.getDrawable(0); 19997 ta.recycle(); 19998 } 19999 } 20000 return mDefaultFocusHighlightCache; 20001 } 20002 20003 /** 20004 * Set the current default focus highlight. 20005 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 20006 */ 20007 private void setDefaultFocusHighlight(Drawable highlight) { 20008 mDefaultFocusHighlight = highlight; 20009 mDefaultFocusHighlightSizeChanged = true; 20010 if (highlight != null) { 20011 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20012 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20013 } 20014 highlight.setLayoutDirection(getLayoutDirection()); 20015 if (highlight.isStateful()) { 20016 highlight.setState(getDrawableState()); 20017 } 20018 if (isAttachedToWindow()) { 20019 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20020 } 20021 // Set callback last, since the view may still be initializing. 20022 highlight.setCallback(this); 20023 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 20024 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 20025 mPrivateFlags |= PFLAG_SKIP_DRAW; 20026 } 20027 invalidate(); 20028 } 20029 20030 /** 20031 * Check whether we need to draw a default focus highlight when this view gets focused, 20032 * which requires: 20033 * <ul> 20034 * <li>In both background and foreground, {@link android.R.attr#state_focused} 20035 * is not defined.</li> 20036 * <li>This view is not in touch mode.</li> 20037 * <li>This view doesn't opt out for a default focus highlight, via 20038 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 20039 * <li>This view is attached to window.</li> 20040 * </ul> 20041 * @return {@code true} if a default focus highlight is needed. 20042 * @hide 20043 */ 20044 @TestApi 20045 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 20046 final boolean lackFocusState = (background == null || !background.isStateful() 20047 || !background.hasFocusStateSpecified()) 20048 && (foreground == null || !foreground.isStateful() 20049 || !foreground.hasFocusStateSpecified()); 20050 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 20051 && isAttachedToWindow() && sUseDefaultFocusHighlight; 20052 } 20053 20054 /** 20055 * When this view is focused, switches on/off the default focused highlight. 20056 * <p> 20057 * This always happens when this view is focused, and only at this moment the default focus 20058 * highlight can be visible. 20059 */ 20060 private void switchDefaultFocusHighlight() { 20061 if (isFocused()) { 20062 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 20063 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 20064 final boolean active = mDefaultFocusHighlight != null; 20065 if (needed && !active) { 20066 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 20067 } else if (!needed && active) { 20068 // The highlight is no longer needed, so tear it down. 20069 setDefaultFocusHighlight(null); 20070 } 20071 } 20072 } 20073 20074 /** 20075 * Draw the default focus highlight onto the canvas. 20076 * @param canvas the canvas where we're drawing the highlight. 20077 */ 20078 private void drawDefaultFocusHighlight(Canvas canvas) { 20079 if (mDefaultFocusHighlight != null) { 20080 if (mDefaultFocusHighlightSizeChanged) { 20081 mDefaultFocusHighlightSizeChanged = false; 20082 final int l = mScrollX; 20083 final int r = l + mRight - mLeft; 20084 final int t = mScrollY; 20085 final int b = t + mBottom - mTop; 20086 mDefaultFocusHighlight.setBounds(l, t, r, b); 20087 } 20088 mDefaultFocusHighlight.draw(canvas); 20089 } 20090 } 20091 20092 /** 20093 * Return an array of resource IDs of the drawable states representing the 20094 * current state of the view. 20095 * 20096 * @return The current drawable state 20097 * 20098 * @see Drawable#setState(int[]) 20099 * @see #drawableStateChanged() 20100 * @see #onCreateDrawableState(int) 20101 */ 20102 public final int[] getDrawableState() { 20103 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 20104 return mDrawableState; 20105 } else { 20106 mDrawableState = onCreateDrawableState(0); 20107 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 20108 return mDrawableState; 20109 } 20110 } 20111 20112 /** 20113 * Generate the new {@link android.graphics.drawable.Drawable} state for 20114 * this view. This is called by the view 20115 * system when the cached Drawable state is determined to be invalid. To 20116 * retrieve the current state, you should use {@link #getDrawableState}. 20117 * 20118 * @param extraSpace if non-zero, this is the number of extra entries you 20119 * would like in the returned array in which you can place your own 20120 * states. 20121 * 20122 * @return Returns an array holding the current {@link Drawable} state of 20123 * the view. 20124 * 20125 * @see #mergeDrawableStates(int[], int[]) 20126 */ 20127 protected int[] onCreateDrawableState(int extraSpace) { 20128 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 20129 mParent instanceof View) { 20130 return ((View) mParent).onCreateDrawableState(extraSpace); 20131 } 20132 20133 int[] drawableState; 20134 20135 int privateFlags = mPrivateFlags; 20136 20137 int viewStateIndex = 0; 20138 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 20139 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 20140 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 20141 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 20142 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 20143 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 20144 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 20145 ThreadedRenderer.isAvailable()) { 20146 // This is set if HW acceleration is requested, even if the current 20147 // process doesn't allow it. This is just to allow app preview 20148 // windows to better match their app. 20149 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 20150 } 20151 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 20152 20153 final int privateFlags2 = mPrivateFlags2; 20154 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 20155 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 20156 } 20157 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 20158 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 20159 } 20160 20161 drawableState = StateSet.get(viewStateIndex); 20162 20163 //noinspection ConstantIfStatement 20164 if (false) { 20165 Log.i("View", "drawableStateIndex=" + viewStateIndex); 20166 Log.i("View", toString() 20167 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 20168 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 20169 + " fo=" + hasFocus() 20170 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 20171 + " wf=" + hasWindowFocus() 20172 + ": " + Arrays.toString(drawableState)); 20173 } 20174 20175 if (extraSpace == 0) { 20176 return drawableState; 20177 } 20178 20179 final int[] fullState; 20180 if (drawableState != null) { 20181 fullState = new int[drawableState.length + extraSpace]; 20182 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 20183 } else { 20184 fullState = new int[extraSpace]; 20185 } 20186 20187 return fullState; 20188 } 20189 20190 /** 20191 * Merge your own state values in <var>additionalState</var> into the base 20192 * state values <var>baseState</var> that were returned by 20193 * {@link #onCreateDrawableState(int)}. 20194 * 20195 * @param baseState The base state values returned by 20196 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 20197 * own additional state values. 20198 * 20199 * @param additionalState The additional state values you would like 20200 * added to <var>baseState</var>; this array is not modified. 20201 * 20202 * @return As a convenience, the <var>baseState</var> array you originally 20203 * passed into the function is returned. 20204 * 20205 * @see #onCreateDrawableState(int) 20206 */ 20207 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 20208 final int N = baseState.length; 20209 int i = N - 1; 20210 while (i >= 0 && baseState[i] == 0) { 20211 i--; 20212 } 20213 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 20214 return baseState; 20215 } 20216 20217 /** 20218 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 20219 * on all Drawable objects associated with this view. 20220 * <p> 20221 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 20222 * attached to this view. 20223 */ 20224 @CallSuper 20225 public void jumpDrawablesToCurrentState() { 20226 if (mBackground != null) { 20227 mBackground.jumpToCurrentState(); 20228 } 20229 if (mStateListAnimator != null) { 20230 mStateListAnimator.jumpToCurrentState(); 20231 } 20232 if (mDefaultFocusHighlight != null) { 20233 mDefaultFocusHighlight.jumpToCurrentState(); 20234 } 20235 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 20236 mForegroundInfo.mDrawable.jumpToCurrentState(); 20237 } 20238 } 20239 20240 /** 20241 * Sets the background color for this view. 20242 * @param color the color of the background 20243 */ 20244 @RemotableViewMethod 20245 public void setBackgroundColor(@ColorInt int color) { 20246 if (mBackground instanceof ColorDrawable) { 20247 ((ColorDrawable) mBackground.mutate()).setColor(color); 20248 computeOpaqueFlags(); 20249 mBackgroundResource = 0; 20250 } else { 20251 setBackground(new ColorDrawable(color)); 20252 } 20253 } 20254 20255 /** 20256 * Set the background to a given resource. The resource should refer to 20257 * a Drawable object or 0 to remove the background. 20258 * @param resid The identifier of the resource. 20259 * 20260 * @attr ref android.R.styleable#View_background 20261 */ 20262 @RemotableViewMethod 20263 public void setBackgroundResource(@DrawableRes int resid) { 20264 if (resid != 0 && resid == mBackgroundResource) { 20265 return; 20266 } 20267 20268 Drawable d = null; 20269 if (resid != 0) { 20270 d = mContext.getDrawable(resid); 20271 } 20272 setBackground(d); 20273 20274 mBackgroundResource = resid; 20275 } 20276 20277 /** 20278 * Set the background to a given Drawable, or remove the background. If the 20279 * background has padding, this View's padding is set to the background's 20280 * padding. However, when a background is removed, this View's padding isn't 20281 * touched. If setting the padding is desired, please use 20282 * {@link #setPadding(int, int, int, int)}. 20283 * 20284 * @param background The Drawable to use as the background, or null to remove the 20285 * background 20286 */ 20287 public void setBackground(Drawable background) { 20288 //noinspection deprecation 20289 setBackgroundDrawable(background); 20290 } 20291 20292 /** 20293 * @deprecated use {@link #setBackground(Drawable)} instead 20294 */ 20295 @Deprecated 20296 public void setBackgroundDrawable(Drawable background) { 20297 computeOpaqueFlags(); 20298 20299 if (background == mBackground) { 20300 return; 20301 } 20302 20303 boolean requestLayout = false; 20304 20305 mBackgroundResource = 0; 20306 20307 /* 20308 * Regardless of whether we're setting a new background or not, we want 20309 * to clear the previous drawable. setVisible first while we still have the callback set. 20310 */ 20311 if (mBackground != null) { 20312 if (isAttachedToWindow()) { 20313 mBackground.setVisible(false, false); 20314 } 20315 mBackground.setCallback(null); 20316 unscheduleDrawable(mBackground); 20317 } 20318 20319 if (background != null) { 20320 Rect padding = sThreadLocal.get(); 20321 if (padding == null) { 20322 padding = new Rect(); 20323 sThreadLocal.set(padding); 20324 } 20325 resetResolvedDrawablesInternal(); 20326 background.setLayoutDirection(getLayoutDirection()); 20327 if (background.getPadding(padding)) { 20328 resetResolvedPaddingInternal(); 20329 switch (background.getLayoutDirection()) { 20330 case LAYOUT_DIRECTION_RTL: 20331 mUserPaddingLeftInitial = padding.right; 20332 mUserPaddingRightInitial = padding.left; 20333 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 20334 break; 20335 case LAYOUT_DIRECTION_LTR: 20336 default: 20337 mUserPaddingLeftInitial = padding.left; 20338 mUserPaddingRightInitial = padding.right; 20339 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 20340 } 20341 mLeftPaddingDefined = false; 20342 mRightPaddingDefined = false; 20343 } 20344 20345 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 20346 // if it has a different minimum size, we should layout again 20347 if (mBackground == null 20348 || mBackground.getMinimumHeight() != background.getMinimumHeight() 20349 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 20350 requestLayout = true; 20351 } 20352 20353 // Set mBackground before we set this as the callback and start making other 20354 // background drawable state change calls. In particular, the setVisible call below 20355 // can result in drawables attempting to start animations or otherwise invalidate, 20356 // which requires the view set as the callback (us) to recognize the drawable as 20357 // belonging to it as per verifyDrawable. 20358 mBackground = background; 20359 if (background.isStateful()) { 20360 background.setState(getDrawableState()); 20361 } 20362 if (isAttachedToWindow()) { 20363 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20364 } 20365 20366 applyBackgroundTint(); 20367 20368 // Set callback last, since the view may still be initializing. 20369 background.setCallback(this); 20370 20371 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20372 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20373 requestLayout = true; 20374 } 20375 } else { 20376 /* Remove the background */ 20377 mBackground = null; 20378 if ((mViewFlags & WILL_NOT_DRAW) != 0 20379 && (mDefaultFocusHighlight == null) 20380 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 20381 mPrivateFlags |= PFLAG_SKIP_DRAW; 20382 } 20383 20384 /* 20385 * When the background is set, we try to apply its padding to this 20386 * View. When the background is removed, we don't touch this View's 20387 * padding. This is noted in the Javadocs. Hence, we don't need to 20388 * requestLayout(), the invalidate() below is sufficient. 20389 */ 20390 20391 // The old background's minimum size could have affected this 20392 // View's layout, so let's requestLayout 20393 requestLayout = true; 20394 } 20395 20396 computeOpaqueFlags(); 20397 20398 if (requestLayout) { 20399 requestLayout(); 20400 } 20401 20402 mBackgroundSizeChanged = true; 20403 invalidate(true); 20404 invalidateOutline(); 20405 } 20406 20407 /** 20408 * Gets the background drawable 20409 * 20410 * @return The drawable used as the background for this view, if any. 20411 * 20412 * @see #setBackground(Drawable) 20413 * 20414 * @attr ref android.R.styleable#View_background 20415 */ 20416 public Drawable getBackground() { 20417 return mBackground; 20418 } 20419 20420 /** 20421 * Applies a tint to the background drawable. Does not modify the current tint 20422 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20423 * <p> 20424 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 20425 * mutate the drawable and apply the specified tint and tint mode using 20426 * {@link Drawable#setTintList(ColorStateList)}. 20427 * 20428 * @param tint the tint to apply, may be {@code null} to clear tint 20429 * 20430 * @attr ref android.R.styleable#View_backgroundTint 20431 * @see #getBackgroundTintList() 20432 * @see Drawable#setTintList(ColorStateList) 20433 */ 20434 public void setBackgroundTintList(@Nullable ColorStateList tint) { 20435 if (mBackgroundTint == null) { 20436 mBackgroundTint = new TintInfo(); 20437 } 20438 mBackgroundTint.mTintList = tint; 20439 mBackgroundTint.mHasTintList = true; 20440 20441 applyBackgroundTint(); 20442 } 20443 20444 /** 20445 * Return the tint applied to the background drawable, if specified. 20446 * 20447 * @return the tint applied to the background drawable 20448 * @attr ref android.R.styleable#View_backgroundTint 20449 * @see #setBackgroundTintList(ColorStateList) 20450 */ 20451 @Nullable 20452 public ColorStateList getBackgroundTintList() { 20453 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 20454 } 20455 20456 /** 20457 * Specifies the blending mode used to apply the tint specified by 20458 * {@link #setBackgroundTintList(ColorStateList)}} to the background 20459 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20460 * 20461 * @param tintMode the blending mode used to apply the tint, may be 20462 * {@code null} to clear tint 20463 * @attr ref android.R.styleable#View_backgroundTintMode 20464 * @see #getBackgroundTintMode() 20465 * @see Drawable#setTintMode(PorterDuff.Mode) 20466 */ 20467 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20468 if (mBackgroundTint == null) { 20469 mBackgroundTint = new TintInfo(); 20470 } 20471 mBackgroundTint.mTintMode = tintMode; 20472 mBackgroundTint.mHasTintMode = true; 20473 20474 applyBackgroundTint(); 20475 } 20476 20477 /** 20478 * Return the blending mode used to apply the tint to the background 20479 * drawable, if specified. 20480 * 20481 * @return the blending mode used to apply the tint to the background 20482 * drawable 20483 * @attr ref android.R.styleable#View_backgroundTintMode 20484 * @see #setBackgroundTintMode(PorterDuff.Mode) 20485 */ 20486 @Nullable 20487 public PorterDuff.Mode getBackgroundTintMode() { 20488 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 20489 } 20490 20491 private void applyBackgroundTint() { 20492 if (mBackground != null && mBackgroundTint != null) { 20493 final TintInfo tintInfo = mBackgroundTint; 20494 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20495 mBackground = mBackground.mutate(); 20496 20497 if (tintInfo.mHasTintList) { 20498 mBackground.setTintList(tintInfo.mTintList); 20499 } 20500 20501 if (tintInfo.mHasTintMode) { 20502 mBackground.setTintMode(tintInfo.mTintMode); 20503 } 20504 20505 // The drawable (or one of its children) may not have been 20506 // stateful before applying the tint, so let's try again. 20507 if (mBackground.isStateful()) { 20508 mBackground.setState(getDrawableState()); 20509 } 20510 } 20511 } 20512 } 20513 20514 /** 20515 * Returns the drawable used as the foreground of this View. The 20516 * foreground drawable, if non-null, is always drawn on top of the view's content. 20517 * 20518 * @return a Drawable or null if no foreground was set 20519 * 20520 * @see #onDrawForeground(Canvas) 20521 */ 20522 public Drawable getForeground() { 20523 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20524 } 20525 20526 /** 20527 * Supply a Drawable that is to be rendered on top of all of the content in the view. 20528 * 20529 * @param foreground the Drawable to be drawn on top of the children 20530 * 20531 * @attr ref android.R.styleable#View_foreground 20532 */ 20533 public void setForeground(Drawable foreground) { 20534 if (mForegroundInfo == null) { 20535 if (foreground == null) { 20536 // Nothing to do. 20537 return; 20538 } 20539 mForegroundInfo = new ForegroundInfo(); 20540 } 20541 20542 if (foreground == mForegroundInfo.mDrawable) { 20543 // Nothing to do 20544 return; 20545 } 20546 20547 if (mForegroundInfo.mDrawable != null) { 20548 if (isAttachedToWindow()) { 20549 mForegroundInfo.mDrawable.setVisible(false, false); 20550 } 20551 mForegroundInfo.mDrawable.setCallback(null); 20552 unscheduleDrawable(mForegroundInfo.mDrawable); 20553 } 20554 20555 mForegroundInfo.mDrawable = foreground; 20556 mForegroundInfo.mBoundsChanged = true; 20557 if (foreground != null) { 20558 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20559 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20560 } 20561 foreground.setLayoutDirection(getLayoutDirection()); 20562 if (foreground.isStateful()) { 20563 foreground.setState(getDrawableState()); 20564 } 20565 applyForegroundTint(); 20566 if (isAttachedToWindow()) { 20567 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20568 } 20569 // Set callback last, since the view may still be initializing. 20570 foreground.setCallback(this); 20571 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 20572 && (mDefaultFocusHighlight == null)) { 20573 mPrivateFlags |= PFLAG_SKIP_DRAW; 20574 } 20575 requestLayout(); 20576 invalidate(); 20577 } 20578 20579 /** 20580 * Magic bit used to support features of framework-internal window decor implementation details. 20581 * This used to live exclusively in FrameLayout. 20582 * 20583 * @return true if the foreground should draw inside the padding region or false 20584 * if it should draw inset by the view's padding 20585 * @hide internal use only; only used by FrameLayout and internal screen layouts. 20586 */ 20587 public boolean isForegroundInsidePadding() { 20588 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 20589 } 20590 20591 /** 20592 * Describes how the foreground is positioned. 20593 * 20594 * @return foreground gravity. 20595 * 20596 * @see #setForegroundGravity(int) 20597 * 20598 * @attr ref android.R.styleable#View_foregroundGravity 20599 */ 20600 public int getForegroundGravity() { 20601 return mForegroundInfo != null ? mForegroundInfo.mGravity 20602 : Gravity.START | Gravity.TOP; 20603 } 20604 20605 /** 20606 * Describes how the foreground is positioned. Defaults to START and TOP. 20607 * 20608 * @param gravity see {@link android.view.Gravity} 20609 * 20610 * @see #getForegroundGravity() 20611 * 20612 * @attr ref android.R.styleable#View_foregroundGravity 20613 */ 20614 public void setForegroundGravity(int gravity) { 20615 if (mForegroundInfo == null) { 20616 mForegroundInfo = new ForegroundInfo(); 20617 } 20618 20619 if (mForegroundInfo.mGravity != gravity) { 20620 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 20621 gravity |= Gravity.START; 20622 } 20623 20624 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 20625 gravity |= Gravity.TOP; 20626 } 20627 20628 mForegroundInfo.mGravity = gravity; 20629 requestLayout(); 20630 } 20631 } 20632 20633 /** 20634 * Applies a tint to the foreground drawable. Does not modify the current tint 20635 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20636 * <p> 20637 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 20638 * mutate the drawable and apply the specified tint and tint mode using 20639 * {@link Drawable#setTintList(ColorStateList)}. 20640 * 20641 * @param tint the tint to apply, may be {@code null} to clear tint 20642 * 20643 * @attr ref android.R.styleable#View_foregroundTint 20644 * @see #getForegroundTintList() 20645 * @see Drawable#setTintList(ColorStateList) 20646 */ 20647 public void setForegroundTintList(@Nullable ColorStateList tint) { 20648 if (mForegroundInfo == null) { 20649 mForegroundInfo = new ForegroundInfo(); 20650 } 20651 if (mForegroundInfo.mTintInfo == null) { 20652 mForegroundInfo.mTintInfo = new TintInfo(); 20653 } 20654 mForegroundInfo.mTintInfo.mTintList = tint; 20655 mForegroundInfo.mTintInfo.mHasTintList = true; 20656 20657 applyForegroundTint(); 20658 } 20659 20660 /** 20661 * Return the tint applied to the foreground drawable, if specified. 20662 * 20663 * @return the tint applied to the foreground drawable 20664 * @attr ref android.R.styleable#View_foregroundTint 20665 * @see #setForegroundTintList(ColorStateList) 20666 */ 20667 @Nullable 20668 public ColorStateList getForegroundTintList() { 20669 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20670 ? mForegroundInfo.mTintInfo.mTintList : null; 20671 } 20672 20673 /** 20674 * Specifies the blending mode used to apply the tint specified by 20675 * {@link #setForegroundTintList(ColorStateList)}} to the background 20676 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20677 * 20678 * @param tintMode the blending mode used to apply the tint, may be 20679 * {@code null} to clear tint 20680 * @attr ref android.R.styleable#View_foregroundTintMode 20681 * @see #getForegroundTintMode() 20682 * @see Drawable#setTintMode(PorterDuff.Mode) 20683 */ 20684 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20685 if (mForegroundInfo == null) { 20686 mForegroundInfo = new ForegroundInfo(); 20687 } 20688 if (mForegroundInfo.mTintInfo == null) { 20689 mForegroundInfo.mTintInfo = new TintInfo(); 20690 } 20691 mForegroundInfo.mTintInfo.mTintMode = tintMode; 20692 mForegroundInfo.mTintInfo.mHasTintMode = true; 20693 20694 applyForegroundTint(); 20695 } 20696 20697 /** 20698 * Return the blending mode used to apply the tint to the foreground 20699 * drawable, if specified. 20700 * 20701 * @return the blending mode used to apply the tint to the foreground 20702 * drawable 20703 * @attr ref android.R.styleable#View_foregroundTintMode 20704 * @see #setForegroundTintMode(PorterDuff.Mode) 20705 */ 20706 @Nullable 20707 public PorterDuff.Mode getForegroundTintMode() { 20708 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20709 ? mForegroundInfo.mTintInfo.mTintMode : null; 20710 } 20711 20712 private void applyForegroundTint() { 20713 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20714 && mForegroundInfo.mTintInfo != null) { 20715 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 20716 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20717 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 20718 20719 if (tintInfo.mHasTintList) { 20720 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 20721 } 20722 20723 if (tintInfo.mHasTintMode) { 20724 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 20725 } 20726 20727 // The drawable (or one of its children) may not have been 20728 // stateful before applying the tint, so let's try again. 20729 if (mForegroundInfo.mDrawable.isStateful()) { 20730 mForegroundInfo.mDrawable.setState(getDrawableState()); 20731 } 20732 } 20733 } 20734 } 20735 20736 /** 20737 * Get the drawable to be overlayed when a view is autofilled 20738 * 20739 * @return The drawable 20740 * 20741 * @throws IllegalStateException if the drawable could not be found. 20742 */ 20743 @Nullable private Drawable getAutofilledDrawable() { 20744 if (mAttachInfo == null) { 20745 return null; 20746 } 20747 // Lazily load the isAutofilled drawable. 20748 if (mAttachInfo.mAutofilledDrawable == null) { 20749 Context rootContext = getRootView().getContext(); 20750 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 20751 int attributeResourceId = a.getResourceId(0, 0); 20752 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 20753 a.recycle(); 20754 } 20755 20756 return mAttachInfo.mAutofilledDrawable; 20757 } 20758 20759 /** 20760 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled. 20761 * 20762 * @param canvas The canvas to draw on 20763 */ 20764 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 20765 if (isAutofilled()) { 20766 Drawable autofilledHighlight = getAutofilledDrawable(); 20767 20768 if (autofilledHighlight != null) { 20769 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 20770 autofilledHighlight.draw(canvas); 20771 } 20772 } 20773 } 20774 20775 /** 20776 * Draw any foreground content for this view. 20777 * 20778 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 20779 * drawable or other view-specific decorations. The foreground is drawn on top of the 20780 * primary view content.</p> 20781 * 20782 * @param canvas canvas to draw into 20783 */ 20784 public void onDrawForeground(Canvas canvas) { 20785 onDrawScrollIndicators(canvas); 20786 onDrawScrollBars(canvas); 20787 20788 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20789 if (foreground != null) { 20790 if (mForegroundInfo.mBoundsChanged) { 20791 mForegroundInfo.mBoundsChanged = false; 20792 final Rect selfBounds = mForegroundInfo.mSelfBounds; 20793 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 20794 20795 if (mForegroundInfo.mInsidePadding) { 20796 selfBounds.set(0, 0, getWidth(), getHeight()); 20797 } else { 20798 selfBounds.set(getPaddingLeft(), getPaddingTop(), 20799 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 20800 } 20801 20802 final int ld = getLayoutDirection(); 20803 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 20804 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 20805 foreground.setBounds(overlayBounds); 20806 } 20807 20808 foreground.draw(canvas); 20809 } 20810 } 20811 20812 /** 20813 * Sets the padding. The view may add on the space required to display 20814 * the scrollbars, depending on the style and visibility of the scrollbars. 20815 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 20816 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 20817 * from the values set in this call. 20818 * 20819 * @attr ref android.R.styleable#View_padding 20820 * @attr ref android.R.styleable#View_paddingBottom 20821 * @attr ref android.R.styleable#View_paddingLeft 20822 * @attr ref android.R.styleable#View_paddingRight 20823 * @attr ref android.R.styleable#View_paddingTop 20824 * @param left the left padding in pixels 20825 * @param top the top padding in pixels 20826 * @param right the right padding in pixels 20827 * @param bottom the bottom padding in pixels 20828 */ 20829 public void setPadding(int left, int top, int right, int bottom) { 20830 resetResolvedPaddingInternal(); 20831 20832 mUserPaddingStart = UNDEFINED_PADDING; 20833 mUserPaddingEnd = UNDEFINED_PADDING; 20834 20835 mUserPaddingLeftInitial = left; 20836 mUserPaddingRightInitial = right; 20837 20838 mLeftPaddingDefined = true; 20839 mRightPaddingDefined = true; 20840 20841 internalSetPadding(left, top, right, bottom); 20842 } 20843 20844 /** 20845 * @hide 20846 */ 20847 protected void internalSetPadding(int left, int top, int right, int bottom) { 20848 mUserPaddingLeft = left; 20849 mUserPaddingRight = right; 20850 mUserPaddingBottom = bottom; 20851 20852 final int viewFlags = mViewFlags; 20853 boolean changed = false; 20854 20855 // Common case is there are no scroll bars. 20856 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 20857 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 20858 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 20859 ? 0 : getVerticalScrollbarWidth(); 20860 switch (mVerticalScrollbarPosition) { 20861 case SCROLLBAR_POSITION_DEFAULT: 20862 if (isLayoutRtl()) { 20863 left += offset; 20864 } else { 20865 right += offset; 20866 } 20867 break; 20868 case SCROLLBAR_POSITION_RIGHT: 20869 right += offset; 20870 break; 20871 case SCROLLBAR_POSITION_LEFT: 20872 left += offset; 20873 break; 20874 } 20875 } 20876 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 20877 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 20878 ? 0 : getHorizontalScrollbarHeight(); 20879 } 20880 } 20881 20882 if (mPaddingLeft != left) { 20883 changed = true; 20884 mPaddingLeft = left; 20885 } 20886 if (mPaddingTop != top) { 20887 changed = true; 20888 mPaddingTop = top; 20889 } 20890 if (mPaddingRight != right) { 20891 changed = true; 20892 mPaddingRight = right; 20893 } 20894 if (mPaddingBottom != bottom) { 20895 changed = true; 20896 mPaddingBottom = bottom; 20897 } 20898 20899 if (changed) { 20900 requestLayout(); 20901 invalidateOutline(); 20902 } 20903 } 20904 20905 /** 20906 * Sets the relative padding. The view may add on the space required to display 20907 * the scrollbars, depending on the style and visibility of the scrollbars. 20908 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 20909 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 20910 * from the values set in this call. 20911 * 20912 * @attr ref android.R.styleable#View_padding 20913 * @attr ref android.R.styleable#View_paddingBottom 20914 * @attr ref android.R.styleable#View_paddingStart 20915 * @attr ref android.R.styleable#View_paddingEnd 20916 * @attr ref android.R.styleable#View_paddingTop 20917 * @param start the start padding in pixels 20918 * @param top the top padding in pixels 20919 * @param end the end padding in pixels 20920 * @param bottom the bottom padding in pixels 20921 */ 20922 public void setPaddingRelative(int start, int top, int end, int bottom) { 20923 resetResolvedPaddingInternal(); 20924 20925 mUserPaddingStart = start; 20926 mUserPaddingEnd = end; 20927 mLeftPaddingDefined = true; 20928 mRightPaddingDefined = true; 20929 20930 switch(getLayoutDirection()) { 20931 case LAYOUT_DIRECTION_RTL: 20932 mUserPaddingLeftInitial = end; 20933 mUserPaddingRightInitial = start; 20934 internalSetPadding(end, top, start, bottom); 20935 break; 20936 case LAYOUT_DIRECTION_LTR: 20937 default: 20938 mUserPaddingLeftInitial = start; 20939 mUserPaddingRightInitial = end; 20940 internalSetPadding(start, top, end, bottom); 20941 } 20942 } 20943 20944 /** 20945 * Returns the top padding of this view. 20946 * 20947 * @return the top padding in pixels 20948 */ 20949 public int getPaddingTop() { 20950 return mPaddingTop; 20951 } 20952 20953 /** 20954 * Returns the bottom padding of this view. If there are inset and enabled 20955 * scrollbars, this value may include the space required to display the 20956 * scrollbars as well. 20957 * 20958 * @return the bottom padding in pixels 20959 */ 20960 public int getPaddingBottom() { 20961 return mPaddingBottom; 20962 } 20963 20964 /** 20965 * Returns the left padding of this view. If there are inset and enabled 20966 * scrollbars, this value may include the space required to display the 20967 * scrollbars as well. 20968 * 20969 * @return the left padding in pixels 20970 */ 20971 public int getPaddingLeft() { 20972 if (!isPaddingResolved()) { 20973 resolvePadding(); 20974 } 20975 return mPaddingLeft; 20976 } 20977 20978 /** 20979 * Returns the start padding of this view depending on its resolved layout direction. 20980 * If there are inset and enabled scrollbars, this value may include the space 20981 * required to display the scrollbars as well. 20982 * 20983 * @return the start padding in pixels 20984 */ 20985 public int getPaddingStart() { 20986 if (!isPaddingResolved()) { 20987 resolvePadding(); 20988 } 20989 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 20990 mPaddingRight : mPaddingLeft; 20991 } 20992 20993 /** 20994 * Returns the right padding of this view. If there are inset and enabled 20995 * scrollbars, this value may include the space required to display the 20996 * scrollbars as well. 20997 * 20998 * @return the right padding in pixels 20999 */ 21000 public int getPaddingRight() { 21001 if (!isPaddingResolved()) { 21002 resolvePadding(); 21003 } 21004 return mPaddingRight; 21005 } 21006 21007 /** 21008 * Returns the end padding of this view depending on its resolved layout direction. 21009 * If there are inset and enabled scrollbars, this value may include the space 21010 * required to display the scrollbars as well. 21011 * 21012 * @return the end padding in pixels 21013 */ 21014 public int getPaddingEnd() { 21015 if (!isPaddingResolved()) { 21016 resolvePadding(); 21017 } 21018 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 21019 mPaddingLeft : mPaddingRight; 21020 } 21021 21022 /** 21023 * Return if the padding has been set through relative values 21024 * {@link #setPaddingRelative(int, int, int, int)} or through 21025 * @attr ref android.R.styleable#View_paddingStart or 21026 * @attr ref android.R.styleable#View_paddingEnd 21027 * 21028 * @return true if the padding is relative or false if it is not. 21029 */ 21030 public boolean isPaddingRelative() { 21031 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 21032 } 21033 21034 Insets computeOpticalInsets() { 21035 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 21036 } 21037 21038 /** 21039 * @hide 21040 */ 21041 public void resetPaddingToInitialValues() { 21042 if (isRtlCompatibilityMode()) { 21043 mPaddingLeft = mUserPaddingLeftInitial; 21044 mPaddingRight = mUserPaddingRightInitial; 21045 return; 21046 } 21047 if (isLayoutRtl()) { 21048 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 21049 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 21050 } else { 21051 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 21052 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 21053 } 21054 } 21055 21056 /** 21057 * @hide 21058 */ 21059 public Insets getOpticalInsets() { 21060 if (mLayoutInsets == null) { 21061 mLayoutInsets = computeOpticalInsets(); 21062 } 21063 return mLayoutInsets; 21064 } 21065 21066 /** 21067 * Set this view's optical insets. 21068 * 21069 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 21070 * property. Views that compute their own optical insets should call it as part of measurement. 21071 * This method does not request layout. If you are setting optical insets outside of 21072 * measure/layout itself you will want to call requestLayout() yourself. 21073 * </p> 21074 * @hide 21075 */ 21076 public void setOpticalInsets(Insets insets) { 21077 mLayoutInsets = insets; 21078 } 21079 21080 /** 21081 * Changes the selection state of this view. A view can be selected or not. 21082 * Note that selection is not the same as focus. Views are typically 21083 * selected in the context of an AdapterView like ListView or GridView; 21084 * the selected view is the view that is highlighted. 21085 * 21086 * @param selected true if the view must be selected, false otherwise 21087 */ 21088 public void setSelected(boolean selected) { 21089 //noinspection DoubleNegation 21090 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 21091 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 21092 if (!selected) resetPressedState(); 21093 invalidate(true); 21094 refreshDrawableState(); 21095 dispatchSetSelected(selected); 21096 if (selected) { 21097 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 21098 } else { 21099 notifyViewAccessibilityStateChangedIfNeeded( 21100 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 21101 } 21102 } 21103 } 21104 21105 /** 21106 * Dispatch setSelected to all of this View's children. 21107 * 21108 * @see #setSelected(boolean) 21109 * 21110 * @param selected The new selected state 21111 */ 21112 protected void dispatchSetSelected(boolean selected) { 21113 } 21114 21115 /** 21116 * Indicates the selection state of this view. 21117 * 21118 * @return true if the view is selected, false otherwise 21119 */ 21120 @ViewDebug.ExportedProperty 21121 public boolean isSelected() { 21122 return (mPrivateFlags & PFLAG_SELECTED) != 0; 21123 } 21124 21125 /** 21126 * Changes the activated state of this view. A view can be activated or not. 21127 * Note that activation is not the same as selection. Selection is 21128 * a transient property, representing the view (hierarchy) the user is 21129 * currently interacting with. Activation is a longer-term state that the 21130 * user can move views in and out of. For example, in a list view with 21131 * single or multiple selection enabled, the views in the current selection 21132 * set are activated. (Um, yeah, we are deeply sorry about the terminology 21133 * here.) The activated state is propagated down to children of the view it 21134 * is set on. 21135 * 21136 * @param activated true if the view must be activated, false otherwise 21137 */ 21138 public void setActivated(boolean activated) { 21139 //noinspection DoubleNegation 21140 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 21141 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 21142 invalidate(true); 21143 refreshDrawableState(); 21144 dispatchSetActivated(activated); 21145 } 21146 } 21147 21148 /** 21149 * Dispatch setActivated to all of this View's children. 21150 * 21151 * @see #setActivated(boolean) 21152 * 21153 * @param activated The new activated state 21154 */ 21155 protected void dispatchSetActivated(boolean activated) { 21156 } 21157 21158 /** 21159 * Indicates the activation state of this view. 21160 * 21161 * @return true if the view is activated, false otherwise 21162 */ 21163 @ViewDebug.ExportedProperty 21164 public boolean isActivated() { 21165 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 21166 } 21167 21168 /** 21169 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 21170 * observer can be used to get notifications when global events, like 21171 * layout, happen. 21172 * 21173 * The returned ViewTreeObserver observer is not guaranteed to remain 21174 * valid for the lifetime of this View. If the caller of this method keeps 21175 * a long-lived reference to ViewTreeObserver, it should always check for 21176 * the return value of {@link ViewTreeObserver#isAlive()}. 21177 * 21178 * @return The ViewTreeObserver for this view's hierarchy. 21179 */ 21180 public ViewTreeObserver getViewTreeObserver() { 21181 if (mAttachInfo != null) { 21182 return mAttachInfo.mTreeObserver; 21183 } 21184 if (mFloatingTreeObserver == null) { 21185 mFloatingTreeObserver = new ViewTreeObserver(mContext); 21186 } 21187 return mFloatingTreeObserver; 21188 } 21189 21190 /** 21191 * <p>Finds the topmost view in the current view hierarchy.</p> 21192 * 21193 * @return the topmost view containing this view 21194 */ 21195 public View getRootView() { 21196 if (mAttachInfo != null) { 21197 final View v = mAttachInfo.mRootView; 21198 if (v != null) { 21199 return v; 21200 } 21201 } 21202 21203 View parent = this; 21204 21205 while (parent.mParent != null && parent.mParent instanceof View) { 21206 parent = (View) parent.mParent; 21207 } 21208 21209 return parent; 21210 } 21211 21212 /** 21213 * Transforms a motion event from view-local coordinates to on-screen 21214 * coordinates. 21215 * 21216 * @param ev the view-local motion event 21217 * @return false if the transformation could not be applied 21218 * @hide 21219 */ 21220 public boolean toGlobalMotionEvent(MotionEvent ev) { 21221 final AttachInfo info = mAttachInfo; 21222 if (info == null) { 21223 return false; 21224 } 21225 21226 final Matrix m = info.mTmpMatrix; 21227 m.set(Matrix.IDENTITY_MATRIX); 21228 transformMatrixToGlobal(m); 21229 ev.transform(m); 21230 return true; 21231 } 21232 21233 /** 21234 * Transforms a motion event from on-screen coordinates to view-local 21235 * coordinates. 21236 * 21237 * @param ev the on-screen motion event 21238 * @return false if the transformation could not be applied 21239 * @hide 21240 */ 21241 public boolean toLocalMotionEvent(MotionEvent ev) { 21242 final AttachInfo info = mAttachInfo; 21243 if (info == null) { 21244 return false; 21245 } 21246 21247 final Matrix m = info.mTmpMatrix; 21248 m.set(Matrix.IDENTITY_MATRIX); 21249 transformMatrixToLocal(m); 21250 ev.transform(m); 21251 return true; 21252 } 21253 21254 /** 21255 * Modifies the input matrix such that it maps view-local coordinates to 21256 * on-screen coordinates. 21257 * 21258 * @param m input matrix to modify 21259 * @hide 21260 */ 21261 public void transformMatrixToGlobal(Matrix m) { 21262 final ViewParent parent = mParent; 21263 if (parent instanceof View) { 21264 final View vp = (View) parent; 21265 vp.transformMatrixToGlobal(m); 21266 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 21267 } else if (parent instanceof ViewRootImpl) { 21268 final ViewRootImpl vr = (ViewRootImpl) parent; 21269 vr.transformMatrixToGlobal(m); 21270 m.preTranslate(0, -vr.mCurScrollY); 21271 } 21272 21273 m.preTranslate(mLeft, mTop); 21274 21275 if (!hasIdentityMatrix()) { 21276 m.preConcat(getMatrix()); 21277 } 21278 } 21279 21280 /** 21281 * Modifies the input matrix such that it maps on-screen coordinates to 21282 * view-local coordinates. 21283 * 21284 * @param m input matrix to modify 21285 * @hide 21286 */ 21287 public void transformMatrixToLocal(Matrix m) { 21288 final ViewParent parent = mParent; 21289 if (parent instanceof View) { 21290 final View vp = (View) parent; 21291 vp.transformMatrixToLocal(m); 21292 m.postTranslate(vp.mScrollX, vp.mScrollY); 21293 } else if (parent instanceof ViewRootImpl) { 21294 final ViewRootImpl vr = (ViewRootImpl) parent; 21295 vr.transformMatrixToLocal(m); 21296 m.postTranslate(0, vr.mCurScrollY); 21297 } 21298 21299 m.postTranslate(-mLeft, -mTop); 21300 21301 if (!hasIdentityMatrix()) { 21302 m.postConcat(getInverseMatrix()); 21303 } 21304 } 21305 21306 /** 21307 * @hide 21308 */ 21309 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 21310 @ViewDebug.IntToString(from = 0, to = "x"), 21311 @ViewDebug.IntToString(from = 1, to = "y") 21312 }) 21313 public int[] getLocationOnScreen() { 21314 int[] location = new int[2]; 21315 getLocationOnScreen(location); 21316 return location; 21317 } 21318 21319 /** 21320 * <p>Computes the coordinates of this view on the screen. The argument 21321 * must be an array of two integers. After the method returns, the array 21322 * contains the x and y location in that order.</p> 21323 * 21324 * @param outLocation an array of two integers in which to hold the coordinates 21325 */ 21326 public void getLocationOnScreen(@Size(2) int[] outLocation) { 21327 getLocationInWindow(outLocation); 21328 21329 final AttachInfo info = mAttachInfo; 21330 if (info != null) { 21331 outLocation[0] += info.mWindowLeft; 21332 outLocation[1] += info.mWindowTop; 21333 } 21334 } 21335 21336 /** 21337 * <p>Computes the coordinates of this view in its window. The argument 21338 * must be an array of two integers. After the method returns, the array 21339 * contains the x and y location in that order.</p> 21340 * 21341 * @param outLocation an array of two integers in which to hold the coordinates 21342 */ 21343 public void getLocationInWindow(@Size(2) int[] outLocation) { 21344 if (outLocation == null || outLocation.length < 2) { 21345 throw new IllegalArgumentException("outLocation must be an array of two integers"); 21346 } 21347 21348 outLocation[0] = 0; 21349 outLocation[1] = 0; 21350 21351 transformFromViewToWindowSpace(outLocation); 21352 } 21353 21354 /** @hide */ 21355 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 21356 if (inOutLocation == null || inOutLocation.length < 2) { 21357 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 21358 } 21359 21360 if (mAttachInfo == null) { 21361 // When the view is not attached to a window, this method does not make sense 21362 inOutLocation[0] = inOutLocation[1] = 0; 21363 return; 21364 } 21365 21366 float position[] = mAttachInfo.mTmpTransformLocation; 21367 position[0] = inOutLocation[0]; 21368 position[1] = inOutLocation[1]; 21369 21370 if (!hasIdentityMatrix()) { 21371 getMatrix().mapPoints(position); 21372 } 21373 21374 position[0] += mLeft; 21375 position[1] += mTop; 21376 21377 ViewParent viewParent = mParent; 21378 while (viewParent instanceof View) { 21379 final View view = (View) viewParent; 21380 21381 position[0] -= view.mScrollX; 21382 position[1] -= view.mScrollY; 21383 21384 if (!view.hasIdentityMatrix()) { 21385 view.getMatrix().mapPoints(position); 21386 } 21387 21388 position[0] += view.mLeft; 21389 position[1] += view.mTop; 21390 21391 viewParent = view.mParent; 21392 } 21393 21394 if (viewParent instanceof ViewRootImpl) { 21395 // *cough* 21396 final ViewRootImpl vr = (ViewRootImpl) viewParent; 21397 position[1] -= vr.mCurScrollY; 21398 } 21399 21400 inOutLocation[0] = Math.round(position[0]); 21401 inOutLocation[1] = Math.round(position[1]); 21402 } 21403 21404 /** 21405 * @param id the id of the view to be found 21406 * @return the view of the specified id, null if cannot be found 21407 * @hide 21408 */ 21409 protected <T extends View> T findViewTraversal(@IdRes int id) { 21410 if (id == mID) { 21411 return (T) this; 21412 } 21413 return null; 21414 } 21415 21416 /** 21417 * @param tag the tag of the view to be found 21418 * @return the view of specified tag, null if cannot be found 21419 * @hide 21420 */ 21421 protected <T extends View> T findViewWithTagTraversal(Object tag) { 21422 if (tag != null && tag.equals(mTag)) { 21423 return (T) this; 21424 } 21425 return null; 21426 } 21427 21428 /** 21429 * @param predicate The predicate to evaluate. 21430 * @param childToSkip If not null, ignores this child during the recursive traversal. 21431 * @return The first view that matches the predicate or null. 21432 * @hide 21433 */ 21434 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 21435 View childToSkip) { 21436 if (predicate.test(this)) { 21437 return (T) this; 21438 } 21439 return null; 21440 } 21441 21442 /** 21443 * Finds the first descendant view with the given ID, the view itself if 21444 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 21445 * (< 0) or there is no matching view in the hierarchy. 21446 * <p> 21447 * <strong>Note:</strong> In most cases -- depending on compiler support -- 21448 * the resulting view is automatically cast to the target class type. If 21449 * the target class type is unconstrained, an explicit cast may be 21450 * necessary. 21451 * 21452 * @param id the ID to search for 21453 * @return a view with given ID if found, or {@code null} otherwise 21454 * @see View#findViewById(int) 21455 */ 21456 @Nullable 21457 public final <T extends View> T findViewById(@IdRes int id) { 21458 if (id == NO_ID) { 21459 return null; 21460 } 21461 return findViewTraversal(id); 21462 } 21463 21464 /** 21465 * Finds a view by its unuque and stable accessibility id. 21466 * 21467 * @param accessibilityId The searched accessibility id. 21468 * @return The found view. 21469 */ 21470 final <T extends View> T findViewByAccessibilityId(int accessibilityId) { 21471 if (accessibilityId < 0) { 21472 return null; 21473 } 21474 T view = findViewByAccessibilityIdTraversal(accessibilityId); 21475 if (view != null) { 21476 return view.includeForAccessibility() ? view : null; 21477 } 21478 return null; 21479 } 21480 21481 /** 21482 * Performs the traversal to find a view by its unuque and stable accessibility id. 21483 * 21484 * <strong>Note:</strong>This method does not stop at the root namespace 21485 * boundary since the user can touch the screen at an arbitrary location 21486 * potentially crossing the root namespace bounday which will send an 21487 * accessibility event to accessibility services and they should be able 21488 * to obtain the event source. Also accessibility ids are guaranteed to be 21489 * unique in the window. 21490 * 21491 * @param accessibilityId The accessibility id. 21492 * @return The found view. 21493 * @hide 21494 */ 21495 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 21496 if (getAccessibilityViewId() == accessibilityId) { 21497 return (T) this; 21498 } 21499 return null; 21500 } 21501 21502 /** 21503 * Look for a child view with the given tag. If this view has the given 21504 * tag, return this view. 21505 * 21506 * @param tag The tag to search for, using "tag.equals(getTag())". 21507 * @return The View that has the given tag in the hierarchy or null 21508 */ 21509 public final <T extends View> T findViewWithTag(Object tag) { 21510 if (tag == null) { 21511 return null; 21512 } 21513 return findViewWithTagTraversal(tag); 21514 } 21515 21516 /** 21517 * Look for a child view that matches the specified predicate. 21518 * If this view matches the predicate, return this view. 21519 * 21520 * @param predicate The predicate to evaluate. 21521 * @return The first view that matches the predicate or null. 21522 * @hide 21523 */ 21524 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 21525 return findViewByPredicateTraversal(predicate, null); 21526 } 21527 21528 /** 21529 * Look for a child view that matches the specified predicate, 21530 * starting with the specified view and its descendents and then 21531 * recusively searching the ancestors and siblings of that view 21532 * until this view is reached. 21533 * 21534 * This method is useful in cases where the predicate does not match 21535 * a single unique view (perhaps multiple views use the same id) 21536 * and we are trying to find the view that is "closest" in scope to the 21537 * starting view. 21538 * 21539 * @param start The view to start from. 21540 * @param predicate The predicate to evaluate. 21541 * @return The first view that matches the predicate or null. 21542 * @hide 21543 */ 21544 public final <T extends View> T findViewByPredicateInsideOut( 21545 View start, Predicate<View> predicate) { 21546 View childToSkip = null; 21547 for (;;) { 21548 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 21549 if (view != null || start == this) { 21550 return view; 21551 } 21552 21553 ViewParent parent = start.getParent(); 21554 if (parent == null || !(parent instanceof View)) { 21555 return null; 21556 } 21557 21558 childToSkip = start; 21559 start = (View) parent; 21560 } 21561 } 21562 21563 /** 21564 * Sets the identifier for this view. The identifier does not have to be 21565 * unique in this view's hierarchy. The identifier should be a positive 21566 * number. 21567 * 21568 * @see #NO_ID 21569 * @see #getId() 21570 * @see #findViewById(int) 21571 * 21572 * @param id a number used to identify the view 21573 * 21574 * @attr ref android.R.styleable#View_id 21575 */ 21576 public void setId(@IdRes int id) { 21577 mID = id; 21578 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 21579 mID = generateViewId(); 21580 } 21581 } 21582 21583 /** 21584 * {@hide} 21585 * 21586 * @param isRoot true if the view belongs to the root namespace, false 21587 * otherwise 21588 */ 21589 public void setIsRootNamespace(boolean isRoot) { 21590 if (isRoot) { 21591 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 21592 } else { 21593 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 21594 } 21595 } 21596 21597 /** 21598 * {@hide} 21599 * 21600 * @return true if the view belongs to the root namespace, false otherwise 21601 */ 21602 public boolean isRootNamespace() { 21603 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 21604 } 21605 21606 /** 21607 * Returns this view's identifier. 21608 * 21609 * @return a positive integer used to identify the view or {@link #NO_ID} 21610 * if the view has no ID 21611 * 21612 * @see #setId(int) 21613 * @see #findViewById(int) 21614 * @attr ref android.R.styleable#View_id 21615 */ 21616 @IdRes 21617 @ViewDebug.CapturedViewProperty 21618 public int getId() { 21619 return mID; 21620 } 21621 21622 /** 21623 * Returns this view's tag. 21624 * 21625 * @return the Object stored in this view as a tag, or {@code null} if not 21626 * set 21627 * 21628 * @see #setTag(Object) 21629 * @see #getTag(int) 21630 */ 21631 @ViewDebug.ExportedProperty 21632 public Object getTag() { 21633 return mTag; 21634 } 21635 21636 /** 21637 * Sets the tag associated with this view. A tag can be used to mark 21638 * a view in its hierarchy and does not have to be unique within the 21639 * hierarchy. Tags can also be used to store data within a view without 21640 * resorting to another data structure. 21641 * 21642 * @param tag an Object to tag the view with 21643 * 21644 * @see #getTag() 21645 * @see #setTag(int, Object) 21646 */ 21647 public void setTag(final Object tag) { 21648 mTag = tag; 21649 } 21650 21651 /** 21652 * Returns the tag associated with this view and the specified key. 21653 * 21654 * @param key The key identifying the tag 21655 * 21656 * @return the Object stored in this view as a tag, or {@code null} if not 21657 * set 21658 * 21659 * @see #setTag(int, Object) 21660 * @see #getTag() 21661 */ 21662 public Object getTag(int key) { 21663 if (mKeyedTags != null) return mKeyedTags.get(key); 21664 return null; 21665 } 21666 21667 /** 21668 * Sets a tag associated with this view and a key. A tag can be used 21669 * to mark a view in its hierarchy and does not have to be unique within 21670 * the hierarchy. Tags can also be used to store data within a view 21671 * without resorting to another data structure. 21672 * 21673 * The specified key should be an id declared in the resources of the 21674 * application to ensure it is unique (see the <a 21675 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 21676 * Keys identified as belonging to 21677 * the Android framework or not associated with any package will cause 21678 * an {@link IllegalArgumentException} to be thrown. 21679 * 21680 * @param key The key identifying the tag 21681 * @param tag An Object to tag the view with 21682 * 21683 * @throws IllegalArgumentException If they specified key is not valid 21684 * 21685 * @see #setTag(Object) 21686 * @see #getTag(int) 21687 */ 21688 public void setTag(int key, final Object tag) { 21689 // If the package id is 0x00 or 0x01, it's either an undefined package 21690 // or a framework id 21691 if ((key >>> 24) < 2) { 21692 throw new IllegalArgumentException("The key must be an application-specific " 21693 + "resource id."); 21694 } 21695 21696 setKeyedTag(key, tag); 21697 } 21698 21699 /** 21700 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 21701 * framework id. 21702 * 21703 * @hide 21704 */ 21705 public void setTagInternal(int key, Object tag) { 21706 if ((key >>> 24) != 0x1) { 21707 throw new IllegalArgumentException("The key must be a framework-specific " 21708 + "resource id."); 21709 } 21710 21711 setKeyedTag(key, tag); 21712 } 21713 21714 private void setKeyedTag(int key, Object tag) { 21715 if (mKeyedTags == null) { 21716 mKeyedTags = new SparseArray<Object>(2); 21717 } 21718 21719 mKeyedTags.put(key, tag); 21720 } 21721 21722 /** 21723 * Prints information about this view in the log output, with the tag 21724 * {@link #VIEW_LOG_TAG}. 21725 * 21726 * @hide 21727 */ 21728 public void debug() { 21729 debug(0); 21730 } 21731 21732 /** 21733 * Prints information about this view in the log output, with the tag 21734 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 21735 * indentation defined by the <code>depth</code>. 21736 * 21737 * @param depth the indentation level 21738 * 21739 * @hide 21740 */ 21741 protected void debug(int depth) { 21742 String output = debugIndent(depth - 1); 21743 21744 output += "+ " + this; 21745 int id = getId(); 21746 if (id != -1) { 21747 output += " (id=" + id + ")"; 21748 } 21749 Object tag = getTag(); 21750 if (tag != null) { 21751 output += " (tag=" + tag + ")"; 21752 } 21753 Log.d(VIEW_LOG_TAG, output); 21754 21755 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 21756 output = debugIndent(depth) + " FOCUSED"; 21757 Log.d(VIEW_LOG_TAG, output); 21758 } 21759 21760 output = debugIndent(depth); 21761 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 21762 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 21763 + "} "; 21764 Log.d(VIEW_LOG_TAG, output); 21765 21766 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 21767 || mPaddingBottom != 0) { 21768 output = debugIndent(depth); 21769 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 21770 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 21771 Log.d(VIEW_LOG_TAG, output); 21772 } 21773 21774 output = debugIndent(depth); 21775 output += "mMeasureWidth=" + mMeasuredWidth + 21776 " mMeasureHeight=" + mMeasuredHeight; 21777 Log.d(VIEW_LOG_TAG, output); 21778 21779 output = debugIndent(depth); 21780 if (mLayoutParams == null) { 21781 output += "BAD! no layout params"; 21782 } else { 21783 output = mLayoutParams.debug(output); 21784 } 21785 Log.d(VIEW_LOG_TAG, output); 21786 21787 output = debugIndent(depth); 21788 output += "flags={"; 21789 output += View.printFlags(mViewFlags); 21790 output += "}"; 21791 Log.d(VIEW_LOG_TAG, output); 21792 21793 output = debugIndent(depth); 21794 output += "privateFlags={"; 21795 output += View.printPrivateFlags(mPrivateFlags); 21796 output += "}"; 21797 Log.d(VIEW_LOG_TAG, output); 21798 } 21799 21800 /** 21801 * Creates a string of whitespaces used for indentation. 21802 * 21803 * @param depth the indentation level 21804 * @return a String containing (depth * 2 + 3) * 2 white spaces 21805 * 21806 * @hide 21807 */ 21808 protected static String debugIndent(int depth) { 21809 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 21810 for (int i = 0; i < (depth * 2) + 3; i++) { 21811 spaces.append(' ').append(' '); 21812 } 21813 return spaces.toString(); 21814 } 21815 21816 /** 21817 * <p>Return the offset of the widget's text baseline from the widget's top 21818 * boundary. If this widget does not support baseline alignment, this 21819 * method returns -1. </p> 21820 * 21821 * @return the offset of the baseline within the widget's bounds or -1 21822 * if baseline alignment is not supported 21823 */ 21824 @ViewDebug.ExportedProperty(category = "layout") 21825 public int getBaseline() { 21826 return -1; 21827 } 21828 21829 /** 21830 * Returns whether the view hierarchy is currently undergoing a layout pass. This 21831 * information is useful to avoid situations such as calling {@link #requestLayout()} during 21832 * a layout pass. 21833 * 21834 * @return whether the view hierarchy is currently undergoing a layout pass 21835 */ 21836 public boolean isInLayout() { 21837 ViewRootImpl viewRoot = getViewRootImpl(); 21838 return (viewRoot != null && viewRoot.isInLayout()); 21839 } 21840 21841 /** 21842 * Call this when something has changed which has invalidated the 21843 * layout of this view. This will schedule a layout pass of the view 21844 * tree. This should not be called while the view hierarchy is currently in a layout 21845 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 21846 * end of the current layout pass (and then layout will run again) or after the current 21847 * frame is drawn and the next layout occurs. 21848 * 21849 * <p>Subclasses which override this method should call the superclass method to 21850 * handle possible request-during-layout errors correctly.</p> 21851 */ 21852 @CallSuper 21853 public void requestLayout() { 21854 if (mMeasureCache != null) mMeasureCache.clear(); 21855 21856 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 21857 // Only trigger request-during-layout logic if this is the view requesting it, 21858 // not the views in its parent hierarchy 21859 ViewRootImpl viewRoot = getViewRootImpl(); 21860 if (viewRoot != null && viewRoot.isInLayout()) { 21861 if (!viewRoot.requestLayoutDuringLayout(this)) { 21862 return; 21863 } 21864 } 21865 mAttachInfo.mViewRequestingLayout = this; 21866 } 21867 21868 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21869 mPrivateFlags |= PFLAG_INVALIDATED; 21870 21871 if (mParent != null && !mParent.isLayoutRequested()) { 21872 mParent.requestLayout(); 21873 } 21874 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 21875 mAttachInfo.mViewRequestingLayout = null; 21876 } 21877 } 21878 21879 /** 21880 * Forces this view to be laid out during the next layout pass. 21881 * This method does not call requestLayout() or forceLayout() 21882 * on the parent. 21883 */ 21884 public void forceLayout() { 21885 if (mMeasureCache != null) mMeasureCache.clear(); 21886 21887 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21888 mPrivateFlags |= PFLAG_INVALIDATED; 21889 } 21890 21891 /** 21892 * <p> 21893 * This is called to find out how big a view should be. The parent 21894 * supplies constraint information in the width and height parameters. 21895 * </p> 21896 * 21897 * <p> 21898 * The actual measurement work of a view is performed in 21899 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 21900 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 21901 * </p> 21902 * 21903 * 21904 * @param widthMeasureSpec Horizontal space requirements as imposed by the 21905 * parent 21906 * @param heightMeasureSpec Vertical space requirements as imposed by the 21907 * parent 21908 * 21909 * @see #onMeasure(int, int) 21910 */ 21911 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 21912 boolean optical = isLayoutModeOptical(this); 21913 if (optical != isLayoutModeOptical(mParent)) { 21914 Insets insets = getOpticalInsets(); 21915 int oWidth = insets.left + insets.right; 21916 int oHeight = insets.top + insets.bottom; 21917 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 21918 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 21919 } 21920 21921 // Suppress sign extension for the low bytes 21922 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 21923 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 21924 21925 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 21926 21927 // Optimize layout by avoiding an extra EXACTLY pass when the view is 21928 // already measured as the correct size. In API 23 and below, this 21929 // extra pass is required to make LinearLayout re-distribute weight. 21930 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 21931 || heightMeasureSpec != mOldHeightMeasureSpec; 21932 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 21933 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 21934 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 21935 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 21936 final boolean needsLayout = specChanged 21937 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 21938 21939 if (forceLayout || needsLayout) { 21940 // first clears the measured dimension flag 21941 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 21942 21943 resolveRtlPropertiesIfNeeded(); 21944 21945 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 21946 if (cacheIndex < 0 || sIgnoreMeasureCache) { 21947 // measure ourselves, this should set the measured dimension flag back 21948 onMeasure(widthMeasureSpec, heightMeasureSpec); 21949 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 21950 } else { 21951 long value = mMeasureCache.valueAt(cacheIndex); 21952 // Casting a long to int drops the high 32 bits, no mask needed 21953 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 21954 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 21955 } 21956 21957 // flag not set, setMeasuredDimension() was not invoked, we raise 21958 // an exception to warn the developer 21959 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 21960 throw new IllegalStateException("View with id " + getId() + ": " 21961 + getClass().getName() + "#onMeasure() did not set the" 21962 + " measured dimension by calling" 21963 + " setMeasuredDimension()"); 21964 } 21965 21966 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 21967 } 21968 21969 mOldWidthMeasureSpec = widthMeasureSpec; 21970 mOldHeightMeasureSpec = heightMeasureSpec; 21971 21972 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 21973 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 21974 } 21975 21976 /** 21977 * <p> 21978 * Measure the view and its content to determine the measured width and the 21979 * measured height. This method is invoked by {@link #measure(int, int)} and 21980 * should be overridden by subclasses to provide accurate and efficient 21981 * measurement of their contents. 21982 * </p> 21983 * 21984 * <p> 21985 * <strong>CONTRACT:</strong> When overriding this method, you 21986 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 21987 * measured width and height of this view. Failure to do so will trigger an 21988 * <code>IllegalStateException</code>, thrown by 21989 * {@link #measure(int, int)}. Calling the superclass' 21990 * {@link #onMeasure(int, int)} is a valid use. 21991 * </p> 21992 * 21993 * <p> 21994 * The base class implementation of measure defaults to the background size, 21995 * unless a larger size is allowed by the MeasureSpec. Subclasses should 21996 * override {@link #onMeasure(int, int)} to provide better measurements of 21997 * their content. 21998 * </p> 21999 * 22000 * <p> 22001 * If this method is overridden, it is the subclass's responsibility to make 22002 * sure the measured height and width are at least the view's minimum height 22003 * and width ({@link #getSuggestedMinimumHeight()} and 22004 * {@link #getSuggestedMinimumWidth()}). 22005 * </p> 22006 * 22007 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 22008 * The requirements are encoded with 22009 * {@link android.view.View.MeasureSpec}. 22010 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 22011 * The requirements are encoded with 22012 * {@link android.view.View.MeasureSpec}. 22013 * 22014 * @see #getMeasuredWidth() 22015 * @see #getMeasuredHeight() 22016 * @see #setMeasuredDimension(int, int) 22017 * @see #getSuggestedMinimumHeight() 22018 * @see #getSuggestedMinimumWidth() 22019 * @see android.view.View.MeasureSpec#getMode(int) 22020 * @see android.view.View.MeasureSpec#getSize(int) 22021 */ 22022 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 22023 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 22024 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 22025 } 22026 22027 /** 22028 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 22029 * measured width and measured height. Failing to do so will trigger an 22030 * exception at measurement time.</p> 22031 * 22032 * @param measuredWidth The measured width of this view. May be a complex 22033 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22034 * {@link #MEASURED_STATE_TOO_SMALL}. 22035 * @param measuredHeight The measured height of this view. May be a complex 22036 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22037 * {@link #MEASURED_STATE_TOO_SMALL}. 22038 */ 22039 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 22040 boolean optical = isLayoutModeOptical(this); 22041 if (optical != isLayoutModeOptical(mParent)) { 22042 Insets insets = getOpticalInsets(); 22043 int opticalWidth = insets.left + insets.right; 22044 int opticalHeight = insets.top + insets.bottom; 22045 22046 measuredWidth += optical ? opticalWidth : -opticalWidth; 22047 measuredHeight += optical ? opticalHeight : -opticalHeight; 22048 } 22049 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 22050 } 22051 22052 /** 22053 * Sets the measured dimension without extra processing for things like optical bounds. 22054 * Useful for reapplying consistent values that have already been cooked with adjustments 22055 * for optical bounds, etc. such as those from the measurement cache. 22056 * 22057 * @param measuredWidth The measured width of this view. May be a complex 22058 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22059 * {@link #MEASURED_STATE_TOO_SMALL}. 22060 * @param measuredHeight The measured height of this view. May be a complex 22061 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22062 * {@link #MEASURED_STATE_TOO_SMALL}. 22063 */ 22064 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 22065 mMeasuredWidth = measuredWidth; 22066 mMeasuredHeight = measuredHeight; 22067 22068 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 22069 } 22070 22071 /** 22072 * Merge two states as returned by {@link #getMeasuredState()}. 22073 * @param curState The current state as returned from a view or the result 22074 * of combining multiple views. 22075 * @param newState The new view state to combine. 22076 * @return Returns a new integer reflecting the combination of the two 22077 * states. 22078 */ 22079 public static int combineMeasuredStates(int curState, int newState) { 22080 return curState | newState; 22081 } 22082 22083 /** 22084 * Version of {@link #resolveSizeAndState(int, int, int)} 22085 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 22086 */ 22087 public static int resolveSize(int size, int measureSpec) { 22088 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 22089 } 22090 22091 /** 22092 * Utility to reconcile a desired size and state, with constraints imposed 22093 * by a MeasureSpec. Will take the desired size, unless a different size 22094 * is imposed by the constraints. The returned value is a compound integer, 22095 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 22096 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 22097 * resulting size is smaller than the size the view wants to be. 22098 * 22099 * @param size How big the view wants to be. 22100 * @param measureSpec Constraints imposed by the parent. 22101 * @param childMeasuredState Size information bit mask for the view's 22102 * children. 22103 * @return Size information bit mask as defined by 22104 * {@link #MEASURED_SIZE_MASK} and 22105 * {@link #MEASURED_STATE_TOO_SMALL}. 22106 */ 22107 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 22108 final int specMode = MeasureSpec.getMode(measureSpec); 22109 final int specSize = MeasureSpec.getSize(measureSpec); 22110 final int result; 22111 switch (specMode) { 22112 case MeasureSpec.AT_MOST: 22113 if (specSize < size) { 22114 result = specSize | MEASURED_STATE_TOO_SMALL; 22115 } else { 22116 result = size; 22117 } 22118 break; 22119 case MeasureSpec.EXACTLY: 22120 result = specSize; 22121 break; 22122 case MeasureSpec.UNSPECIFIED: 22123 default: 22124 result = size; 22125 } 22126 return result | (childMeasuredState & MEASURED_STATE_MASK); 22127 } 22128 22129 /** 22130 * Utility to return a default size. Uses the supplied size if the 22131 * MeasureSpec imposed no constraints. Will get larger if allowed 22132 * by the MeasureSpec. 22133 * 22134 * @param size Default size for this view 22135 * @param measureSpec Constraints imposed by the parent 22136 * @return The size this view should be. 22137 */ 22138 public static int getDefaultSize(int size, int measureSpec) { 22139 int result = size; 22140 int specMode = MeasureSpec.getMode(measureSpec); 22141 int specSize = MeasureSpec.getSize(measureSpec); 22142 22143 switch (specMode) { 22144 case MeasureSpec.UNSPECIFIED: 22145 result = size; 22146 break; 22147 case MeasureSpec.AT_MOST: 22148 case MeasureSpec.EXACTLY: 22149 result = specSize; 22150 break; 22151 } 22152 return result; 22153 } 22154 22155 /** 22156 * Returns the suggested minimum height that the view should use. This 22157 * returns the maximum of the view's minimum height 22158 * and the background's minimum height 22159 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 22160 * <p> 22161 * When being used in {@link #onMeasure(int, int)}, the caller should still 22162 * ensure the returned height is within the requirements of the parent. 22163 * 22164 * @return The suggested minimum height of the view. 22165 */ 22166 protected int getSuggestedMinimumHeight() { 22167 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 22168 22169 } 22170 22171 /** 22172 * Returns the suggested minimum width that the view should use. This 22173 * returns the maximum of the view's minimum width 22174 * and the background's minimum width 22175 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 22176 * <p> 22177 * When being used in {@link #onMeasure(int, int)}, the caller should still 22178 * ensure the returned width is within the requirements of the parent. 22179 * 22180 * @return The suggested minimum width of the view. 22181 */ 22182 protected int getSuggestedMinimumWidth() { 22183 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 22184 } 22185 22186 /** 22187 * Returns the minimum height of the view. 22188 * 22189 * @return the minimum height the view will try to be, in pixels 22190 * 22191 * @see #setMinimumHeight(int) 22192 * 22193 * @attr ref android.R.styleable#View_minHeight 22194 */ 22195 public int getMinimumHeight() { 22196 return mMinHeight; 22197 } 22198 22199 /** 22200 * Sets the minimum height of the view. It is not guaranteed the view will 22201 * be able to achieve this minimum height (for example, if its parent layout 22202 * constrains it with less available height). 22203 * 22204 * @param minHeight The minimum height the view will try to be, in pixels 22205 * 22206 * @see #getMinimumHeight() 22207 * 22208 * @attr ref android.R.styleable#View_minHeight 22209 */ 22210 @RemotableViewMethod 22211 public void setMinimumHeight(int minHeight) { 22212 mMinHeight = minHeight; 22213 requestLayout(); 22214 } 22215 22216 /** 22217 * Returns the minimum width of the view. 22218 * 22219 * @return the minimum width the view will try to be, in pixels 22220 * 22221 * @see #setMinimumWidth(int) 22222 * 22223 * @attr ref android.R.styleable#View_minWidth 22224 */ 22225 public int getMinimumWidth() { 22226 return mMinWidth; 22227 } 22228 22229 /** 22230 * Sets the minimum width of the view. It is not guaranteed the view will 22231 * be able to achieve this minimum width (for example, if its parent layout 22232 * constrains it with less available width). 22233 * 22234 * @param minWidth The minimum width the view will try to be, in pixels 22235 * 22236 * @see #getMinimumWidth() 22237 * 22238 * @attr ref android.R.styleable#View_minWidth 22239 */ 22240 public void setMinimumWidth(int minWidth) { 22241 mMinWidth = minWidth; 22242 requestLayout(); 22243 22244 } 22245 22246 /** 22247 * Get the animation currently associated with this view. 22248 * 22249 * @return The animation that is currently playing or 22250 * scheduled to play for this view. 22251 */ 22252 public Animation getAnimation() { 22253 return mCurrentAnimation; 22254 } 22255 22256 /** 22257 * Start the specified animation now. 22258 * 22259 * @param animation the animation to start now 22260 */ 22261 public void startAnimation(Animation animation) { 22262 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 22263 setAnimation(animation); 22264 invalidateParentCaches(); 22265 invalidate(true); 22266 } 22267 22268 /** 22269 * Cancels any animations for this view. 22270 */ 22271 public void clearAnimation() { 22272 if (mCurrentAnimation != null) { 22273 mCurrentAnimation.detach(); 22274 } 22275 mCurrentAnimation = null; 22276 invalidateParentIfNeeded(); 22277 } 22278 22279 /** 22280 * Sets the next animation to play for this view. 22281 * If you want the animation to play immediately, use 22282 * {@link #startAnimation(android.view.animation.Animation)} instead. 22283 * This method provides allows fine-grained 22284 * control over the start time and invalidation, but you 22285 * must make sure that 1) the animation has a start time set, and 22286 * 2) the view's parent (which controls animations on its children) 22287 * will be invalidated when the animation is supposed to 22288 * start. 22289 * 22290 * @param animation The next animation, or null. 22291 */ 22292 public void setAnimation(Animation animation) { 22293 mCurrentAnimation = animation; 22294 22295 if (animation != null) { 22296 // If the screen is off assume the animation start time is now instead of 22297 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 22298 // would cause the animation to start when the screen turns back on 22299 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 22300 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 22301 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 22302 } 22303 animation.reset(); 22304 } 22305 } 22306 22307 /** 22308 * Invoked by a parent ViewGroup to notify the start of the animation 22309 * currently associated with this view. If you override this method, 22310 * always call super.onAnimationStart(); 22311 * 22312 * @see #setAnimation(android.view.animation.Animation) 22313 * @see #getAnimation() 22314 */ 22315 @CallSuper 22316 protected void onAnimationStart() { 22317 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 22318 } 22319 22320 /** 22321 * Invoked by a parent ViewGroup to notify the end of the animation 22322 * currently associated with this view. If you override this method, 22323 * always call super.onAnimationEnd(); 22324 * 22325 * @see #setAnimation(android.view.animation.Animation) 22326 * @see #getAnimation() 22327 */ 22328 @CallSuper 22329 protected void onAnimationEnd() { 22330 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 22331 } 22332 22333 /** 22334 * Invoked if there is a Transform that involves alpha. Subclass that can 22335 * draw themselves with the specified alpha should return true, and then 22336 * respect that alpha when their onDraw() is called. If this returns false 22337 * then the view may be redirected to draw into an offscreen buffer to 22338 * fulfill the request, which will look fine, but may be slower than if the 22339 * subclass handles it internally. The default implementation returns false. 22340 * 22341 * @param alpha The alpha (0..255) to apply to the view's drawing 22342 * @return true if the view can draw with the specified alpha. 22343 */ 22344 protected boolean onSetAlpha(int alpha) { 22345 return false; 22346 } 22347 22348 /** 22349 * This is used by the RootView to perform an optimization when 22350 * the view hierarchy contains one or several SurfaceView. 22351 * SurfaceView is always considered transparent, but its children are not, 22352 * therefore all View objects remove themselves from the global transparent 22353 * region (passed as a parameter to this function). 22354 * 22355 * @param region The transparent region for this ViewAncestor (window). 22356 * 22357 * @return Returns true if the effective visibility of the view at this 22358 * point is opaque, regardless of the transparent region; returns false 22359 * if it is possible for underlying windows to be seen behind the view. 22360 * 22361 * {@hide} 22362 */ 22363 public boolean gatherTransparentRegion(Region region) { 22364 final AttachInfo attachInfo = mAttachInfo; 22365 if (region != null && attachInfo != null) { 22366 final int pflags = mPrivateFlags; 22367 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 22368 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 22369 // remove it from the transparent region. 22370 final int[] location = attachInfo.mTransparentLocation; 22371 getLocationInWindow(location); 22372 // When a view has Z value, then it will be better to leave some area below the view 22373 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 22374 // the bottom part needs more offset than the left, top and right parts due to the 22375 // spot light effects. 22376 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 22377 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 22378 location[0] + mRight - mLeft + shadowOffset, 22379 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 22380 } else { 22381 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 22382 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 22383 // the background drawable's non-transparent parts from this transparent region. 22384 applyDrawableToTransparentRegion(mBackground, region); 22385 } 22386 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 22387 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 22388 // Similarly, we remove the foreground drawable's non-transparent parts. 22389 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 22390 } 22391 if (mDefaultFocusHighlight != null 22392 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 22393 // Similarly, we remove the default focus highlight's non-transparent parts. 22394 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 22395 } 22396 } 22397 } 22398 return true; 22399 } 22400 22401 /** 22402 * Play a sound effect for this view. 22403 * 22404 * <p>The framework will play sound effects for some built in actions, such as 22405 * clicking, but you may wish to play these effects in your widget, 22406 * for instance, for internal navigation. 22407 * 22408 * <p>The sound effect will only be played if sound effects are enabled by the user, and 22409 * {@link #isSoundEffectsEnabled()} is true. 22410 * 22411 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 22412 */ 22413 public void playSoundEffect(int soundConstant) { 22414 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 22415 return; 22416 } 22417 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 22418 } 22419 22420 /** 22421 * BZZZTT!!1! 22422 * 22423 * <p>Provide haptic feedback to the user for this view. 22424 * 22425 * <p>The framework will provide haptic feedback for some built in actions, 22426 * such as long presses, but you may wish to provide feedback for your 22427 * own widget. 22428 * 22429 * <p>The feedback will only be performed if 22430 * {@link #isHapticFeedbackEnabled()} is true. 22431 * 22432 * @param feedbackConstant One of the constants defined in 22433 * {@link HapticFeedbackConstants} 22434 */ 22435 public boolean performHapticFeedback(int feedbackConstant) { 22436 return performHapticFeedback(feedbackConstant, 0); 22437 } 22438 22439 /** 22440 * BZZZTT!!1! 22441 * 22442 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 22443 * 22444 * @param feedbackConstant One of the constants defined in 22445 * {@link HapticFeedbackConstants} 22446 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 22447 */ 22448 public boolean performHapticFeedback(int feedbackConstant, int flags) { 22449 if (mAttachInfo == null) { 22450 return false; 22451 } 22452 //noinspection SimplifiableIfStatement 22453 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 22454 && !isHapticFeedbackEnabled()) { 22455 return false; 22456 } 22457 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 22458 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 22459 } 22460 22461 /** 22462 * Request that the visibility of the status bar or other screen/window 22463 * decorations be changed. 22464 * 22465 * <p>This method is used to put the over device UI into temporary modes 22466 * where the user's attention is focused more on the application content, 22467 * by dimming or hiding surrounding system affordances. This is typically 22468 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 22469 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 22470 * to be placed behind the action bar (and with these flags other system 22471 * affordances) so that smooth transitions between hiding and showing them 22472 * can be done. 22473 * 22474 * <p>Two representative examples of the use of system UI visibility is 22475 * implementing a content browsing application (like a magazine reader) 22476 * and a video playing application. 22477 * 22478 * <p>The first code shows a typical implementation of a View in a content 22479 * browsing application. In this implementation, the application goes 22480 * into a content-oriented mode by hiding the status bar and action bar, 22481 * and putting the navigation elements into lights out mode. The user can 22482 * then interact with content while in this mode. Such an application should 22483 * provide an easy way for the user to toggle out of the mode (such as to 22484 * check information in the status bar or access notifications). In the 22485 * implementation here, this is done simply by tapping on the content. 22486 * 22487 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 22488 * content} 22489 * 22490 * <p>This second code sample shows a typical implementation of a View 22491 * in a video playing application. In this situation, while the video is 22492 * playing the application would like to go into a complete full-screen mode, 22493 * to use as much of the display as possible for the video. When in this state 22494 * the user can not interact with the application; the system intercepts 22495 * touching on the screen to pop the UI out of full screen mode. See 22496 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 22497 * 22498 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 22499 * content} 22500 * 22501 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22502 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 22503 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 22504 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 22505 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 22506 */ 22507 public void setSystemUiVisibility(int visibility) { 22508 if (visibility != mSystemUiVisibility) { 22509 mSystemUiVisibility = visibility; 22510 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 22511 mParent.recomputeViewAttributes(this); 22512 } 22513 } 22514 } 22515 22516 /** 22517 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 22518 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22519 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 22520 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 22521 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 22522 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 22523 */ 22524 public int getSystemUiVisibility() { 22525 return mSystemUiVisibility; 22526 } 22527 22528 /** 22529 * Returns the current system UI visibility that is currently set for 22530 * the entire window. This is the combination of the 22531 * {@link #setSystemUiVisibility(int)} values supplied by all of the 22532 * views in the window. 22533 */ 22534 public int getWindowSystemUiVisibility() { 22535 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 22536 } 22537 22538 /** 22539 * Override to find out when the window's requested system UI visibility 22540 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 22541 * This is different from the callbacks received through 22542 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 22543 * in that this is only telling you about the local request of the window, 22544 * not the actual values applied by the system. 22545 */ 22546 public void onWindowSystemUiVisibilityChanged(int visible) { 22547 } 22548 22549 /** 22550 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 22551 * the view hierarchy. 22552 */ 22553 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 22554 onWindowSystemUiVisibilityChanged(visible); 22555 } 22556 22557 /** 22558 * Set a listener to receive callbacks when the visibility of the system bar changes. 22559 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 22560 */ 22561 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 22562 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 22563 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 22564 mParent.recomputeViewAttributes(this); 22565 } 22566 } 22567 22568 /** 22569 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 22570 * the view hierarchy. 22571 */ 22572 public void dispatchSystemUiVisibilityChanged(int visibility) { 22573 ListenerInfo li = mListenerInfo; 22574 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 22575 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 22576 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 22577 } 22578 } 22579 22580 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 22581 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 22582 if (val != mSystemUiVisibility) { 22583 setSystemUiVisibility(val); 22584 return true; 22585 } 22586 return false; 22587 } 22588 22589 /** @hide */ 22590 public void setDisabledSystemUiVisibility(int flags) { 22591 if (mAttachInfo != null) { 22592 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 22593 mAttachInfo.mDisabledSystemUiVisibility = flags; 22594 if (mParent != null) { 22595 mParent.recomputeViewAttributes(this); 22596 } 22597 } 22598 } 22599 } 22600 22601 /** 22602 * Creates an image that the system displays during the drag and drop 22603 * operation. This is called a "drag shadow". The default implementation 22604 * for a DragShadowBuilder based on a View returns an image that has exactly the same 22605 * appearance as the given View. The default also positions the center of the drag shadow 22606 * directly under the touch point. If no View is provided (the constructor with no parameters 22607 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 22608 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 22609 * default is an invisible drag shadow. 22610 * <p> 22611 * You are not required to use the View you provide to the constructor as the basis of the 22612 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 22613 * anything you want as the drag shadow. 22614 * </p> 22615 * <p> 22616 * You pass a DragShadowBuilder object to the system when you start the drag. The system 22617 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 22618 * size and position of the drag shadow. It uses this data to construct a 22619 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 22620 * so that your application can draw the shadow image in the Canvas. 22621 * </p> 22622 * 22623 * <div class="special reference"> 22624 * <h3>Developer Guides</h3> 22625 * <p>For a guide to implementing drag and drop features, read the 22626 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 22627 * </div> 22628 */ 22629 public static class DragShadowBuilder { 22630 private final WeakReference<View> mView; 22631 22632 /** 22633 * Constructs a shadow image builder based on a View. By default, the resulting drag 22634 * shadow will have the same appearance and dimensions as the View, with the touch point 22635 * over the center of the View. 22636 * @param view A View. Any View in scope can be used. 22637 */ 22638 public DragShadowBuilder(View view) { 22639 mView = new WeakReference<View>(view); 22640 } 22641 22642 /** 22643 * Construct a shadow builder object with no associated View. This 22644 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 22645 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 22646 * to supply the drag shadow's dimensions and appearance without 22647 * reference to any View object. If they are not overridden, then the result is an 22648 * invisible drag shadow. 22649 */ 22650 public DragShadowBuilder() { 22651 mView = new WeakReference<View>(null); 22652 } 22653 22654 /** 22655 * Returns the View object that had been passed to the 22656 * {@link #View.DragShadowBuilder(View)} 22657 * constructor. If that View parameter was {@code null} or if the 22658 * {@link #View.DragShadowBuilder()} 22659 * constructor was used to instantiate the builder object, this method will return 22660 * null. 22661 * 22662 * @return The View object associate with this builder object. 22663 */ 22664 @SuppressWarnings({"JavadocReference"}) 22665 final public View getView() { 22666 return mView.get(); 22667 } 22668 22669 /** 22670 * Provides the metrics for the shadow image. These include the dimensions of 22671 * the shadow image, and the point within that shadow that should 22672 * be centered under the touch location while dragging. 22673 * <p> 22674 * The default implementation sets the dimensions of the shadow to be the 22675 * same as the dimensions of the View itself and centers the shadow under 22676 * the touch point. 22677 * </p> 22678 * 22679 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 22680 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 22681 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 22682 * image. 22683 * 22684 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 22685 * shadow image that should be underneath the touch point during the drag and drop 22686 * operation. Your application must set {@link android.graphics.Point#x} to the 22687 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 22688 */ 22689 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 22690 final View view = mView.get(); 22691 if (view != null) { 22692 outShadowSize.set(view.getWidth(), view.getHeight()); 22693 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 22694 } else { 22695 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 22696 } 22697 } 22698 22699 /** 22700 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 22701 * based on the dimensions it received from the 22702 * {@link #onProvideShadowMetrics(Point, Point)} callback. 22703 * 22704 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 22705 */ 22706 public void onDrawShadow(Canvas canvas) { 22707 final View view = mView.get(); 22708 if (view != null) { 22709 view.draw(canvas); 22710 } else { 22711 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 22712 } 22713 } 22714 } 22715 22716 /** 22717 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 22718 * startDragAndDrop()} for newer platform versions. 22719 */ 22720 @Deprecated 22721 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 22722 Object myLocalState, int flags) { 22723 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 22724 } 22725 22726 /** 22727 * Starts a drag and drop operation. When your application calls this method, it passes a 22728 * {@link android.view.View.DragShadowBuilder} object to the system. The 22729 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 22730 * to get metrics for the drag shadow, and then calls the object's 22731 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 22732 * <p> 22733 * Once the system has the drag shadow, it begins the drag and drop operation by sending 22734 * drag events to all the View objects in your application that are currently visible. It does 22735 * this either by calling the View object's drag listener (an implementation of 22736 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 22737 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 22738 * Both are passed a {@link android.view.DragEvent} object that has a 22739 * {@link android.view.DragEvent#getAction()} value of 22740 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 22741 * </p> 22742 * <p> 22743 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 22744 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 22745 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 22746 * to the View the user selected for dragging. 22747 * </p> 22748 * @param data A {@link android.content.ClipData} object pointing to the data to be 22749 * transferred by the drag and drop operation. 22750 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22751 * drag shadow. 22752 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 22753 * drop operation. When dispatching drag events to views in the same activity this object 22754 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 22755 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 22756 * will return null). 22757 * <p> 22758 * myLocalState is a lightweight mechanism for the sending information from the dragged View 22759 * to the target Views. For example, it can contain flags that differentiate between a 22760 * a copy operation and a move operation. 22761 * </p> 22762 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 22763 * flags, or any combination of the following: 22764 * <ul> 22765 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 22766 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 22767 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 22768 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 22769 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 22770 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 22771 * </ul> 22772 * @return {@code true} if the method completes successfully, or 22773 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 22774 * do a drag, and so no drag operation is in progress. 22775 */ 22776 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 22777 Object myLocalState, int flags) { 22778 if (ViewDebug.DEBUG_DRAG) { 22779 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 22780 } 22781 if (mAttachInfo == null) { 22782 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 22783 return false; 22784 } 22785 22786 if (data != null) { 22787 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 22788 } 22789 22790 boolean okay = false; 22791 22792 Point shadowSize = new Point(); 22793 Point shadowTouchPoint = new Point(); 22794 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 22795 22796 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 22797 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 22798 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 22799 } 22800 22801 if (ViewDebug.DEBUG_DRAG) { 22802 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 22803 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 22804 } 22805 if (mAttachInfo.mDragSurface != null) { 22806 mAttachInfo.mDragSurface.release(); 22807 } 22808 mAttachInfo.mDragSurface = new Surface(); 22809 try { 22810 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 22811 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 22812 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 22813 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 22814 if (mAttachInfo.mDragToken != null) { 22815 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22816 try { 22817 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22818 shadowBuilder.onDrawShadow(canvas); 22819 } finally { 22820 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22821 } 22822 22823 final ViewRootImpl root = getViewRootImpl(); 22824 22825 // Cache the local state object for delivery with DragEvents 22826 root.setLocalDragState(myLocalState); 22827 22828 // repurpose 'shadowSize' for the last touch point 22829 root.getLastTouchPoint(shadowSize); 22830 22831 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 22832 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 22833 shadowTouchPoint.x, shadowTouchPoint.y, data); 22834 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 22835 } 22836 } catch (Exception e) { 22837 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 22838 mAttachInfo.mDragSurface.destroy(); 22839 mAttachInfo.mDragSurface = null; 22840 } 22841 22842 return okay; 22843 } 22844 22845 /** 22846 * Cancels an ongoing drag and drop operation. 22847 * <p> 22848 * A {@link android.view.DragEvent} object with 22849 * {@link android.view.DragEvent#getAction()} value of 22850 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 22851 * {@link android.view.DragEvent#getResult()} value of {@code false} 22852 * will be sent to every 22853 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 22854 * even if they are not currently visible. 22855 * </p> 22856 * <p> 22857 * This method can be called on any View in the same window as the View on which 22858 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 22859 * was called. 22860 * </p> 22861 */ 22862 public final void cancelDragAndDrop() { 22863 if (ViewDebug.DEBUG_DRAG) { 22864 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 22865 } 22866 if (mAttachInfo == null) { 22867 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 22868 return; 22869 } 22870 if (mAttachInfo.mDragToken != null) { 22871 try { 22872 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 22873 } catch (Exception e) { 22874 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 22875 } 22876 mAttachInfo.mDragToken = null; 22877 } else { 22878 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 22879 } 22880 } 22881 22882 /** 22883 * Updates the drag shadow for the ongoing drag and drop operation. 22884 * 22885 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22886 * new drag shadow. 22887 */ 22888 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 22889 if (ViewDebug.DEBUG_DRAG) { 22890 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 22891 } 22892 if (mAttachInfo == null) { 22893 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 22894 return; 22895 } 22896 if (mAttachInfo.mDragToken != null) { 22897 try { 22898 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22899 try { 22900 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22901 shadowBuilder.onDrawShadow(canvas); 22902 } finally { 22903 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22904 } 22905 } catch (Exception e) { 22906 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 22907 } 22908 } else { 22909 Log.e(VIEW_LOG_TAG, "No active drag"); 22910 } 22911 } 22912 22913 /** 22914 * Starts a move from {startX, startY}, the amount of the movement will be the offset 22915 * between {startX, startY} and the new cursor positon. 22916 * @param startX horizontal coordinate where the move started. 22917 * @param startY vertical coordinate where the move started. 22918 * @return whether moving was started successfully. 22919 * @hide 22920 */ 22921 public final boolean startMovingTask(float startX, float startY) { 22922 if (ViewDebug.DEBUG_POSITIONING) { 22923 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 22924 } 22925 try { 22926 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 22927 } catch (RemoteException e) { 22928 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 22929 } 22930 return false; 22931 } 22932 22933 /** 22934 * Handles drag events sent by the system following a call to 22935 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 22936 * startDragAndDrop()}. 22937 *<p> 22938 * When the system calls this method, it passes a 22939 * {@link android.view.DragEvent} object. A call to 22940 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 22941 * in DragEvent. The method uses these to determine what is happening in the drag and drop 22942 * operation. 22943 * @param event The {@link android.view.DragEvent} sent by the system. 22944 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 22945 * in DragEvent, indicating the type of drag event represented by this object. 22946 * @return {@code true} if the method was successful, otherwise {@code false}. 22947 * <p> 22948 * The method should return {@code true} in response to an action type of 22949 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 22950 * operation. 22951 * </p> 22952 * <p> 22953 * The method should also return {@code true} in response to an action type of 22954 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 22955 * {@code false} if it didn't. 22956 * </p> 22957 * <p> 22958 * For all other events, the return value is ignored. 22959 * </p> 22960 */ 22961 public boolean onDragEvent(DragEvent event) { 22962 return false; 22963 } 22964 22965 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 22966 boolean dispatchDragEnterExitInPreN(DragEvent event) { 22967 return callDragEventHandler(event); 22968 } 22969 22970 /** 22971 * Detects if this View is enabled and has a drag event listener. 22972 * If both are true, then it calls the drag event listener with the 22973 * {@link android.view.DragEvent} it received. If the drag event listener returns 22974 * {@code true}, then dispatchDragEvent() returns {@code true}. 22975 * <p> 22976 * For all other cases, the method calls the 22977 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 22978 * method and returns its result. 22979 * </p> 22980 * <p> 22981 * This ensures that a drag event is always consumed, even if the View does not have a drag 22982 * event listener. However, if the View has a listener and the listener returns true, then 22983 * onDragEvent() is not called. 22984 * </p> 22985 */ 22986 public boolean dispatchDragEvent(DragEvent event) { 22987 event.mEventHandlerWasCalled = true; 22988 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 22989 event.mAction == DragEvent.ACTION_DROP) { 22990 // About to deliver an event with coordinates to this view. Notify that now this view 22991 // has drag focus. This will send exit/enter events as needed. 22992 getViewRootImpl().setDragFocus(this, event); 22993 } 22994 return callDragEventHandler(event); 22995 } 22996 22997 final boolean callDragEventHandler(DragEvent event) { 22998 final boolean result; 22999 23000 ListenerInfo li = mListenerInfo; 23001 //noinspection SimplifiableIfStatement 23002 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 23003 && li.mOnDragListener.onDrag(this, event)) { 23004 result = true; 23005 } else { 23006 result = onDragEvent(event); 23007 } 23008 23009 switch (event.mAction) { 23010 case DragEvent.ACTION_DRAG_ENTERED: { 23011 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 23012 refreshDrawableState(); 23013 } break; 23014 case DragEvent.ACTION_DRAG_EXITED: { 23015 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 23016 refreshDrawableState(); 23017 } break; 23018 case DragEvent.ACTION_DRAG_ENDED: { 23019 mPrivateFlags2 &= ~View.DRAG_MASK; 23020 refreshDrawableState(); 23021 } break; 23022 } 23023 23024 return result; 23025 } 23026 23027 boolean canAcceptDrag() { 23028 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 23029 } 23030 23031 /** 23032 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 23033 * it is ever exposed at all. 23034 * @hide 23035 */ 23036 public void onCloseSystemDialogs(String reason) { 23037 } 23038 23039 /** 23040 * Given a Drawable whose bounds have been set to draw into this view, 23041 * update a Region being computed for 23042 * {@link #gatherTransparentRegion(android.graphics.Region)} so 23043 * that any non-transparent parts of the Drawable are removed from the 23044 * given transparent region. 23045 * 23046 * @param dr The Drawable whose transparency is to be applied to the region. 23047 * @param region A Region holding the current transparency information, 23048 * where any parts of the region that are set are considered to be 23049 * transparent. On return, this region will be modified to have the 23050 * transparency information reduced by the corresponding parts of the 23051 * Drawable that are not transparent. 23052 * {@hide} 23053 */ 23054 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 23055 if (DBG) { 23056 Log.i("View", "Getting transparent region for: " + this); 23057 } 23058 final Region r = dr.getTransparentRegion(); 23059 final Rect db = dr.getBounds(); 23060 final AttachInfo attachInfo = mAttachInfo; 23061 if (r != null && attachInfo != null) { 23062 final int w = getRight()-getLeft(); 23063 final int h = getBottom()-getTop(); 23064 if (db.left > 0) { 23065 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 23066 r.op(0, 0, db.left, h, Region.Op.UNION); 23067 } 23068 if (db.right < w) { 23069 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 23070 r.op(db.right, 0, w, h, Region.Op.UNION); 23071 } 23072 if (db.top > 0) { 23073 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 23074 r.op(0, 0, w, db.top, Region.Op.UNION); 23075 } 23076 if (db.bottom < h) { 23077 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 23078 r.op(0, db.bottom, w, h, Region.Op.UNION); 23079 } 23080 final int[] location = attachInfo.mTransparentLocation; 23081 getLocationInWindow(location); 23082 r.translate(location[0], location[1]); 23083 region.op(r, Region.Op.INTERSECT); 23084 } else { 23085 region.op(db, Region.Op.DIFFERENCE); 23086 } 23087 } 23088 23089 private void checkForLongClick(int delayOffset, float x, float y) { 23090 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 23091 mHasPerformedLongPress = false; 23092 23093 if (mPendingCheckForLongPress == null) { 23094 mPendingCheckForLongPress = new CheckForLongPress(); 23095 } 23096 mPendingCheckForLongPress.setAnchor(x, y); 23097 mPendingCheckForLongPress.rememberWindowAttachCount(); 23098 mPendingCheckForLongPress.rememberPressedState(); 23099 postDelayed(mPendingCheckForLongPress, 23100 ViewConfiguration.getLongPressTimeout() - delayOffset); 23101 } 23102 } 23103 23104 /** 23105 * Inflate a view from an XML resource. This convenience method wraps the {@link 23106 * LayoutInflater} class, which provides a full range of options for view inflation. 23107 * 23108 * @param context The Context object for your activity or application. 23109 * @param resource The resource ID to inflate 23110 * @param root A view group that will be the parent. Used to properly inflate the 23111 * layout_* parameters. 23112 * @see LayoutInflater 23113 */ 23114 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 23115 LayoutInflater factory = LayoutInflater.from(context); 23116 return factory.inflate(resource, root); 23117 } 23118 23119 /** 23120 * Scroll the view with standard behavior for scrolling beyond the normal 23121 * content boundaries. Views that call this method should override 23122 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 23123 * results of an over-scroll operation. 23124 * 23125 * Views can use this method to handle any touch or fling-based scrolling. 23126 * 23127 * @param deltaX Change in X in pixels 23128 * @param deltaY Change in Y in pixels 23129 * @param scrollX Current X scroll value in pixels before applying deltaX 23130 * @param scrollY Current Y scroll value in pixels before applying deltaY 23131 * @param scrollRangeX Maximum content scroll range along the X axis 23132 * @param scrollRangeY Maximum content scroll range along the Y axis 23133 * @param maxOverScrollX Number of pixels to overscroll by in either direction 23134 * along the X axis. 23135 * @param maxOverScrollY Number of pixels to overscroll by in either direction 23136 * along the Y axis. 23137 * @param isTouchEvent true if this scroll operation is the result of a touch event. 23138 * @return true if scrolling was clamped to an over-scroll boundary along either 23139 * axis, false otherwise. 23140 */ 23141 @SuppressWarnings({"UnusedParameters"}) 23142 protected boolean overScrollBy(int deltaX, int deltaY, 23143 int scrollX, int scrollY, 23144 int scrollRangeX, int scrollRangeY, 23145 int maxOverScrollX, int maxOverScrollY, 23146 boolean isTouchEvent) { 23147 final int overScrollMode = mOverScrollMode; 23148 final boolean canScrollHorizontal = 23149 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 23150 final boolean canScrollVertical = 23151 computeVerticalScrollRange() > computeVerticalScrollExtent(); 23152 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 23153 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 23154 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 23155 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 23156 23157 int newScrollX = scrollX + deltaX; 23158 if (!overScrollHorizontal) { 23159 maxOverScrollX = 0; 23160 } 23161 23162 int newScrollY = scrollY + deltaY; 23163 if (!overScrollVertical) { 23164 maxOverScrollY = 0; 23165 } 23166 23167 // Clamp values if at the limits and record 23168 final int left = -maxOverScrollX; 23169 final int right = maxOverScrollX + scrollRangeX; 23170 final int top = -maxOverScrollY; 23171 final int bottom = maxOverScrollY + scrollRangeY; 23172 23173 boolean clampedX = false; 23174 if (newScrollX > right) { 23175 newScrollX = right; 23176 clampedX = true; 23177 } else if (newScrollX < left) { 23178 newScrollX = left; 23179 clampedX = true; 23180 } 23181 23182 boolean clampedY = false; 23183 if (newScrollY > bottom) { 23184 newScrollY = bottom; 23185 clampedY = true; 23186 } else if (newScrollY < top) { 23187 newScrollY = top; 23188 clampedY = true; 23189 } 23190 23191 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 23192 23193 return clampedX || clampedY; 23194 } 23195 23196 /** 23197 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 23198 * respond to the results of an over-scroll operation. 23199 * 23200 * @param scrollX New X scroll value in pixels 23201 * @param scrollY New Y scroll value in pixels 23202 * @param clampedX True if scrollX was clamped to an over-scroll boundary 23203 * @param clampedY True if scrollY was clamped to an over-scroll boundary 23204 */ 23205 protected void onOverScrolled(int scrollX, int scrollY, 23206 boolean clampedX, boolean clampedY) { 23207 // Intentionally empty. 23208 } 23209 23210 /** 23211 * Returns the over-scroll mode for this view. The result will be 23212 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 23213 * (allow over-scrolling only if the view content is larger than the container), 23214 * or {@link #OVER_SCROLL_NEVER}. 23215 * 23216 * @return This view's over-scroll mode. 23217 */ 23218 public int getOverScrollMode() { 23219 return mOverScrollMode; 23220 } 23221 23222 /** 23223 * Set the over-scroll mode for this view. Valid over-scroll modes are 23224 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 23225 * (allow over-scrolling only if the view content is larger than the container), 23226 * or {@link #OVER_SCROLL_NEVER}. 23227 * 23228 * Setting the over-scroll mode of a view will have an effect only if the 23229 * view is capable of scrolling. 23230 * 23231 * @param overScrollMode The new over-scroll mode for this view. 23232 */ 23233 public void setOverScrollMode(int overScrollMode) { 23234 if (overScrollMode != OVER_SCROLL_ALWAYS && 23235 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 23236 overScrollMode != OVER_SCROLL_NEVER) { 23237 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 23238 } 23239 mOverScrollMode = overScrollMode; 23240 } 23241 23242 /** 23243 * Enable or disable nested scrolling for this view. 23244 * 23245 * <p>If this property is set to true the view will be permitted to initiate nested 23246 * scrolling operations with a compatible parent view in the current hierarchy. If this 23247 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 23248 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 23249 * the nested scroll.</p> 23250 * 23251 * @param enabled true to enable nested scrolling, false to disable 23252 * 23253 * @see #isNestedScrollingEnabled() 23254 */ 23255 public void setNestedScrollingEnabled(boolean enabled) { 23256 if (enabled) { 23257 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 23258 } else { 23259 stopNestedScroll(); 23260 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 23261 } 23262 } 23263 23264 /** 23265 * Returns true if nested scrolling is enabled for this view. 23266 * 23267 * <p>If nested scrolling is enabled and this View class implementation supports it, 23268 * this view will act as a nested scrolling child view when applicable, forwarding data 23269 * about the scroll operation in progress to a compatible and cooperating nested scrolling 23270 * parent.</p> 23271 * 23272 * @return true if nested scrolling is enabled 23273 * 23274 * @see #setNestedScrollingEnabled(boolean) 23275 */ 23276 public boolean isNestedScrollingEnabled() { 23277 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 23278 PFLAG3_NESTED_SCROLLING_ENABLED; 23279 } 23280 23281 /** 23282 * Begin a nestable scroll operation along the given axes. 23283 * 23284 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 23285 * 23286 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 23287 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 23288 * In the case of touch scrolling the nested scroll will be terminated automatically in 23289 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 23290 * In the event of programmatic scrolling the caller must explicitly call 23291 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 23292 * 23293 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 23294 * If it returns false the caller may ignore the rest of this contract until the next scroll. 23295 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 23296 * 23297 * <p>At each incremental step of the scroll the caller should invoke 23298 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 23299 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 23300 * parent at least partially consumed the scroll and the caller should adjust the amount it 23301 * scrolls by.</p> 23302 * 23303 * <p>After applying the remainder of the scroll delta the caller should invoke 23304 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 23305 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 23306 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 23307 * </p> 23308 * 23309 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 23310 * {@link #SCROLL_AXIS_VERTICAL}. 23311 * @return true if a cooperative parent was found and nested scrolling has been enabled for 23312 * the current gesture. 23313 * 23314 * @see #stopNestedScroll() 23315 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 23316 * @see #dispatchNestedScroll(int, int, int, int, int[]) 23317 */ 23318 public boolean startNestedScroll(int axes) { 23319 if (hasNestedScrollingParent()) { 23320 // Already in progress 23321 return true; 23322 } 23323 if (isNestedScrollingEnabled()) { 23324 ViewParent p = getParent(); 23325 View child = this; 23326 while (p != null) { 23327 try { 23328 if (p.onStartNestedScroll(child, this, axes)) { 23329 mNestedScrollingParent = p; 23330 p.onNestedScrollAccepted(child, this, axes); 23331 return true; 23332 } 23333 } catch (AbstractMethodError e) { 23334 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 23335 "method onStartNestedScroll", e); 23336 // Allow the search upward to continue 23337 } 23338 if (p instanceof View) { 23339 child = (View) p; 23340 } 23341 p = p.getParent(); 23342 } 23343 } 23344 return false; 23345 } 23346 23347 /** 23348 * Stop a nested scroll in progress. 23349 * 23350 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 23351 * 23352 * @see #startNestedScroll(int) 23353 */ 23354 public void stopNestedScroll() { 23355 if (mNestedScrollingParent != null) { 23356 mNestedScrollingParent.onStopNestedScroll(this); 23357 mNestedScrollingParent = null; 23358 } 23359 } 23360 23361 /** 23362 * Returns true if this view has a nested scrolling parent. 23363 * 23364 * <p>The presence of a nested scrolling parent indicates that this view has initiated 23365 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 23366 * 23367 * @return whether this view has a nested scrolling parent 23368 */ 23369 public boolean hasNestedScrollingParent() { 23370 return mNestedScrollingParent != null; 23371 } 23372 23373 /** 23374 * Dispatch one step of a nested scroll in progress. 23375 * 23376 * <p>Implementations of views that support nested scrolling should call this to report 23377 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 23378 * is not currently in progress or nested scrolling is not 23379 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 23380 * 23381 * <p>Compatible View implementations should also call 23382 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 23383 * consuming a component of the scroll event themselves.</p> 23384 * 23385 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 23386 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 23387 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 23388 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 23389 * @param offsetInWindow Optional. If not null, on return this will contain the offset 23390 * in local view coordinates of this view from before this operation 23391 * to after it completes. View implementations may use this to adjust 23392 * expected input coordinate tracking. 23393 * @return true if the event was dispatched, false if it could not be dispatched. 23394 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 23395 */ 23396 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 23397 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 23398 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23399 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 23400 int startX = 0; 23401 int startY = 0; 23402 if (offsetInWindow != null) { 23403 getLocationInWindow(offsetInWindow); 23404 startX = offsetInWindow[0]; 23405 startY = offsetInWindow[1]; 23406 } 23407 23408 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 23409 dxUnconsumed, dyUnconsumed); 23410 23411 if (offsetInWindow != null) { 23412 getLocationInWindow(offsetInWindow); 23413 offsetInWindow[0] -= startX; 23414 offsetInWindow[1] -= startY; 23415 } 23416 return true; 23417 } else if (offsetInWindow != null) { 23418 // No motion, no dispatch. Keep offsetInWindow up to date. 23419 offsetInWindow[0] = 0; 23420 offsetInWindow[1] = 0; 23421 } 23422 } 23423 return false; 23424 } 23425 23426 /** 23427 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 23428 * 23429 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 23430 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 23431 * scrolling operation to consume some or all of the scroll operation before the child view 23432 * consumes it.</p> 23433 * 23434 * @param dx Horizontal scroll distance in pixels 23435 * @param dy Vertical scroll distance in pixels 23436 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 23437 * and consumed[1] the consumed dy. 23438 * @param offsetInWindow Optional. If not null, on return this will contain the offset 23439 * in local view coordinates of this view from before this operation 23440 * to after it completes. View implementations may use this to adjust 23441 * expected input coordinate tracking. 23442 * @return true if the parent consumed some or all of the scroll delta 23443 * @see #dispatchNestedScroll(int, int, int, int, int[]) 23444 */ 23445 public boolean dispatchNestedPreScroll(int dx, int dy, 23446 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 23447 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23448 if (dx != 0 || dy != 0) { 23449 int startX = 0; 23450 int startY = 0; 23451 if (offsetInWindow != null) { 23452 getLocationInWindow(offsetInWindow); 23453 startX = offsetInWindow[0]; 23454 startY = offsetInWindow[1]; 23455 } 23456 23457 if (consumed == null) { 23458 if (mTempNestedScrollConsumed == null) { 23459 mTempNestedScrollConsumed = new int[2]; 23460 } 23461 consumed = mTempNestedScrollConsumed; 23462 } 23463 consumed[0] = 0; 23464 consumed[1] = 0; 23465 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 23466 23467 if (offsetInWindow != null) { 23468 getLocationInWindow(offsetInWindow); 23469 offsetInWindow[0] -= startX; 23470 offsetInWindow[1] -= startY; 23471 } 23472 return consumed[0] != 0 || consumed[1] != 0; 23473 } else if (offsetInWindow != null) { 23474 offsetInWindow[0] = 0; 23475 offsetInWindow[1] = 0; 23476 } 23477 } 23478 return false; 23479 } 23480 23481 /** 23482 * Dispatch a fling to a nested scrolling parent. 23483 * 23484 * <p>This method should be used to indicate that a nested scrolling child has detected 23485 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 23486 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 23487 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 23488 * along a scrollable axis.</p> 23489 * 23490 * <p>If a nested scrolling child view would normally fling but it is at the edge of 23491 * its own content, it can use this method to delegate the fling to its nested scrolling 23492 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 23493 * 23494 * @param velocityX Horizontal fling velocity in pixels per second 23495 * @param velocityY Vertical fling velocity in pixels per second 23496 * @param consumed true if the child consumed the fling, false otherwise 23497 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 23498 */ 23499 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 23500 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23501 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 23502 } 23503 return false; 23504 } 23505 23506 /** 23507 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 23508 * 23509 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 23510 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 23511 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 23512 * before the child view consumes it. If this method returns <code>true</code>, a nested 23513 * parent view consumed the fling and this view should not scroll as a result.</p> 23514 * 23515 * <p>For a better user experience, only one view in a nested scrolling chain should consume 23516 * the fling at a time. If a parent view consumed the fling this method will return false. 23517 * Custom view implementations should account for this in two ways:</p> 23518 * 23519 * <ul> 23520 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 23521 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 23522 * position regardless.</li> 23523 * <li>If a nested parent does consume the fling, this view should not scroll at all, 23524 * even to settle back to a valid idle position.</li> 23525 * </ul> 23526 * 23527 * <p>Views should also not offer fling velocities to nested parent views along an axis 23528 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 23529 * should not offer a horizontal fling velocity to its parents since scrolling along that 23530 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 23531 * 23532 * @param velocityX Horizontal fling velocity in pixels per second 23533 * @param velocityY Vertical fling velocity in pixels per second 23534 * @return true if a nested scrolling parent consumed the fling 23535 */ 23536 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 23537 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23538 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 23539 } 23540 return false; 23541 } 23542 23543 /** 23544 * Gets a scale factor that determines the distance the view should scroll 23545 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 23546 * @return The vertical scroll scale factor. 23547 * @hide 23548 */ 23549 protected float getVerticalScrollFactor() { 23550 if (mVerticalScrollFactor == 0) { 23551 TypedValue outValue = new TypedValue(); 23552 if (!mContext.getTheme().resolveAttribute( 23553 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 23554 throw new IllegalStateException( 23555 "Expected theme to define listPreferredItemHeight."); 23556 } 23557 mVerticalScrollFactor = outValue.getDimension( 23558 mContext.getResources().getDisplayMetrics()); 23559 } 23560 return mVerticalScrollFactor; 23561 } 23562 23563 /** 23564 * Gets a scale factor that determines the distance the view should scroll 23565 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 23566 * @return The horizontal scroll scale factor. 23567 * @hide 23568 */ 23569 protected float getHorizontalScrollFactor() { 23570 // TODO: Should use something else. 23571 return getVerticalScrollFactor(); 23572 } 23573 23574 /** 23575 * Return the value specifying the text direction or policy that was set with 23576 * {@link #setTextDirection(int)}. 23577 * 23578 * @return the defined text direction. It can be one of: 23579 * 23580 * {@link #TEXT_DIRECTION_INHERIT}, 23581 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23582 * {@link #TEXT_DIRECTION_ANY_RTL}, 23583 * {@link #TEXT_DIRECTION_LTR}, 23584 * {@link #TEXT_DIRECTION_RTL}, 23585 * {@link #TEXT_DIRECTION_LOCALE}, 23586 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23587 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 23588 * 23589 * @attr ref android.R.styleable#View_textDirection 23590 * 23591 * @hide 23592 */ 23593 @ViewDebug.ExportedProperty(category = "text", mapping = { 23594 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 23595 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 23596 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 23597 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 23598 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 23599 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 23600 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 23601 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 23602 }) 23603 public int getRawTextDirection() { 23604 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 23605 } 23606 23607 /** 23608 * Set the text direction. 23609 * 23610 * @param textDirection the direction to set. Should be one of: 23611 * 23612 * {@link #TEXT_DIRECTION_INHERIT}, 23613 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23614 * {@link #TEXT_DIRECTION_ANY_RTL}, 23615 * {@link #TEXT_DIRECTION_LTR}, 23616 * {@link #TEXT_DIRECTION_RTL}, 23617 * {@link #TEXT_DIRECTION_LOCALE} 23618 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23619 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 23620 * 23621 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 23622 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 23623 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 23624 * 23625 * @attr ref android.R.styleable#View_textDirection 23626 */ 23627 public void setTextDirection(int textDirection) { 23628 if (getRawTextDirection() != textDirection) { 23629 // Reset the current text direction and the resolved one 23630 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 23631 resetResolvedTextDirection(); 23632 // Set the new text direction 23633 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 23634 // Do resolution 23635 resolveTextDirection(); 23636 // Notify change 23637 onRtlPropertiesChanged(getLayoutDirection()); 23638 // Refresh 23639 requestLayout(); 23640 invalidate(true); 23641 } 23642 } 23643 23644 /** 23645 * Return the resolved text direction. 23646 * 23647 * @return the resolved text direction. Returns one of: 23648 * 23649 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23650 * {@link #TEXT_DIRECTION_ANY_RTL}, 23651 * {@link #TEXT_DIRECTION_LTR}, 23652 * {@link #TEXT_DIRECTION_RTL}, 23653 * {@link #TEXT_DIRECTION_LOCALE}, 23654 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23655 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 23656 * 23657 * @attr ref android.R.styleable#View_textDirection 23658 */ 23659 @ViewDebug.ExportedProperty(category = "text", mapping = { 23660 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 23661 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 23662 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 23663 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 23664 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 23665 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 23666 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 23667 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 23668 }) 23669 public int getTextDirection() { 23670 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 23671 } 23672 23673 /** 23674 * Resolve the text direction. 23675 * 23676 * @return true if resolution has been done, false otherwise. 23677 * 23678 * @hide 23679 */ 23680 public boolean resolveTextDirection() { 23681 // Reset any previous text direction resolution 23682 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23683 23684 if (hasRtlSupport()) { 23685 // Set resolved text direction flag depending on text direction flag 23686 final int textDirection = getRawTextDirection(); 23687 switch(textDirection) { 23688 case TEXT_DIRECTION_INHERIT: 23689 if (!canResolveTextDirection()) { 23690 // We cannot do the resolution if there is no parent, so use the default one 23691 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23692 // Resolution will need to happen again later 23693 return false; 23694 } 23695 23696 // Parent has not yet resolved, so we still return the default 23697 try { 23698 if (!mParent.isTextDirectionResolved()) { 23699 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23700 // Resolution will need to happen again later 23701 return false; 23702 } 23703 } catch (AbstractMethodError e) { 23704 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23705 " does not fully implement ViewParent", e); 23706 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 23707 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23708 return true; 23709 } 23710 23711 // Set current resolved direction to the same value as the parent's one 23712 int parentResolvedDirection; 23713 try { 23714 parentResolvedDirection = mParent.getTextDirection(); 23715 } catch (AbstractMethodError e) { 23716 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23717 " does not fully implement ViewParent", e); 23718 parentResolvedDirection = TEXT_DIRECTION_LTR; 23719 } 23720 switch (parentResolvedDirection) { 23721 case TEXT_DIRECTION_FIRST_STRONG: 23722 case TEXT_DIRECTION_ANY_RTL: 23723 case TEXT_DIRECTION_LTR: 23724 case TEXT_DIRECTION_RTL: 23725 case TEXT_DIRECTION_LOCALE: 23726 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23727 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23728 mPrivateFlags2 |= 23729 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23730 break; 23731 default: 23732 // Default resolved direction is "first strong" heuristic 23733 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23734 } 23735 break; 23736 case TEXT_DIRECTION_FIRST_STRONG: 23737 case TEXT_DIRECTION_ANY_RTL: 23738 case TEXT_DIRECTION_LTR: 23739 case TEXT_DIRECTION_RTL: 23740 case TEXT_DIRECTION_LOCALE: 23741 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23742 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23743 // Resolved direction is the same as text direction 23744 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23745 break; 23746 default: 23747 // Default resolved direction is "first strong" heuristic 23748 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23749 } 23750 } else { 23751 // Default resolved direction is "first strong" heuristic 23752 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23753 } 23754 23755 // Set to resolved 23756 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 23757 return true; 23758 } 23759 23760 /** 23761 * Check if text direction resolution can be done. 23762 * 23763 * @return true if text direction resolution can be done otherwise return false. 23764 */ 23765 public boolean canResolveTextDirection() { 23766 switch (getRawTextDirection()) { 23767 case TEXT_DIRECTION_INHERIT: 23768 if (mParent != null) { 23769 try { 23770 return mParent.canResolveTextDirection(); 23771 } catch (AbstractMethodError e) { 23772 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23773 " does not fully implement ViewParent", e); 23774 } 23775 } 23776 return false; 23777 23778 default: 23779 return true; 23780 } 23781 } 23782 23783 /** 23784 * Reset resolved text direction. Text direction will be resolved during a call to 23785 * {@link #onMeasure(int, int)}. 23786 * 23787 * @hide 23788 */ 23789 public void resetResolvedTextDirection() { 23790 // Reset any previous text direction resolution 23791 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23792 // Set to default value 23793 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23794 } 23795 23796 /** 23797 * @return true if text direction is inherited. 23798 * 23799 * @hide 23800 */ 23801 public boolean isTextDirectionInherited() { 23802 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 23803 } 23804 23805 /** 23806 * @return true if text direction is resolved. 23807 */ 23808 public boolean isTextDirectionResolved() { 23809 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 23810 } 23811 23812 /** 23813 * Return the value specifying the text alignment or policy that was set with 23814 * {@link #setTextAlignment(int)}. 23815 * 23816 * @return the defined text alignment. It can be one of: 23817 * 23818 * {@link #TEXT_ALIGNMENT_INHERIT}, 23819 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23820 * {@link #TEXT_ALIGNMENT_CENTER}, 23821 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23822 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23823 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23824 * {@link #TEXT_ALIGNMENT_VIEW_END} 23825 * 23826 * @attr ref android.R.styleable#View_textAlignment 23827 * 23828 * @hide 23829 */ 23830 @ViewDebug.ExportedProperty(category = "text", mapping = { 23831 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23832 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23833 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23834 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23835 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23836 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23837 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23838 }) 23839 @TextAlignment 23840 public int getRawTextAlignment() { 23841 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 23842 } 23843 23844 /** 23845 * Set the text alignment. 23846 * 23847 * @param textAlignment The text alignment to set. Should be one of 23848 * 23849 * {@link #TEXT_ALIGNMENT_INHERIT}, 23850 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23851 * {@link #TEXT_ALIGNMENT_CENTER}, 23852 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23853 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23854 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23855 * {@link #TEXT_ALIGNMENT_VIEW_END} 23856 * 23857 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 23858 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 23859 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 23860 * 23861 * @attr ref android.R.styleable#View_textAlignment 23862 */ 23863 public void setTextAlignment(@TextAlignment int textAlignment) { 23864 if (textAlignment != getRawTextAlignment()) { 23865 // Reset the current and resolved text alignment 23866 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 23867 resetResolvedTextAlignment(); 23868 // Set the new text alignment 23869 mPrivateFlags2 |= 23870 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 23871 // Do resolution 23872 resolveTextAlignment(); 23873 // Notify change 23874 onRtlPropertiesChanged(getLayoutDirection()); 23875 // Refresh 23876 requestLayout(); 23877 invalidate(true); 23878 } 23879 } 23880 23881 /** 23882 * Return the resolved text alignment. 23883 * 23884 * @return the resolved text alignment. Returns one of: 23885 * 23886 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23887 * {@link #TEXT_ALIGNMENT_CENTER}, 23888 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23889 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23890 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23891 * {@link #TEXT_ALIGNMENT_VIEW_END} 23892 * 23893 * @attr ref android.R.styleable#View_textAlignment 23894 */ 23895 @ViewDebug.ExportedProperty(category = "text", mapping = { 23896 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23897 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23898 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23899 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23900 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23901 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23902 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23903 }) 23904 @TextAlignment 23905 public int getTextAlignment() { 23906 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 23907 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 23908 } 23909 23910 /** 23911 * Resolve the text alignment. 23912 * 23913 * @return true if resolution has been done, false otherwise. 23914 * 23915 * @hide 23916 */ 23917 public boolean resolveTextAlignment() { 23918 // Reset any previous text alignment resolution 23919 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 23920 23921 if (hasRtlSupport()) { 23922 // Set resolved text alignment flag depending on text alignment flag 23923 final int textAlignment = getRawTextAlignment(); 23924 switch (textAlignment) { 23925 case TEXT_ALIGNMENT_INHERIT: 23926 // Check if we can resolve the text alignment 23927 if (!canResolveTextAlignment()) { 23928 // We cannot do the resolution if there is no parent so use the default 23929 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23930 // Resolution will need to happen again later 23931 return false; 23932 } 23933 23934 // Parent has not yet resolved, so we still return the default 23935 try { 23936 if (!mParent.isTextAlignmentResolved()) { 23937 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23938 // Resolution will need to happen again later 23939 return false; 23940 } 23941 } catch (AbstractMethodError e) { 23942 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23943 " does not fully implement ViewParent", e); 23944 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 23945 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23946 return true; 23947 } 23948 23949 int parentResolvedTextAlignment; 23950 try { 23951 parentResolvedTextAlignment = mParent.getTextAlignment(); 23952 } catch (AbstractMethodError e) { 23953 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23954 " does not fully implement ViewParent", e); 23955 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 23956 } 23957 switch (parentResolvedTextAlignment) { 23958 case TEXT_ALIGNMENT_GRAVITY: 23959 case TEXT_ALIGNMENT_TEXT_START: 23960 case TEXT_ALIGNMENT_TEXT_END: 23961 case TEXT_ALIGNMENT_CENTER: 23962 case TEXT_ALIGNMENT_VIEW_START: 23963 case TEXT_ALIGNMENT_VIEW_END: 23964 // Resolved text alignment is the same as the parent resolved 23965 // text alignment 23966 mPrivateFlags2 |= 23967 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 23968 break; 23969 default: 23970 // Use default resolved text alignment 23971 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23972 } 23973 break; 23974 case TEXT_ALIGNMENT_GRAVITY: 23975 case TEXT_ALIGNMENT_TEXT_START: 23976 case TEXT_ALIGNMENT_TEXT_END: 23977 case TEXT_ALIGNMENT_CENTER: 23978 case TEXT_ALIGNMENT_VIEW_START: 23979 case TEXT_ALIGNMENT_VIEW_END: 23980 // Resolved text alignment is the same as text alignment 23981 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 23982 break; 23983 default: 23984 // Use default resolved text alignment 23985 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23986 } 23987 } else { 23988 // Use default resolved text alignment 23989 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23990 } 23991 23992 // Set the resolved 23993 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 23994 return true; 23995 } 23996 23997 /** 23998 * Check if text alignment resolution can be done. 23999 * 24000 * @return true if text alignment resolution can be done otherwise return false. 24001 */ 24002 public boolean canResolveTextAlignment() { 24003 switch (getRawTextAlignment()) { 24004 case TEXT_DIRECTION_INHERIT: 24005 if (mParent != null) { 24006 try { 24007 return mParent.canResolveTextAlignment(); 24008 } catch (AbstractMethodError e) { 24009 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24010 " does not fully implement ViewParent", e); 24011 } 24012 } 24013 return false; 24014 24015 default: 24016 return true; 24017 } 24018 } 24019 24020 /** 24021 * Reset resolved text alignment. Text alignment will be resolved during a call to 24022 * {@link #onMeasure(int, int)}. 24023 * 24024 * @hide 24025 */ 24026 public void resetResolvedTextAlignment() { 24027 // Reset any previous text alignment resolution 24028 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 24029 // Set to default 24030 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24031 } 24032 24033 /** 24034 * @return true if text alignment is inherited. 24035 * 24036 * @hide 24037 */ 24038 public boolean isTextAlignmentInherited() { 24039 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 24040 } 24041 24042 /** 24043 * @return true if text alignment is resolved. 24044 */ 24045 public boolean isTextAlignmentResolved() { 24046 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 24047 } 24048 24049 /** 24050 * Generate a value suitable for use in {@link #setId(int)}. 24051 * This value will not collide with ID values generated at build time by aapt for R.id. 24052 * 24053 * @return a generated ID value 24054 */ 24055 public static int generateViewId() { 24056 for (;;) { 24057 final int result = sNextGeneratedId.get(); 24058 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 24059 int newValue = result + 1; 24060 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 24061 if (sNextGeneratedId.compareAndSet(result, newValue)) { 24062 return result; 24063 } 24064 } 24065 } 24066 24067 private static boolean isViewIdGenerated(int id) { 24068 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 24069 } 24070 24071 /** 24072 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 24073 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 24074 * a normal View or a ViewGroup with 24075 * {@link android.view.ViewGroup#isTransitionGroup()} true. 24076 * @hide 24077 */ 24078 public void captureTransitioningViews(List<View> transitioningViews) { 24079 if (getVisibility() == View.VISIBLE) { 24080 transitioningViews.add(this); 24081 } 24082 } 24083 24084 /** 24085 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 24086 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 24087 * @hide 24088 */ 24089 public void findNamedViews(Map<String, View> namedElements) { 24090 if (getVisibility() == VISIBLE || mGhostView != null) { 24091 String transitionName = getTransitionName(); 24092 if (transitionName != null) { 24093 namedElements.put(transitionName, this); 24094 } 24095 } 24096 } 24097 24098 /** 24099 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 24100 * The default implementation does not care the location or event types, but some subclasses 24101 * may use it (such as WebViews). 24102 * @param event The MotionEvent from a mouse 24103 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 24104 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 24105 * @see PointerIcon 24106 */ 24107 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 24108 final float x = event.getX(pointerIndex); 24109 final float y = event.getY(pointerIndex); 24110 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 24111 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 24112 } 24113 return mPointerIcon; 24114 } 24115 24116 /** 24117 * Set the pointer icon for the current view. 24118 * Passing {@code null} will restore the pointer icon to its default value. 24119 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 24120 */ 24121 public void setPointerIcon(PointerIcon pointerIcon) { 24122 mPointerIcon = pointerIcon; 24123 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 24124 return; 24125 } 24126 try { 24127 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 24128 } catch (RemoteException e) { 24129 } 24130 } 24131 24132 /** 24133 * Gets the pointer icon for the current view. 24134 */ 24135 public PointerIcon getPointerIcon() { 24136 return mPointerIcon; 24137 } 24138 24139 /** 24140 * Checks pointer capture status. 24141 * 24142 * @return true if the view has pointer capture. 24143 * @see #requestPointerCapture() 24144 * @see #hasPointerCapture() 24145 */ 24146 public boolean hasPointerCapture() { 24147 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24148 if (viewRootImpl == null) { 24149 return false; 24150 } 24151 return viewRootImpl.hasPointerCapture(); 24152 } 24153 24154 /** 24155 * Requests pointer capture mode. 24156 * <p> 24157 * When the window has pointer capture, the mouse pointer icon will disappear and will not 24158 * change its position. Further mouse will be dispatched with the source 24159 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 24160 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 24161 * (touchscreens, or stylus) will not be affected. 24162 * <p> 24163 * If the window already has pointer capture, this call does nothing. 24164 * <p> 24165 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 24166 * automatically when the window loses focus. 24167 * 24168 * @see #releasePointerCapture() 24169 * @see #hasPointerCapture() 24170 */ 24171 public void requestPointerCapture() { 24172 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24173 if (viewRootImpl != null) { 24174 viewRootImpl.requestPointerCapture(true); 24175 } 24176 } 24177 24178 24179 /** 24180 * Releases the pointer capture. 24181 * <p> 24182 * If the window does not have pointer capture, this call will do nothing. 24183 * @see #requestPointerCapture() 24184 * @see #hasPointerCapture() 24185 */ 24186 public void releasePointerCapture() { 24187 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24188 if (viewRootImpl != null) { 24189 viewRootImpl.requestPointerCapture(false); 24190 } 24191 } 24192 24193 /** 24194 * Called when the window has just acquired or lost pointer capture. 24195 * 24196 * @param hasCapture True if the view now has pointerCapture, false otherwise. 24197 */ 24198 @CallSuper 24199 public void onPointerCaptureChange(boolean hasCapture) { 24200 } 24201 24202 /** 24203 * @see #onPointerCaptureChange 24204 */ 24205 public void dispatchPointerCaptureChanged(boolean hasCapture) { 24206 onPointerCaptureChange(hasCapture); 24207 } 24208 24209 /** 24210 * Implement this method to handle captured pointer events 24211 * 24212 * @param event The captured pointer event. 24213 * @return True if the event was handled, false otherwise. 24214 * @see #requestPointerCapture() 24215 */ 24216 public boolean onCapturedPointerEvent(MotionEvent event) { 24217 return false; 24218 } 24219 24220 /** 24221 * Interface definition for a callback to be invoked when a captured pointer event 24222 * is being dispatched this view. The callback will be invoked before the event is 24223 * given to the view. 24224 */ 24225 public interface OnCapturedPointerListener { 24226 /** 24227 * Called when a captured pointer event is dispatched to a view. 24228 * @param view The view this event has been dispatched to. 24229 * @param event The captured event. 24230 * @return True if the listener has consumed the event, false otherwise. 24231 */ 24232 boolean onCapturedPointer(View view, MotionEvent event); 24233 } 24234 24235 /** 24236 * Set a listener to receive callbacks when the pointer capture state of a view changes. 24237 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 24238 */ 24239 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 24240 getListenerInfo().mOnCapturedPointerListener = l; 24241 } 24242 24243 // Properties 24244 // 24245 /** 24246 * A Property wrapper around the <code>alpha</code> functionality handled by the 24247 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 24248 */ 24249 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 24250 @Override 24251 public void setValue(View object, float value) { 24252 object.setAlpha(value); 24253 } 24254 24255 @Override 24256 public Float get(View object) { 24257 return object.getAlpha(); 24258 } 24259 }; 24260 24261 /** 24262 * A Property wrapper around the <code>translationX</code> functionality handled by the 24263 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 24264 */ 24265 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 24266 @Override 24267 public void setValue(View object, float value) { 24268 object.setTranslationX(value); 24269 } 24270 24271 @Override 24272 public Float get(View object) { 24273 return object.getTranslationX(); 24274 } 24275 }; 24276 24277 /** 24278 * A Property wrapper around the <code>translationY</code> functionality handled by the 24279 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 24280 */ 24281 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 24282 @Override 24283 public void setValue(View object, float value) { 24284 object.setTranslationY(value); 24285 } 24286 24287 @Override 24288 public Float get(View object) { 24289 return object.getTranslationY(); 24290 } 24291 }; 24292 24293 /** 24294 * A Property wrapper around the <code>translationZ</code> functionality handled by the 24295 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 24296 */ 24297 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 24298 @Override 24299 public void setValue(View object, float value) { 24300 object.setTranslationZ(value); 24301 } 24302 24303 @Override 24304 public Float get(View object) { 24305 return object.getTranslationZ(); 24306 } 24307 }; 24308 24309 /** 24310 * A Property wrapper around the <code>x</code> functionality handled by the 24311 * {@link View#setX(float)} and {@link View#getX()} methods. 24312 */ 24313 public static final Property<View, Float> X = new FloatProperty<View>("x") { 24314 @Override 24315 public void setValue(View object, float value) { 24316 object.setX(value); 24317 } 24318 24319 @Override 24320 public Float get(View object) { 24321 return object.getX(); 24322 } 24323 }; 24324 24325 /** 24326 * A Property wrapper around the <code>y</code> functionality handled by the 24327 * {@link View#setY(float)} and {@link View#getY()} methods. 24328 */ 24329 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 24330 @Override 24331 public void setValue(View object, float value) { 24332 object.setY(value); 24333 } 24334 24335 @Override 24336 public Float get(View object) { 24337 return object.getY(); 24338 } 24339 }; 24340 24341 /** 24342 * A Property wrapper around the <code>z</code> functionality handled by the 24343 * {@link View#setZ(float)} and {@link View#getZ()} methods. 24344 */ 24345 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 24346 @Override 24347 public void setValue(View object, float value) { 24348 object.setZ(value); 24349 } 24350 24351 @Override 24352 public Float get(View object) { 24353 return object.getZ(); 24354 } 24355 }; 24356 24357 /** 24358 * A Property wrapper around the <code>rotation</code> functionality handled by the 24359 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 24360 */ 24361 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 24362 @Override 24363 public void setValue(View object, float value) { 24364 object.setRotation(value); 24365 } 24366 24367 @Override 24368 public Float get(View object) { 24369 return object.getRotation(); 24370 } 24371 }; 24372 24373 /** 24374 * A Property wrapper around the <code>rotationX</code> functionality handled by the 24375 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 24376 */ 24377 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 24378 @Override 24379 public void setValue(View object, float value) { 24380 object.setRotationX(value); 24381 } 24382 24383 @Override 24384 public Float get(View object) { 24385 return object.getRotationX(); 24386 } 24387 }; 24388 24389 /** 24390 * A Property wrapper around the <code>rotationY</code> functionality handled by the 24391 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 24392 */ 24393 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 24394 @Override 24395 public void setValue(View object, float value) { 24396 object.setRotationY(value); 24397 } 24398 24399 @Override 24400 public Float get(View object) { 24401 return object.getRotationY(); 24402 } 24403 }; 24404 24405 /** 24406 * A Property wrapper around the <code>scaleX</code> functionality handled by the 24407 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 24408 */ 24409 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 24410 @Override 24411 public void setValue(View object, float value) { 24412 object.setScaleX(value); 24413 } 24414 24415 @Override 24416 public Float get(View object) { 24417 return object.getScaleX(); 24418 } 24419 }; 24420 24421 /** 24422 * A Property wrapper around the <code>scaleY</code> functionality handled by the 24423 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 24424 */ 24425 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 24426 @Override 24427 public void setValue(View object, float value) { 24428 object.setScaleY(value); 24429 } 24430 24431 @Override 24432 public Float get(View object) { 24433 return object.getScaleY(); 24434 } 24435 }; 24436 24437 /** 24438 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 24439 * Each MeasureSpec represents a requirement for either the width or the height. 24440 * A MeasureSpec is comprised of a size and a mode. There are three possible 24441 * modes: 24442 * <dl> 24443 * <dt>UNSPECIFIED</dt> 24444 * <dd> 24445 * The parent has not imposed any constraint on the child. It can be whatever size 24446 * it wants. 24447 * </dd> 24448 * 24449 * <dt>EXACTLY</dt> 24450 * <dd> 24451 * The parent has determined an exact size for the child. The child is going to be 24452 * given those bounds regardless of how big it wants to be. 24453 * </dd> 24454 * 24455 * <dt>AT_MOST</dt> 24456 * <dd> 24457 * The child can be as large as it wants up to the specified size. 24458 * </dd> 24459 * </dl> 24460 * 24461 * MeasureSpecs are implemented as ints to reduce object allocation. This class 24462 * is provided to pack and unpack the <size, mode> tuple into the int. 24463 */ 24464 public static class MeasureSpec { 24465 private static final int MODE_SHIFT = 30; 24466 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 24467 24468 /** @hide */ 24469 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 24470 @Retention(RetentionPolicy.SOURCE) 24471 public @interface MeasureSpecMode {} 24472 24473 /** 24474 * Measure specification mode: The parent has not imposed any constraint 24475 * on the child. It can be whatever size it wants. 24476 */ 24477 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 24478 24479 /** 24480 * Measure specification mode: The parent has determined an exact size 24481 * for the child. The child is going to be given those bounds regardless 24482 * of how big it wants to be. 24483 */ 24484 public static final int EXACTLY = 1 << MODE_SHIFT; 24485 24486 /** 24487 * Measure specification mode: The child can be as large as it wants up 24488 * to the specified size. 24489 */ 24490 public static final int AT_MOST = 2 << MODE_SHIFT; 24491 24492 /** 24493 * Creates a measure specification based on the supplied size and mode. 24494 * 24495 * The mode must always be one of the following: 24496 * <ul> 24497 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 24498 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 24499 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 24500 * </ul> 24501 * 24502 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 24503 * implementation was such that the order of arguments did not matter 24504 * and overflow in either value could impact the resulting MeasureSpec. 24505 * {@link android.widget.RelativeLayout} was affected by this bug. 24506 * Apps targeting API levels greater than 17 will get the fixed, more strict 24507 * behavior.</p> 24508 * 24509 * @param size the size of the measure specification 24510 * @param mode the mode of the measure specification 24511 * @return the measure specification based on size and mode 24512 */ 24513 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 24514 @MeasureSpecMode int mode) { 24515 if (sUseBrokenMakeMeasureSpec) { 24516 return size + mode; 24517 } else { 24518 return (size & ~MODE_MASK) | (mode & MODE_MASK); 24519 } 24520 } 24521 24522 /** 24523 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 24524 * will automatically get a size of 0. Older apps expect this. 24525 * 24526 * @hide internal use only for compatibility with system widgets and older apps 24527 */ 24528 public static int makeSafeMeasureSpec(int size, int mode) { 24529 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 24530 return 0; 24531 } 24532 return makeMeasureSpec(size, mode); 24533 } 24534 24535 /** 24536 * Extracts the mode from the supplied measure specification. 24537 * 24538 * @param measureSpec the measure specification to extract the mode from 24539 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 24540 * {@link android.view.View.MeasureSpec#AT_MOST} or 24541 * {@link android.view.View.MeasureSpec#EXACTLY} 24542 */ 24543 @MeasureSpecMode 24544 public static int getMode(int measureSpec) { 24545 //noinspection ResourceType 24546 return (measureSpec & MODE_MASK); 24547 } 24548 24549 /** 24550 * Extracts the size from the supplied measure specification. 24551 * 24552 * @param measureSpec the measure specification to extract the size from 24553 * @return the size in pixels defined in the supplied measure specification 24554 */ 24555 public static int getSize(int measureSpec) { 24556 return (measureSpec & ~MODE_MASK); 24557 } 24558 24559 static int adjust(int measureSpec, int delta) { 24560 final int mode = getMode(measureSpec); 24561 int size = getSize(measureSpec); 24562 if (mode == UNSPECIFIED) { 24563 // No need to adjust size for UNSPECIFIED mode. 24564 return makeMeasureSpec(size, UNSPECIFIED); 24565 } 24566 size += delta; 24567 if (size < 0) { 24568 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 24569 ") spec: " + toString(measureSpec) + " delta: " + delta); 24570 size = 0; 24571 } 24572 return makeMeasureSpec(size, mode); 24573 } 24574 24575 /** 24576 * Returns a String representation of the specified measure 24577 * specification. 24578 * 24579 * @param measureSpec the measure specification to convert to a String 24580 * @return a String with the following format: "MeasureSpec: MODE SIZE" 24581 */ 24582 public static String toString(int measureSpec) { 24583 int mode = getMode(measureSpec); 24584 int size = getSize(measureSpec); 24585 24586 StringBuilder sb = new StringBuilder("MeasureSpec: "); 24587 24588 if (mode == UNSPECIFIED) 24589 sb.append("UNSPECIFIED "); 24590 else if (mode == EXACTLY) 24591 sb.append("EXACTLY "); 24592 else if (mode == AT_MOST) 24593 sb.append("AT_MOST "); 24594 else 24595 sb.append(mode).append(" "); 24596 24597 sb.append(size); 24598 return sb.toString(); 24599 } 24600 } 24601 24602 private final class CheckForLongPress implements Runnable { 24603 private int mOriginalWindowAttachCount; 24604 private float mX; 24605 private float mY; 24606 private boolean mOriginalPressedState; 24607 24608 @Override 24609 public void run() { 24610 if ((mOriginalPressedState == isPressed()) && (mParent != null) 24611 && mOriginalWindowAttachCount == mWindowAttachCount) { 24612 if (performLongClick(mX, mY)) { 24613 mHasPerformedLongPress = true; 24614 } 24615 } 24616 } 24617 24618 public void setAnchor(float x, float y) { 24619 mX = x; 24620 mY = y; 24621 } 24622 24623 public void rememberWindowAttachCount() { 24624 mOriginalWindowAttachCount = mWindowAttachCount; 24625 } 24626 24627 public void rememberPressedState() { 24628 mOriginalPressedState = isPressed(); 24629 } 24630 } 24631 24632 private final class CheckForTap implements Runnable { 24633 public float x; 24634 public float y; 24635 24636 @Override 24637 public void run() { 24638 mPrivateFlags &= ~PFLAG_PREPRESSED; 24639 setPressed(true, x, y); 24640 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 24641 } 24642 } 24643 24644 private final class PerformClick implements Runnable { 24645 @Override 24646 public void run() { 24647 performClick(); 24648 } 24649 } 24650 24651 /** 24652 * This method returns a ViewPropertyAnimator object, which can be used to animate 24653 * specific properties on this View. 24654 * 24655 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 24656 */ 24657 public ViewPropertyAnimator animate() { 24658 if (mAnimator == null) { 24659 mAnimator = new ViewPropertyAnimator(this); 24660 } 24661 return mAnimator; 24662 } 24663 24664 /** 24665 * Sets the name of the View to be used to identify Views in Transitions. 24666 * Names should be unique in the View hierarchy. 24667 * 24668 * @param transitionName The name of the View to uniquely identify it for Transitions. 24669 */ 24670 public final void setTransitionName(String transitionName) { 24671 mTransitionName = transitionName; 24672 } 24673 24674 /** 24675 * Returns the name of the View to be used to identify Views in Transitions. 24676 * Names should be unique in the View hierarchy. 24677 * 24678 * <p>This returns null if the View has not been given a name.</p> 24679 * 24680 * @return The name used of the View to be used to identify Views in Transitions or null 24681 * if no name has been given. 24682 */ 24683 @ViewDebug.ExportedProperty 24684 public String getTransitionName() { 24685 return mTransitionName; 24686 } 24687 24688 /** 24689 * @hide 24690 */ 24691 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 24692 // Do nothing. 24693 } 24694 24695 /** 24696 * Interface definition for a callback to be invoked when a hardware key event is 24697 * dispatched to this view. The callback will be invoked before the key event is 24698 * given to the view. This is only useful for hardware keyboards; a software input 24699 * method has no obligation to trigger this listener. 24700 */ 24701 public interface OnKeyListener { 24702 /** 24703 * Called when a hardware key is dispatched to a view. This allows listeners to 24704 * get a chance to respond before the target view. 24705 * <p>Key presses in software keyboards will generally NOT trigger this method, 24706 * although some may elect to do so in some situations. Do not assume a 24707 * software input method has to be key-based; even if it is, it may use key presses 24708 * in a different way than you expect, so there is no way to reliably catch soft 24709 * input key presses. 24710 * 24711 * @param v The view the key has been dispatched to. 24712 * @param keyCode The code for the physical key that was pressed 24713 * @param event The KeyEvent object containing full information about 24714 * the event. 24715 * @return True if the listener has consumed the event, false otherwise. 24716 */ 24717 boolean onKey(View v, int keyCode, KeyEvent event); 24718 } 24719 24720 /** 24721 * Interface definition for a callback to be invoked when a touch event is 24722 * dispatched to this view. The callback will be invoked before the touch 24723 * event is given to the view. 24724 */ 24725 public interface OnTouchListener { 24726 /** 24727 * Called when a touch event is dispatched to a view. This allows listeners to 24728 * get a chance to respond before the target view. 24729 * 24730 * @param v The view the touch event has been dispatched to. 24731 * @param event The MotionEvent object containing full information about 24732 * the event. 24733 * @return True if the listener has consumed the event, false otherwise. 24734 */ 24735 boolean onTouch(View v, MotionEvent event); 24736 } 24737 24738 /** 24739 * Interface definition for a callback to be invoked when a hover event is 24740 * dispatched to this view. The callback will be invoked before the hover 24741 * event is given to the view. 24742 */ 24743 public interface OnHoverListener { 24744 /** 24745 * Called when a hover event is dispatched to a view. This allows listeners to 24746 * get a chance to respond before the target view. 24747 * 24748 * @param v The view the hover event has been dispatched to. 24749 * @param event The MotionEvent object containing full information about 24750 * the event. 24751 * @return True if the listener has consumed the event, false otherwise. 24752 */ 24753 boolean onHover(View v, MotionEvent event); 24754 } 24755 24756 /** 24757 * Interface definition for a callback to be invoked when a generic motion event is 24758 * dispatched to this view. The callback will be invoked before the generic motion 24759 * event is given to the view. 24760 */ 24761 public interface OnGenericMotionListener { 24762 /** 24763 * Called when a generic motion event is dispatched to a view. This allows listeners to 24764 * get a chance to respond before the target view. 24765 * 24766 * @param v The view the generic motion event has been dispatched to. 24767 * @param event The MotionEvent object containing full information about 24768 * the event. 24769 * @return True if the listener has consumed the event, false otherwise. 24770 */ 24771 boolean onGenericMotion(View v, MotionEvent event); 24772 } 24773 24774 /** 24775 * Interface definition for a callback to be invoked when a view has been clicked and held. 24776 */ 24777 public interface OnLongClickListener { 24778 /** 24779 * Called when a view has been clicked and held. 24780 * 24781 * @param v The view that was clicked and held. 24782 * 24783 * @return true if the callback consumed the long click, false otherwise. 24784 */ 24785 boolean onLongClick(View v); 24786 } 24787 24788 /** 24789 * Interface definition for a callback to be invoked when a drag is being dispatched 24790 * to this view. The callback will be invoked before the hosting view's own 24791 * onDrag(event) method. If the listener wants to fall back to the hosting view's 24792 * onDrag(event) behavior, it should return 'false' from this callback. 24793 * 24794 * <div class="special reference"> 24795 * <h3>Developer Guides</h3> 24796 * <p>For a guide to implementing drag and drop features, read the 24797 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 24798 * </div> 24799 */ 24800 public interface OnDragListener { 24801 /** 24802 * Called when a drag event is dispatched to a view. This allows listeners 24803 * to get a chance to override base View behavior. 24804 * 24805 * @param v The View that received the drag event. 24806 * @param event The {@link android.view.DragEvent} object for the drag event. 24807 * @return {@code true} if the drag event was handled successfully, or {@code false} 24808 * if the drag event was not handled. Note that {@code false} will trigger the View 24809 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 24810 */ 24811 boolean onDrag(View v, DragEvent event); 24812 } 24813 24814 /** 24815 * Interface definition for a callback to be invoked when the focus state of 24816 * a view changed. 24817 */ 24818 public interface OnFocusChangeListener { 24819 /** 24820 * Called when the focus state of a view has changed. 24821 * 24822 * @param v The view whose state has changed. 24823 * @param hasFocus The new focus state of v. 24824 */ 24825 void onFocusChange(View v, boolean hasFocus); 24826 } 24827 24828 /** 24829 * Interface definition for a callback to be invoked when a view is clicked. 24830 */ 24831 public interface OnClickListener { 24832 /** 24833 * Called when a view has been clicked. 24834 * 24835 * @param v The view that was clicked. 24836 */ 24837 void onClick(View v); 24838 } 24839 24840 /** 24841 * Interface definition for a callback to be invoked when a view is context clicked. 24842 */ 24843 public interface OnContextClickListener { 24844 /** 24845 * Called when a view is context clicked. 24846 * 24847 * @param v The view that has been context clicked. 24848 * @return true if the callback consumed the context click, false otherwise. 24849 */ 24850 boolean onContextClick(View v); 24851 } 24852 24853 /** 24854 * Interface definition for a callback to be invoked when the context menu 24855 * for this view is being built. 24856 */ 24857 public interface OnCreateContextMenuListener { 24858 /** 24859 * Called when the context menu for this view is being built. It is not 24860 * safe to hold onto the menu after this method returns. 24861 * 24862 * @param menu The context menu that is being built 24863 * @param v The view for which the context menu is being built 24864 * @param menuInfo Extra information about the item for which the 24865 * context menu should be shown. This information will vary 24866 * depending on the class of v. 24867 */ 24868 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 24869 } 24870 24871 /** 24872 * Interface definition for a callback to be invoked when the status bar changes 24873 * visibility. This reports <strong>global</strong> changes to the system UI 24874 * state, not what the application is requesting. 24875 * 24876 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 24877 */ 24878 public interface OnSystemUiVisibilityChangeListener { 24879 /** 24880 * Called when the status bar changes visibility because of a call to 24881 * {@link View#setSystemUiVisibility(int)}. 24882 * 24883 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 24884 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 24885 * This tells you the <strong>global</strong> state of these UI visibility 24886 * flags, not what your app is currently applying. 24887 */ 24888 public void onSystemUiVisibilityChange(int visibility); 24889 } 24890 24891 /** 24892 * Interface definition for a callback to be invoked when this view is attached 24893 * or detached from its window. 24894 */ 24895 public interface OnAttachStateChangeListener { 24896 /** 24897 * Called when the view is attached to a window. 24898 * @param v The view that was attached 24899 */ 24900 public void onViewAttachedToWindow(View v); 24901 /** 24902 * Called when the view is detached from a window. 24903 * @param v The view that was detached 24904 */ 24905 public void onViewDetachedFromWindow(View v); 24906 } 24907 24908 /** 24909 * Listener for applying window insets on a view in a custom way. 24910 * 24911 * <p>Apps may choose to implement this interface if they want to apply custom policy 24912 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 24913 * is set, its 24914 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 24915 * method will be called instead of the View's own 24916 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 24917 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 24918 * the View's normal behavior as part of its own.</p> 24919 */ 24920 public interface OnApplyWindowInsetsListener { 24921 /** 24922 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 24923 * on a View, this listener method will be called instead of the view's own 24924 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 24925 * 24926 * @param v The view applying window insets 24927 * @param insets The insets to apply 24928 * @return The insets supplied, minus any insets that were consumed 24929 */ 24930 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 24931 } 24932 24933 private final class UnsetPressedState implements Runnable { 24934 @Override 24935 public void run() { 24936 setPressed(false); 24937 } 24938 } 24939 24940 /** 24941 * When a view becomes invisible checks if autofill considers the view invisible too. This 24942 * happens after the regular removal operation to make sure the operation is finished by the 24943 * time this is called. 24944 */ 24945 private static class VisibilityChangeForAutofillHandler extends Handler { 24946 private final AutofillManager mAfm; 24947 private final View mView; 24948 24949 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 24950 @NonNull View view) { 24951 mAfm = afm; 24952 mView = view; 24953 } 24954 24955 @Override 24956 public void handleMessage(Message msg) { 24957 mAfm.notifyViewVisibilityChange(mView, mView.isShown()); 24958 } 24959 } 24960 24961 /** 24962 * Base class for derived classes that want to save and restore their own 24963 * state in {@link android.view.View#onSaveInstanceState()}. 24964 */ 24965 public static class BaseSavedState extends AbsSavedState { 24966 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 24967 static final int IS_AUTOFILLED = 0b10; 24968 static final int ACCESSIBILITY_ID = 0b100; 24969 24970 // Flags that describe what data in this state is valid 24971 int mSavedData; 24972 String mStartActivityRequestWhoSaved; 24973 boolean mIsAutofilled; 24974 int mAccessibilityViewId; 24975 24976 /** 24977 * Constructor used when reading from a parcel. Reads the state of the superclass. 24978 * 24979 * @param source parcel to read from 24980 */ 24981 public BaseSavedState(Parcel source) { 24982 this(source, null); 24983 } 24984 24985 /** 24986 * Constructor used when reading from a parcel using a given class loader. 24987 * Reads the state of the superclass. 24988 * 24989 * @param source parcel to read from 24990 * @param loader ClassLoader to use for reading 24991 */ 24992 public BaseSavedState(Parcel source, ClassLoader loader) { 24993 super(source, loader); 24994 mSavedData = source.readInt(); 24995 mStartActivityRequestWhoSaved = source.readString(); 24996 mIsAutofilled = source.readBoolean(); 24997 mAccessibilityViewId = source.readInt(); 24998 } 24999 25000 /** 25001 * Constructor called by derived classes when creating their SavedState objects 25002 * 25003 * @param superState The state of the superclass of this view 25004 */ 25005 public BaseSavedState(Parcelable superState) { 25006 super(superState); 25007 } 25008 25009 @Override 25010 public void writeToParcel(Parcel out, int flags) { 25011 super.writeToParcel(out, flags); 25012 25013 out.writeInt(mSavedData); 25014 out.writeString(mStartActivityRequestWhoSaved); 25015 out.writeBoolean(mIsAutofilled); 25016 out.writeInt(mAccessibilityViewId); 25017 } 25018 25019 public static final Parcelable.Creator<BaseSavedState> CREATOR 25020 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 25021 @Override 25022 public BaseSavedState createFromParcel(Parcel in) { 25023 return new BaseSavedState(in); 25024 } 25025 25026 @Override 25027 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 25028 return new BaseSavedState(in, loader); 25029 } 25030 25031 @Override 25032 public BaseSavedState[] newArray(int size) { 25033 return new BaseSavedState[size]; 25034 } 25035 }; 25036 } 25037 25038 /** 25039 * A set of information given to a view when it is attached to its parent 25040 * window. 25041 */ 25042 final static class AttachInfo { 25043 interface Callbacks { 25044 void playSoundEffect(int effectId); 25045 boolean performHapticFeedback(int effectId, boolean always); 25046 } 25047 25048 /** 25049 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 25050 * to a Handler. This class contains the target (View) to invalidate and 25051 * the coordinates of the dirty rectangle. 25052 * 25053 * For performance purposes, this class also implements a pool of up to 25054 * POOL_LIMIT objects that get reused. This reduces memory allocations 25055 * whenever possible. 25056 */ 25057 static class InvalidateInfo { 25058 private static final int POOL_LIMIT = 10; 25059 25060 private static final SynchronizedPool<InvalidateInfo> sPool = 25061 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 25062 25063 View target; 25064 25065 int left; 25066 int top; 25067 int right; 25068 int bottom; 25069 25070 public static InvalidateInfo obtain() { 25071 InvalidateInfo instance = sPool.acquire(); 25072 return (instance != null) ? instance : new InvalidateInfo(); 25073 } 25074 25075 public void recycle() { 25076 target = null; 25077 sPool.release(this); 25078 } 25079 } 25080 25081 final IWindowSession mSession; 25082 25083 final IWindow mWindow; 25084 25085 final IBinder mWindowToken; 25086 25087 Display mDisplay; 25088 25089 final Callbacks mRootCallbacks; 25090 25091 IWindowId mIWindowId; 25092 WindowId mWindowId; 25093 25094 /** 25095 * The top view of the hierarchy. 25096 */ 25097 View mRootView; 25098 25099 IBinder mPanelParentWindowToken; 25100 25101 boolean mHardwareAccelerated; 25102 boolean mHardwareAccelerationRequested; 25103 ThreadedRenderer mThreadedRenderer; 25104 List<RenderNode> mPendingAnimatingRenderNodes; 25105 25106 /** 25107 * The state of the display to which the window is attached, as reported 25108 * by {@link Display#getState()}. Note that the display state constants 25109 * declared by {@link Display} do not exactly line up with the screen state 25110 * constants declared by {@link View} (there are more display states than 25111 * screen states). 25112 */ 25113 int mDisplayState = Display.STATE_UNKNOWN; 25114 25115 /** 25116 * Scale factor used by the compatibility mode 25117 */ 25118 float mApplicationScale; 25119 25120 /** 25121 * Indicates whether the application is in compatibility mode 25122 */ 25123 boolean mScalingRequired; 25124 25125 /** 25126 * Left position of this view's window 25127 */ 25128 int mWindowLeft; 25129 25130 /** 25131 * Top position of this view's window 25132 */ 25133 int mWindowTop; 25134 25135 /** 25136 * Indicates whether views need to use 32-bit drawing caches 25137 */ 25138 boolean mUse32BitDrawingCache; 25139 25140 /** 25141 * For windows that are full-screen but using insets to layout inside 25142 * of the screen areas, these are the current insets to appear inside 25143 * the overscan area of the display. 25144 */ 25145 final Rect mOverscanInsets = new Rect(); 25146 25147 /** 25148 * For windows that are full-screen but using insets to layout inside 25149 * of the screen decorations, these are the current insets for the 25150 * content of the window. 25151 */ 25152 final Rect mContentInsets = new Rect(); 25153 25154 /** 25155 * For windows that are full-screen but using insets to layout inside 25156 * of the screen decorations, these are the current insets for the 25157 * actual visible parts of the window. 25158 */ 25159 final Rect mVisibleInsets = new Rect(); 25160 25161 /** 25162 * For windows that are full-screen but using insets to layout inside 25163 * of the screen decorations, these are the current insets for the 25164 * stable system windows. 25165 */ 25166 final Rect mStableInsets = new Rect(); 25167 25168 /** 25169 * For windows that include areas that are not covered by real surface these are the outsets 25170 * for real surface. 25171 */ 25172 final Rect mOutsets = new Rect(); 25173 25174 /** 25175 * In multi-window we force show the navigation bar. Because we don't want that the surface 25176 * size changes in this mode, we instead have a flag whether the navigation bar size should 25177 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 25178 */ 25179 boolean mAlwaysConsumeNavBar; 25180 25181 /** 25182 * The internal insets given by this window. This value is 25183 * supplied by the client (through 25184 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 25185 * be given to the window manager when changed to be used in laying 25186 * out windows behind it. 25187 */ 25188 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 25189 = new ViewTreeObserver.InternalInsetsInfo(); 25190 25191 /** 25192 * Set to true when mGivenInternalInsets is non-empty. 25193 */ 25194 boolean mHasNonEmptyGivenInternalInsets; 25195 25196 /** 25197 * All views in the window's hierarchy that serve as scroll containers, 25198 * used to determine if the window can be resized or must be panned 25199 * to adjust for a soft input area. 25200 */ 25201 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 25202 25203 final KeyEvent.DispatcherState mKeyDispatchState 25204 = new KeyEvent.DispatcherState(); 25205 25206 /** 25207 * Indicates whether the view's window currently has the focus. 25208 */ 25209 boolean mHasWindowFocus; 25210 25211 /** 25212 * The current visibility of the window. 25213 */ 25214 int mWindowVisibility; 25215 25216 /** 25217 * Indicates the time at which drawing started to occur. 25218 */ 25219 long mDrawingTime; 25220 25221 /** 25222 * Indicates whether or not ignoring the DIRTY_MASK flags. 25223 */ 25224 boolean mIgnoreDirtyState; 25225 25226 /** 25227 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 25228 * to avoid clearing that flag prematurely. 25229 */ 25230 boolean mSetIgnoreDirtyState = false; 25231 25232 /** 25233 * Indicates whether the view's window is currently in touch mode. 25234 */ 25235 boolean mInTouchMode; 25236 25237 /** 25238 * Indicates whether the view has requested unbuffered input dispatching for the current 25239 * event stream. 25240 */ 25241 boolean mUnbufferedDispatchRequested; 25242 25243 /** 25244 * Indicates that ViewAncestor should trigger a global layout change 25245 * the next time it performs a traversal 25246 */ 25247 boolean mRecomputeGlobalAttributes; 25248 25249 /** 25250 * Always report new attributes at next traversal. 25251 */ 25252 boolean mForceReportNewAttributes; 25253 25254 /** 25255 * Set during a traveral if any views want to keep the screen on. 25256 */ 25257 boolean mKeepScreenOn; 25258 25259 /** 25260 * Set during a traveral if the light center needs to be updated. 25261 */ 25262 boolean mNeedsUpdateLightCenter; 25263 25264 /** 25265 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 25266 */ 25267 int mSystemUiVisibility; 25268 25269 /** 25270 * Hack to force certain system UI visibility flags to be cleared. 25271 */ 25272 int mDisabledSystemUiVisibility; 25273 25274 /** 25275 * Last global system UI visibility reported by the window manager. 25276 */ 25277 int mGlobalSystemUiVisibility = -1; 25278 25279 /** 25280 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 25281 * attached. 25282 */ 25283 boolean mHasSystemUiListeners; 25284 25285 /** 25286 * Set if the window has requested to extend into the overscan region 25287 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 25288 */ 25289 boolean mOverscanRequested; 25290 25291 /** 25292 * Set if the visibility of any views has changed. 25293 */ 25294 boolean mViewVisibilityChanged; 25295 25296 /** 25297 * Set to true if a view has been scrolled. 25298 */ 25299 boolean mViewScrollChanged; 25300 25301 /** 25302 * Set to true if high contrast mode enabled 25303 */ 25304 boolean mHighContrastText; 25305 25306 /** 25307 * Set to true if a pointer event is currently being handled. 25308 */ 25309 boolean mHandlingPointerEvent; 25310 25311 /** 25312 * Global to the view hierarchy used as a temporary for dealing with 25313 * x/y points in the transparent region computations. 25314 */ 25315 final int[] mTransparentLocation = new int[2]; 25316 25317 /** 25318 * Global to the view hierarchy used as a temporary for dealing with 25319 * x/y points in the ViewGroup.invalidateChild implementation. 25320 */ 25321 final int[] mInvalidateChildLocation = new int[2]; 25322 25323 /** 25324 * Global to the view hierarchy used as a temporary for dealing with 25325 * computing absolute on-screen location. 25326 */ 25327 final int[] mTmpLocation = new int[2]; 25328 25329 /** 25330 * Global to the view hierarchy used as a temporary for dealing with 25331 * x/y location when view is transformed. 25332 */ 25333 final float[] mTmpTransformLocation = new float[2]; 25334 25335 /** 25336 * The view tree observer used to dispatch global events like 25337 * layout, pre-draw, touch mode change, etc. 25338 */ 25339 final ViewTreeObserver mTreeObserver; 25340 25341 /** 25342 * A Canvas used by the view hierarchy to perform bitmap caching. 25343 */ 25344 Canvas mCanvas; 25345 25346 /** 25347 * The view root impl. 25348 */ 25349 final ViewRootImpl mViewRootImpl; 25350 25351 /** 25352 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 25353 * handler can be used to pump events in the UI events queue. 25354 */ 25355 final Handler mHandler; 25356 25357 /** 25358 * Temporary for use in computing invalidate rectangles while 25359 * calling up the hierarchy. 25360 */ 25361 final Rect mTmpInvalRect = new Rect(); 25362 25363 /** 25364 * Temporary for use in computing hit areas with transformed views 25365 */ 25366 final RectF mTmpTransformRect = new RectF(); 25367 25368 /** 25369 * Temporary for use in computing hit areas with transformed views 25370 */ 25371 final RectF mTmpTransformRect1 = new RectF(); 25372 25373 /** 25374 * Temporary list of rectanges. 25375 */ 25376 final List<RectF> mTmpRectList = new ArrayList<>(); 25377 25378 /** 25379 * Temporary for use in transforming invalidation rect 25380 */ 25381 final Matrix mTmpMatrix = new Matrix(); 25382 25383 /** 25384 * Temporary for use in transforming invalidation rect 25385 */ 25386 final Transformation mTmpTransformation = new Transformation(); 25387 25388 /** 25389 * Temporary for use in querying outlines from OutlineProviders 25390 */ 25391 final Outline mTmpOutline = new Outline(); 25392 25393 /** 25394 * Temporary list for use in collecting focusable descendents of a view. 25395 */ 25396 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 25397 25398 /** 25399 * The id of the window for accessibility purposes. 25400 */ 25401 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 25402 25403 /** 25404 * Flags related to accessibility processing. 25405 * 25406 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 25407 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 25408 */ 25409 int mAccessibilityFetchFlags; 25410 25411 /** 25412 * The drawable for highlighting accessibility focus. 25413 */ 25414 Drawable mAccessibilityFocusDrawable; 25415 25416 /** 25417 * The drawable for highlighting autofilled views. 25418 * 25419 * @see #isAutofilled() 25420 */ 25421 Drawable mAutofilledDrawable; 25422 25423 /** 25424 * Show where the margins, bounds and layout bounds are for each view. 25425 */ 25426 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 25427 25428 /** 25429 * Point used to compute visible regions. 25430 */ 25431 final Point mPoint = new Point(); 25432 25433 /** 25434 * Used to track which View originated a requestLayout() call, used when 25435 * requestLayout() is called during layout. 25436 */ 25437 View mViewRequestingLayout; 25438 25439 /** 25440 * Used to track views that need (at least) a partial relayout at their current size 25441 * during the next traversal. 25442 */ 25443 List<View> mPartialLayoutViews = new ArrayList<>(); 25444 25445 /** 25446 * Swapped with mPartialLayoutViews during layout to avoid concurrent 25447 * modification. Lazily assigned during ViewRootImpl layout. 25448 */ 25449 List<View> mEmptyPartialLayoutViews; 25450 25451 /** 25452 * Used to track the identity of the current drag operation. 25453 */ 25454 IBinder mDragToken; 25455 25456 /** 25457 * The drag shadow surface for the current drag operation. 25458 */ 25459 public Surface mDragSurface; 25460 25461 25462 /** 25463 * The view that currently has a tooltip displayed. 25464 */ 25465 View mTooltipHost; 25466 25467 /** 25468 * Creates a new set of attachment information with the specified 25469 * events handler and thread. 25470 * 25471 * @param handler the events handler the view must use 25472 */ 25473 AttachInfo(IWindowSession session, IWindow window, Display display, 25474 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 25475 Context context) { 25476 mSession = session; 25477 mWindow = window; 25478 mWindowToken = window.asBinder(); 25479 mDisplay = display; 25480 mViewRootImpl = viewRootImpl; 25481 mHandler = handler; 25482 mRootCallbacks = effectPlayer; 25483 mTreeObserver = new ViewTreeObserver(context); 25484 } 25485 } 25486 25487 /** 25488 * <p>ScrollabilityCache holds various fields used by a View when scrolling 25489 * is supported. This avoids keeping too many unused fields in most 25490 * instances of View.</p> 25491 */ 25492 private static class ScrollabilityCache implements Runnable { 25493 25494 /** 25495 * Scrollbars are not visible 25496 */ 25497 public static final int OFF = 0; 25498 25499 /** 25500 * Scrollbars are visible 25501 */ 25502 public static final int ON = 1; 25503 25504 /** 25505 * Scrollbars are fading away 25506 */ 25507 public static final int FADING = 2; 25508 25509 public boolean fadeScrollBars; 25510 25511 public int fadingEdgeLength; 25512 public int scrollBarDefaultDelayBeforeFade; 25513 public int scrollBarFadeDuration; 25514 25515 public int scrollBarSize; 25516 public int scrollBarMinTouchTarget; 25517 public ScrollBarDrawable scrollBar; 25518 public float[] interpolatorValues; 25519 public View host; 25520 25521 public final Paint paint; 25522 public final Matrix matrix; 25523 public Shader shader; 25524 25525 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 25526 25527 private static final float[] OPAQUE = { 255 }; 25528 private static final float[] TRANSPARENT = { 0.0f }; 25529 25530 /** 25531 * When fading should start. This time moves into the future every time 25532 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 25533 */ 25534 public long fadeStartTime; 25535 25536 25537 /** 25538 * The current state of the scrollbars: ON, OFF, or FADING 25539 */ 25540 public int state = OFF; 25541 25542 private int mLastColor; 25543 25544 public final Rect mScrollBarBounds = new Rect(); 25545 public final Rect mScrollBarTouchBounds = new Rect(); 25546 25547 public static final int NOT_DRAGGING = 0; 25548 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 25549 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 25550 public int mScrollBarDraggingState = NOT_DRAGGING; 25551 25552 public float mScrollBarDraggingPos = 0; 25553 25554 public ScrollabilityCache(ViewConfiguration configuration, View host) { 25555 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 25556 scrollBarSize = configuration.getScaledScrollBarSize(); 25557 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 25558 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 25559 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 25560 25561 paint = new Paint(); 25562 matrix = new Matrix(); 25563 // use use a height of 1, and then wack the matrix each time we 25564 // actually use it. 25565 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 25566 paint.setShader(shader); 25567 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 25568 25569 this.host = host; 25570 } 25571 25572 public void setFadeColor(int color) { 25573 if (color != mLastColor) { 25574 mLastColor = color; 25575 25576 if (color != 0) { 25577 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 25578 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 25579 paint.setShader(shader); 25580 // Restore the default transfer mode (src_over) 25581 paint.setXfermode(null); 25582 } else { 25583 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 25584 paint.setShader(shader); 25585 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 25586 } 25587 } 25588 } 25589 25590 public void run() { 25591 long now = AnimationUtils.currentAnimationTimeMillis(); 25592 if (now >= fadeStartTime) { 25593 25594 // the animation fades the scrollbars out by changing 25595 // the opacity (alpha) from fully opaque to fully 25596 // transparent 25597 int nextFrame = (int) now; 25598 int framesCount = 0; 25599 25600 Interpolator interpolator = scrollBarInterpolator; 25601 25602 // Start opaque 25603 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 25604 25605 // End transparent 25606 nextFrame += scrollBarFadeDuration; 25607 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 25608 25609 state = FADING; 25610 25611 // Kick off the fade animation 25612 host.invalidate(true); 25613 } 25614 } 25615 } 25616 25617 /** 25618 * Resuable callback for sending 25619 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 25620 */ 25621 private class SendViewScrolledAccessibilityEvent implements Runnable { 25622 public volatile boolean mIsPending; 25623 25624 public void run() { 25625 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 25626 mIsPending = false; 25627 } 25628 } 25629 25630 /** 25631 * <p> 25632 * This class represents a delegate that can be registered in a {@link View} 25633 * to enhance accessibility support via composition rather via inheritance. 25634 * It is specifically targeted to widget developers that extend basic View 25635 * classes i.e. classes in package android.view, that would like their 25636 * applications to be backwards compatible. 25637 * </p> 25638 * <div class="special reference"> 25639 * <h3>Developer Guides</h3> 25640 * <p>For more information about making applications accessible, read the 25641 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 25642 * developer guide.</p> 25643 * </div> 25644 * <p> 25645 * A scenario in which a developer would like to use an accessibility delegate 25646 * is overriding a method introduced in a later API version than the minimal API 25647 * version supported by the application. For example, the method 25648 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 25649 * in API version 4 when the accessibility APIs were first introduced. If a 25650 * developer would like his application to run on API version 4 devices (assuming 25651 * all other APIs used by the application are version 4 or lower) and take advantage 25652 * of this method, instead of overriding the method which would break the application's 25653 * backwards compatibility, he can override the corresponding method in this 25654 * delegate and register the delegate in the target View if the API version of 25655 * the system is high enough, i.e. the API version is the same as or higher than the API 25656 * version that introduced 25657 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 25658 * </p> 25659 * <p> 25660 * Here is an example implementation: 25661 * </p> 25662 * <code><pre><p> 25663 * if (Build.VERSION.SDK_INT >= 14) { 25664 * // If the API version is equal of higher than the version in 25665 * // which onInitializeAccessibilityNodeInfo was introduced we 25666 * // register a delegate with a customized implementation. 25667 * View view = findViewById(R.id.view_id); 25668 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 25669 * public void onInitializeAccessibilityNodeInfo(View host, 25670 * AccessibilityNodeInfo info) { 25671 * // Let the default implementation populate the info. 25672 * super.onInitializeAccessibilityNodeInfo(host, info); 25673 * // Set some other information. 25674 * info.setEnabled(host.isEnabled()); 25675 * } 25676 * }); 25677 * } 25678 * </code></pre></p> 25679 * <p> 25680 * This delegate contains methods that correspond to the accessibility methods 25681 * in View. If a delegate has been specified the implementation in View hands 25682 * off handling to the corresponding method in this delegate. The default 25683 * implementation the delegate methods behaves exactly as the corresponding 25684 * method in View for the case of no accessibility delegate been set. Hence, 25685 * to customize the behavior of a View method, clients can override only the 25686 * corresponding delegate method without altering the behavior of the rest 25687 * accessibility related methods of the host view. 25688 * </p> 25689 * <p> 25690 * <strong>Note:</strong> On platform versions prior to 25691 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 25692 * views in the {@code android.widget.*} package are called <i>before</i> 25693 * host methods. This prevents certain properties such as class name from 25694 * being modified by overriding 25695 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 25696 * as any changes will be overwritten by the host class. 25697 * <p> 25698 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 25699 * methods are called <i>after</i> host methods, which all properties to be 25700 * modified without being overwritten by the host class. 25701 */ 25702 public static class AccessibilityDelegate { 25703 25704 /** 25705 * Sends an accessibility event of the given type. If accessibility is not 25706 * enabled this method has no effect. 25707 * <p> 25708 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 25709 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 25710 * been set. 25711 * </p> 25712 * 25713 * @param host The View hosting the delegate. 25714 * @param eventType The type of the event to send. 25715 * 25716 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 25717 */ 25718 public void sendAccessibilityEvent(View host, int eventType) { 25719 host.sendAccessibilityEventInternal(eventType); 25720 } 25721 25722 /** 25723 * Performs the specified accessibility action on the view. For 25724 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 25725 * <p> 25726 * The default implementation behaves as 25727 * {@link View#performAccessibilityAction(int, Bundle) 25728 * View#performAccessibilityAction(int, Bundle)} for the case of 25729 * no accessibility delegate been set. 25730 * </p> 25731 * 25732 * @param action The action to perform. 25733 * @return Whether the action was performed. 25734 * 25735 * @see View#performAccessibilityAction(int, Bundle) 25736 * View#performAccessibilityAction(int, Bundle) 25737 */ 25738 public boolean performAccessibilityAction(View host, int action, Bundle args) { 25739 return host.performAccessibilityActionInternal(action, args); 25740 } 25741 25742 /** 25743 * Sends an accessibility event. This method behaves exactly as 25744 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 25745 * empty {@link AccessibilityEvent} and does not perform a check whether 25746 * accessibility is enabled. 25747 * <p> 25748 * The default implementation behaves as 25749 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25750 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 25751 * the case of no accessibility delegate been set. 25752 * </p> 25753 * 25754 * @param host The View hosting the delegate. 25755 * @param event The event to send. 25756 * 25757 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25758 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25759 */ 25760 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 25761 host.sendAccessibilityEventUncheckedInternal(event); 25762 } 25763 25764 /** 25765 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 25766 * to its children for adding their text content to the event. 25767 * <p> 25768 * The default implementation behaves as 25769 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25770 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 25771 * the case of no accessibility delegate been set. 25772 * </p> 25773 * 25774 * @param host The View hosting the delegate. 25775 * @param event The event. 25776 * @return True if the event population was completed. 25777 * 25778 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25779 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25780 */ 25781 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25782 return host.dispatchPopulateAccessibilityEventInternal(event); 25783 } 25784 25785 /** 25786 * Gives a chance to the host View to populate the accessibility event with its 25787 * text content. 25788 * <p> 25789 * The default implementation behaves as 25790 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 25791 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 25792 * the case of no accessibility delegate been set. 25793 * </p> 25794 * 25795 * @param host The View hosting the delegate. 25796 * @param event The accessibility event which to populate. 25797 * 25798 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 25799 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 25800 */ 25801 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25802 host.onPopulateAccessibilityEventInternal(event); 25803 } 25804 25805 /** 25806 * Initializes an {@link AccessibilityEvent} with information about the 25807 * the host View which is the event source. 25808 * <p> 25809 * The default implementation behaves as 25810 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 25811 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 25812 * the case of no accessibility delegate been set. 25813 * </p> 25814 * 25815 * @param host The View hosting the delegate. 25816 * @param event The event to initialize. 25817 * 25818 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 25819 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 25820 */ 25821 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 25822 host.onInitializeAccessibilityEventInternal(event); 25823 } 25824 25825 /** 25826 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 25827 * <p> 25828 * The default implementation behaves as 25829 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25830 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 25831 * the case of no accessibility delegate been set. 25832 * </p> 25833 * 25834 * @param host The View hosting the delegate. 25835 * @param info The instance to initialize. 25836 * 25837 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25838 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25839 */ 25840 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 25841 host.onInitializeAccessibilityNodeInfoInternal(info); 25842 } 25843 25844 /** 25845 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 25846 * additional data. 25847 * <p> 25848 * This method only needs to be implemented if the View offers to provide additional data. 25849 * </p> 25850 * <p> 25851 * The default implementation behaves as 25852 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, int) for 25853 * the case where no accessibility delegate is set. 25854 * </p> 25855 * 25856 * @param host The View hosting the delegate. Never {@code null}. 25857 * @param info The info to which to add the extra data. Never {@code null}. 25858 * @param extraDataKey A key specifying the type of extra data to add to the info. The 25859 * extra data should be added to the {@link Bundle} returned by 25860 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 25861 * {@code null}. 25862 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 25863 * May be {@code null} if the if the service provided no arguments. 25864 * 25865 * @see AccessibilityNodeInfo#setExtraAvailableData 25866 */ 25867 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 25868 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 25869 @Nullable Bundle arguments) { 25870 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 25871 } 25872 25873 /** 25874 * Called when a child of the host View has requested sending an 25875 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 25876 * to augment the event. 25877 * <p> 25878 * The default implementation behaves as 25879 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25880 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 25881 * the case of no accessibility delegate been set. 25882 * </p> 25883 * 25884 * @param host The View hosting the delegate. 25885 * @param child The child which requests sending the event. 25886 * @param event The event to be sent. 25887 * @return True if the event should be sent 25888 * 25889 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25890 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25891 */ 25892 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 25893 AccessibilityEvent event) { 25894 return host.onRequestSendAccessibilityEventInternal(child, event); 25895 } 25896 25897 /** 25898 * Gets the provider for managing a virtual view hierarchy rooted at this View 25899 * and reported to {@link android.accessibilityservice.AccessibilityService}s 25900 * that explore the window content. 25901 * <p> 25902 * The default implementation behaves as 25903 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 25904 * the case of no accessibility delegate been set. 25905 * </p> 25906 * 25907 * @return The provider. 25908 * 25909 * @see AccessibilityNodeProvider 25910 */ 25911 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 25912 return null; 25913 } 25914 25915 /** 25916 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 25917 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 25918 * This method is responsible for obtaining an accessibility node info from a 25919 * pool of reusable instances and calling 25920 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 25921 * view to initialize the former. 25922 * <p> 25923 * <strong>Note:</strong> The client is responsible for recycling the obtained 25924 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 25925 * creation. 25926 * </p> 25927 * <p> 25928 * The default implementation behaves as 25929 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 25930 * the case of no accessibility delegate been set. 25931 * </p> 25932 * @return A populated {@link AccessibilityNodeInfo}. 25933 * 25934 * @see AccessibilityNodeInfo 25935 * 25936 * @hide 25937 */ 25938 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 25939 return host.createAccessibilityNodeInfoInternal(); 25940 } 25941 } 25942 25943 private static class MatchIdPredicate implements Predicate<View> { 25944 public int mId; 25945 25946 @Override 25947 public boolean test(View view) { 25948 return (view.mID == mId); 25949 } 25950 } 25951 25952 private static class MatchLabelForPredicate implements Predicate<View> { 25953 private int mLabeledId; 25954 25955 @Override 25956 public boolean test(View view) { 25957 return (view.mLabelForId == mLabeledId); 25958 } 25959 } 25960 25961 private class SendViewStateChangedAccessibilityEvent implements Runnable { 25962 private int mChangeTypes = 0; 25963 private boolean mPosted; 25964 private boolean mPostedWithDelay; 25965 private long mLastEventTimeMillis; 25966 25967 @Override 25968 public void run() { 25969 mPosted = false; 25970 mPostedWithDelay = false; 25971 mLastEventTimeMillis = SystemClock.uptimeMillis(); 25972 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 25973 final AccessibilityEvent event = AccessibilityEvent.obtain(); 25974 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 25975 event.setContentChangeTypes(mChangeTypes); 25976 sendAccessibilityEventUnchecked(event); 25977 } 25978 mChangeTypes = 0; 25979 } 25980 25981 public void runOrPost(int changeType) { 25982 mChangeTypes |= changeType; 25983 25984 // If this is a live region or the child of a live region, collect 25985 // all events from this frame and send them on the next frame. 25986 if (inLiveRegion()) { 25987 // If we're already posted with a delay, remove that. 25988 if (mPostedWithDelay) { 25989 removeCallbacks(this); 25990 mPostedWithDelay = false; 25991 } 25992 // Only post if we're not already posted. 25993 if (!mPosted) { 25994 post(this); 25995 mPosted = true; 25996 } 25997 return; 25998 } 25999 26000 if (mPosted) { 26001 return; 26002 } 26003 26004 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 26005 final long minEventIntevalMillis = 26006 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 26007 if (timeSinceLastMillis >= minEventIntevalMillis) { 26008 removeCallbacks(this); 26009 run(); 26010 } else { 26011 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 26012 mPostedWithDelay = true; 26013 } 26014 } 26015 } 26016 26017 private boolean inLiveRegion() { 26018 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { 26019 return true; 26020 } 26021 26022 ViewParent parent = getParent(); 26023 while (parent instanceof View) { 26024 if (((View) parent).getAccessibilityLiveRegion() 26025 != View.ACCESSIBILITY_LIVE_REGION_NONE) { 26026 return true; 26027 } 26028 parent = parent.getParent(); 26029 } 26030 26031 return false; 26032 } 26033 26034 /** 26035 * Dump all private flags in readable format, useful for documentation and 26036 * sanity checking. 26037 */ 26038 private static void dumpFlags() { 26039 final HashMap<String, String> found = Maps.newHashMap(); 26040 try { 26041 for (Field field : View.class.getDeclaredFields()) { 26042 final int modifiers = field.getModifiers(); 26043 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 26044 if (field.getType().equals(int.class)) { 26045 final int value = field.getInt(null); 26046 dumpFlag(found, field.getName(), value); 26047 } else if (field.getType().equals(int[].class)) { 26048 final int[] values = (int[]) field.get(null); 26049 for (int i = 0; i < values.length; i++) { 26050 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 26051 } 26052 } 26053 } 26054 } 26055 } catch (IllegalAccessException e) { 26056 throw new RuntimeException(e); 26057 } 26058 26059 final ArrayList<String> keys = Lists.newArrayList(); 26060 keys.addAll(found.keySet()); 26061 Collections.sort(keys); 26062 for (String key : keys) { 26063 Log.d(VIEW_LOG_TAG, found.get(key)); 26064 } 26065 } 26066 26067 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 26068 // Sort flags by prefix, then by bits, always keeping unique keys 26069 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 26070 final int prefix = name.indexOf('_'); 26071 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 26072 final String output = bits + " " + name; 26073 found.put(key, output); 26074 } 26075 26076 /** {@hide} */ 26077 public void encode(@NonNull ViewHierarchyEncoder stream) { 26078 stream.beginObject(this); 26079 encodeProperties(stream); 26080 stream.endObject(); 26081 } 26082 26083 /** {@hide} */ 26084 @CallSuper 26085 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 26086 Object resolveId = ViewDebug.resolveId(getContext(), mID); 26087 if (resolveId instanceof String) { 26088 stream.addProperty("id", (String) resolveId); 26089 } else { 26090 stream.addProperty("id", mID); 26091 } 26092 26093 stream.addProperty("misc:transformation.alpha", 26094 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 26095 stream.addProperty("misc:transitionName", getTransitionName()); 26096 26097 // layout 26098 stream.addProperty("layout:left", mLeft); 26099 stream.addProperty("layout:right", mRight); 26100 stream.addProperty("layout:top", mTop); 26101 stream.addProperty("layout:bottom", mBottom); 26102 stream.addProperty("layout:width", getWidth()); 26103 stream.addProperty("layout:height", getHeight()); 26104 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 26105 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 26106 stream.addProperty("layout:hasTransientState", hasTransientState()); 26107 stream.addProperty("layout:baseline", getBaseline()); 26108 26109 // layout params 26110 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 26111 if (layoutParams != null) { 26112 stream.addPropertyKey("layoutParams"); 26113 layoutParams.encode(stream); 26114 } 26115 26116 // scrolling 26117 stream.addProperty("scrolling:scrollX", mScrollX); 26118 stream.addProperty("scrolling:scrollY", mScrollY); 26119 26120 // padding 26121 stream.addProperty("padding:paddingLeft", mPaddingLeft); 26122 stream.addProperty("padding:paddingRight", mPaddingRight); 26123 stream.addProperty("padding:paddingTop", mPaddingTop); 26124 stream.addProperty("padding:paddingBottom", mPaddingBottom); 26125 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 26126 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 26127 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 26128 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 26129 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 26130 26131 // measurement 26132 stream.addProperty("measurement:minHeight", mMinHeight); 26133 stream.addProperty("measurement:minWidth", mMinWidth); 26134 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 26135 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 26136 26137 // drawing 26138 stream.addProperty("drawing:elevation", getElevation()); 26139 stream.addProperty("drawing:translationX", getTranslationX()); 26140 stream.addProperty("drawing:translationY", getTranslationY()); 26141 stream.addProperty("drawing:translationZ", getTranslationZ()); 26142 stream.addProperty("drawing:rotation", getRotation()); 26143 stream.addProperty("drawing:rotationX", getRotationX()); 26144 stream.addProperty("drawing:rotationY", getRotationY()); 26145 stream.addProperty("drawing:scaleX", getScaleX()); 26146 stream.addProperty("drawing:scaleY", getScaleY()); 26147 stream.addProperty("drawing:pivotX", getPivotX()); 26148 stream.addProperty("drawing:pivotY", getPivotY()); 26149 stream.addProperty("drawing:opaque", isOpaque()); 26150 stream.addProperty("drawing:alpha", getAlpha()); 26151 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 26152 stream.addProperty("drawing:shadow", hasShadow()); 26153 stream.addProperty("drawing:solidColor", getSolidColor()); 26154 stream.addProperty("drawing:layerType", mLayerType); 26155 stream.addProperty("drawing:willNotDraw", willNotDraw()); 26156 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 26157 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 26158 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 26159 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 26160 26161 // focus 26162 stream.addProperty("focus:hasFocus", hasFocus()); 26163 stream.addProperty("focus:isFocused", isFocused()); 26164 stream.addProperty("focus:focusable", getFocusable()); 26165 stream.addProperty("focus:isFocusable", isFocusable()); 26166 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 26167 26168 stream.addProperty("misc:clickable", isClickable()); 26169 stream.addProperty("misc:pressed", isPressed()); 26170 stream.addProperty("misc:selected", isSelected()); 26171 stream.addProperty("misc:touchMode", isInTouchMode()); 26172 stream.addProperty("misc:hovered", isHovered()); 26173 stream.addProperty("misc:activated", isActivated()); 26174 26175 stream.addProperty("misc:visibility", getVisibility()); 26176 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 26177 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 26178 26179 stream.addProperty("misc:enabled", isEnabled()); 26180 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 26181 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 26182 26183 // theme attributes 26184 Resources.Theme theme = getContext().getTheme(); 26185 if (theme != null) { 26186 stream.addPropertyKey("theme"); 26187 theme.encode(stream); 26188 } 26189 26190 // view attribute information 26191 int n = mAttributes != null ? mAttributes.length : 0; 26192 stream.addProperty("meta:__attrCount__", n/2); 26193 for (int i = 0; i < n; i += 2) { 26194 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 26195 } 26196 26197 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 26198 26199 // text 26200 stream.addProperty("text:textDirection", getTextDirection()); 26201 stream.addProperty("text:textAlignment", getTextAlignment()); 26202 26203 // accessibility 26204 CharSequence contentDescription = getContentDescription(); 26205 stream.addProperty("accessibility:contentDescription", 26206 contentDescription == null ? "" : contentDescription.toString()); 26207 stream.addProperty("accessibility:labelFor", getLabelFor()); 26208 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 26209 } 26210 26211 /** 26212 * Determine if this view is rendered on a round wearable device and is the main view 26213 * on the screen. 26214 */ 26215 boolean shouldDrawRoundScrollbar() { 26216 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 26217 return false; 26218 } 26219 26220 final View rootView = getRootView(); 26221 final WindowInsets insets = getRootWindowInsets(); 26222 26223 int height = getHeight(); 26224 int width = getWidth(); 26225 int displayHeight = rootView.getHeight(); 26226 int displayWidth = rootView.getWidth(); 26227 26228 if (height != displayHeight || width != displayWidth) { 26229 return false; 26230 } 26231 26232 getLocationInWindow(mAttachInfo.mTmpLocation); 26233 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 26234 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 26235 } 26236 26237 /** 26238 * Sets the tooltip text which will be displayed in a small popup next to the view. 26239 * <p> 26240 * The tooltip will be displayed: 26241 * <ul> 26242 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 26243 * menu). </li> 26244 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 26245 * </ul> 26246 * <p> 26247 * <strong>Note:</strong> Do not override this method, as it will have no 26248 * effect on the text displayed in the tooltip. 26249 * 26250 * @param tooltipText the tooltip text, or null if no tooltip is required 26251 * @see #getTooltipText() 26252 * @attr ref android.R.styleable#View_tooltipText 26253 */ 26254 public void setTooltipText(@Nullable CharSequence tooltipText) { 26255 if (TextUtils.isEmpty(tooltipText)) { 26256 setFlags(0, TOOLTIP); 26257 hideTooltip(); 26258 mTooltipInfo = null; 26259 } else { 26260 setFlags(TOOLTIP, TOOLTIP); 26261 if (mTooltipInfo == null) { 26262 mTooltipInfo = new TooltipInfo(); 26263 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 26264 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 26265 } 26266 mTooltipInfo.mTooltipText = tooltipText; 26267 if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) { 26268 mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText); 26269 } 26270 } 26271 } 26272 26273 /** 26274 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 26275 */ 26276 public void setTooltip(@Nullable CharSequence tooltipText) { 26277 setTooltipText(tooltipText); 26278 } 26279 26280 /** 26281 * Returns the view's tooltip text. 26282 * 26283 * <strong>Note:</strong> Do not override this method, as it will have no 26284 * effect on the text displayed in the tooltip. You must call 26285 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 26286 * 26287 * @return the tooltip text 26288 * @see #setTooltipText(CharSequence) 26289 * @attr ref android.R.styleable#View_tooltipText 26290 */ 26291 @Nullable 26292 public CharSequence getTooltipText() { 26293 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 26294 } 26295 26296 /** 26297 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 26298 */ 26299 @Nullable 26300 public CharSequence getTooltip() { 26301 return getTooltipText(); 26302 } 26303 26304 private boolean showTooltip(int x, int y, boolean fromLongClick) { 26305 if (mAttachInfo == null || mTooltipInfo == null) { 26306 return false; 26307 } 26308 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 26309 return false; 26310 } 26311 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 26312 return false; 26313 } 26314 hideTooltip(); 26315 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 26316 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 26317 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 26318 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 26319 mAttachInfo.mTooltipHost = this; 26320 return true; 26321 } 26322 26323 void hideTooltip() { 26324 if (mTooltipInfo == null) { 26325 return; 26326 } 26327 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26328 if (mTooltipInfo.mTooltipPopup == null) { 26329 return; 26330 } 26331 mTooltipInfo.mTooltipPopup.hide(); 26332 mTooltipInfo.mTooltipPopup = null; 26333 mTooltipInfo.mTooltipFromLongClick = false; 26334 if (mAttachInfo != null) { 26335 mAttachInfo.mTooltipHost = null; 26336 } 26337 } 26338 26339 private boolean showLongClickTooltip(int x, int y) { 26340 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26341 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26342 return showTooltip(x, y, true); 26343 } 26344 26345 private void showHoverTooltip() { 26346 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 26347 } 26348 26349 boolean dispatchTooltipHoverEvent(MotionEvent event) { 26350 if (mTooltipInfo == null) { 26351 return false; 26352 } 26353 switch(event.getAction()) { 26354 case MotionEvent.ACTION_HOVER_MOVE: 26355 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 26356 break; 26357 } 26358 if (!mTooltipInfo.mTooltipFromLongClick) { 26359 if (mTooltipInfo.mTooltipPopup == null) { 26360 // Schedule showing the tooltip after a timeout. 26361 mTooltipInfo.mAnchorX = (int) event.getX(); 26362 mTooltipInfo.mAnchorY = (int) event.getY(); 26363 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26364 postDelayed(mTooltipInfo.mShowTooltipRunnable, 26365 ViewConfiguration.getHoverTooltipShowTimeout()); 26366 } 26367 26368 // Hide hover-triggered tooltip after a period of inactivity. 26369 // Match the timeout used by NativeInputManager to hide the mouse pointer 26370 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 26371 final int timeout; 26372 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 26373 == SYSTEM_UI_FLAG_LOW_PROFILE) { 26374 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 26375 } else { 26376 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 26377 } 26378 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26379 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 26380 } 26381 return true; 26382 26383 case MotionEvent.ACTION_HOVER_EXIT: 26384 if (!mTooltipInfo.mTooltipFromLongClick) { 26385 hideTooltip(); 26386 } 26387 break; 26388 } 26389 return false; 26390 } 26391 26392 void handleTooltipKey(KeyEvent event) { 26393 switch (event.getAction()) { 26394 case KeyEvent.ACTION_DOWN: 26395 if (event.getRepeatCount() == 0) { 26396 hideTooltip(); 26397 } 26398 break; 26399 26400 case KeyEvent.ACTION_UP: 26401 handleTooltipUp(); 26402 break; 26403 } 26404 } 26405 26406 private void handleTooltipUp() { 26407 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 26408 return; 26409 } 26410 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26411 postDelayed(mTooltipInfo.mHideTooltipRunnable, 26412 ViewConfiguration.getLongPressTooltipHideTimeout()); 26413 } 26414 26415 private int getFocusableAttribute(TypedArray attributes) { 26416 TypedValue val = new TypedValue(); 26417 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 26418 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 26419 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 26420 } else { 26421 return val.data; 26422 } 26423 } else { 26424 return FOCUSABLE_AUTO; 26425 } 26426 } 26427 26428 /** 26429 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 26430 * is not showing. 26431 * @hide 26432 */ 26433 @TestApi 26434 public View getTooltipView() { 26435 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 26436 return null; 26437 } 26438 return mTooltipInfo.mTooltipPopup.getContentView(); 26439 } 26440} 26441