View.java revision 04b926a68b85d9b93f7de2647f9f4770532b2e0f
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.view; 18 19import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH; 20import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 21import static android.os.Build.VERSION_CODES.KITKAT; 22import static android.os.Build.VERSION_CODES.M; 23import static android.os.Build.VERSION_CODES.N; 24 25import static java.lang.Math.max; 26 27import android.animation.AnimatorInflater; 28import android.animation.StateListAnimator; 29import android.annotation.CallSuper; 30import android.annotation.ColorInt; 31import android.annotation.DrawableRes; 32import android.annotation.FloatRange; 33import android.annotation.IdRes; 34import android.annotation.IntDef; 35import android.annotation.IntRange; 36import android.annotation.LayoutRes; 37import android.annotation.NonNull; 38import android.annotation.Nullable; 39import android.annotation.Size; 40import android.annotation.TestApi; 41import android.annotation.UiThread; 42import android.app.Application.OnProvideAssistDataListener; 43import android.content.ClipData; 44import android.content.Context; 45import android.content.ContextWrapper; 46import android.content.Intent; 47import android.content.res.ColorStateList; 48import android.content.res.Configuration; 49import android.content.res.Resources; 50import android.content.res.TypedArray; 51import android.graphics.Bitmap; 52import android.graphics.Canvas; 53import android.graphics.Color; 54import android.graphics.Insets; 55import android.graphics.Interpolator; 56import android.graphics.LinearGradient; 57import android.graphics.Matrix; 58import android.graphics.Outline; 59import android.graphics.Paint; 60import android.graphics.PixelFormat; 61import android.graphics.Point; 62import android.graphics.PorterDuff; 63import android.graphics.PorterDuffXfermode; 64import android.graphics.Rect; 65import android.graphics.RectF; 66import android.graphics.Region; 67import android.graphics.Shader; 68import android.graphics.drawable.ColorDrawable; 69import android.graphics.drawable.Drawable; 70import android.hardware.display.DisplayManagerGlobal; 71import android.os.Build.VERSION_CODES; 72import android.os.Bundle; 73import android.os.Handler; 74import android.os.IBinder; 75import android.os.Parcel; 76import android.os.Parcelable; 77import android.os.RemoteException; 78import android.os.SystemClock; 79import android.os.SystemProperties; 80import android.os.Trace; 81import android.text.TextUtils; 82import android.util.AttributeSet; 83import android.util.FloatProperty; 84import android.util.LayoutDirection; 85import android.util.Log; 86import android.util.LongSparseLongArray; 87import android.util.Pools.SynchronizedPool; 88import android.util.Property; 89import android.util.SparseArray; 90import android.util.StateSet; 91import android.util.SuperNotCalledException; 92import android.util.TypedValue; 93import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 94import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 95import android.view.AccessibilityIterators.TextSegmentIterator; 96import android.view.AccessibilityIterators.WordTextSegmentIterator; 97import android.view.ContextMenu.ContextMenuInfo; 98import android.view.accessibility.AccessibilityEvent; 99import android.view.accessibility.AccessibilityEventSource; 100import android.view.accessibility.AccessibilityManager; 101import android.view.accessibility.AccessibilityNodeInfo; 102import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 103import android.view.accessibility.AccessibilityNodeProvider; 104import android.view.animation.Animation; 105import android.view.animation.AnimationUtils; 106import android.view.animation.Transformation; 107import android.view.autofill.AutoFillType; 108import android.view.autofill.AutoFillValue; 109import android.view.autofill.VirtualViewDelegate; 110import android.view.inputmethod.EditorInfo; 111import android.view.inputmethod.InputConnection; 112import android.view.inputmethod.InputMethodManager; 113import android.widget.Checkable; 114import android.widget.FrameLayout; 115import android.widget.ScrollBarDrawable; 116 117import com.android.internal.R; 118import com.android.internal.util.Predicate; 119import com.android.internal.view.TooltipPopup; 120import com.android.internal.view.menu.MenuBuilder; 121import com.android.internal.widget.ScrollBarUtils; 122 123import com.google.android.collect.Lists; 124import com.google.android.collect.Maps; 125 126import java.lang.annotation.Retention; 127import java.lang.annotation.RetentionPolicy; 128import java.lang.ref.WeakReference; 129import java.lang.reflect.Field; 130import java.lang.reflect.InvocationTargetException; 131import java.lang.reflect.Method; 132import java.lang.reflect.Modifier; 133import java.util.ArrayList; 134import java.util.Arrays; 135import java.util.Collection; 136import java.util.Collections; 137import java.util.HashMap; 138import java.util.List; 139import java.util.Locale; 140import java.util.Map; 141import java.util.concurrent.CopyOnWriteArrayList; 142import java.util.concurrent.atomic.AtomicInteger; 143 144/** 145 * <p> 146 * This class represents the basic building block for user interface components. A View 147 * occupies a rectangular area on the screen and is responsible for drawing and 148 * event handling. View is the base class for <em>widgets</em>, which are 149 * used to create interactive UI components (buttons, text fields, etc.). The 150 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 151 * are invisible containers that hold other Views (or other ViewGroups) and define 152 * their layout properties. 153 * </p> 154 * 155 * <div class="special reference"> 156 * <h3>Developer Guides</h3> 157 * <p>For information about using this class to develop your application's user interface, 158 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 159 * </div> 160 * 161 * <a name="Using"></a> 162 * <h3>Using Views</h3> 163 * <p> 164 * All of the views in a window are arranged in a single tree. You can add views 165 * either from code or by specifying a tree of views in one or more XML layout 166 * files. There are many specialized subclasses of views that act as controls or 167 * are capable of displaying text, images, or other content. 168 * </p> 169 * <p> 170 * Once you have created a tree of views, there are typically a few types of 171 * common operations you may wish to perform: 172 * <ul> 173 * <li><strong>Set properties:</strong> for example setting the text of a 174 * {@link android.widget.TextView}. The available properties and the methods 175 * that set them will vary among the different subclasses of views. Note that 176 * properties that are known at build time can be set in the XML layout 177 * files.</li> 178 * <li><strong>Set focus:</strong> The framework will handle moving focus in 179 * response to user input. To force focus to a specific view, call 180 * {@link #requestFocus}.</li> 181 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 182 * that will be notified when something interesting happens to the view. For 183 * example, all views will let you set a listener to be notified when the view 184 * gains or loses focus. You can register such a listener using 185 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 186 * Other view subclasses offer more specialized listeners. For example, a Button 187 * exposes a listener to notify clients when the button is clicked.</li> 188 * <li><strong>Set visibility:</strong> You can hide or show views using 189 * {@link #setVisibility(int)}.</li> 190 * </ul> 191 * </p> 192 * <p><em> 193 * Note: The Android framework is responsible for measuring, laying out and 194 * drawing views. You should not call methods that perform these actions on 195 * views yourself unless you are actually implementing a 196 * {@link android.view.ViewGroup}. 197 * </em></p> 198 * 199 * <a name="Lifecycle"></a> 200 * <h3>Implementing a Custom View</h3> 201 * 202 * <p> 203 * To implement a custom view, you will usually begin by providing overrides for 204 * some of the standard methods that the framework calls on all views. You do 205 * not need to override all of these methods. In fact, you can start by just 206 * overriding {@link #onDraw(android.graphics.Canvas)}. 207 * <table border="2" width="85%" align="center" cellpadding="5"> 208 * <thead> 209 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 210 * </thead> 211 * 212 * <tbody> 213 * <tr> 214 * <td rowspan="2">Creation</td> 215 * <td>Constructors</td> 216 * <td>There is a form of the constructor that are called when the view 217 * is created from code and a form that is called when the view is 218 * inflated from a layout file. The second form should parse and apply 219 * any attributes defined in the layout file. 220 * </td> 221 * </tr> 222 * <tr> 223 * <td><code>{@link #onFinishInflate()}</code></td> 224 * <td>Called after a view and all of its children has been inflated 225 * from XML.</td> 226 * </tr> 227 * 228 * <tr> 229 * <td rowspan="3">Layout</td> 230 * <td><code>{@link #onMeasure(int, int)}</code></td> 231 * <td>Called to determine the size requirements for this view and all 232 * of its children. 233 * </td> 234 * </tr> 235 * <tr> 236 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 237 * <td>Called when this view should assign a size and position to all 238 * of its children. 239 * </td> 240 * </tr> 241 * <tr> 242 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 243 * <td>Called when the size of this view has changed. 244 * </td> 245 * </tr> 246 * 247 * <tr> 248 * <td>Drawing</td> 249 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 250 * <td>Called when the view should render its content. 251 * </td> 252 * </tr> 253 * 254 * <tr> 255 * <td rowspan="4">Event processing</td> 256 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 257 * <td>Called when a new hardware key event occurs. 258 * </td> 259 * </tr> 260 * <tr> 261 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 262 * <td>Called when a hardware key up event occurs. 263 * </td> 264 * </tr> 265 * <tr> 266 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 267 * <td>Called when a trackball motion event occurs. 268 * </td> 269 * </tr> 270 * <tr> 271 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 272 * <td>Called when a touch screen motion event occurs. 273 * </td> 274 * </tr> 275 * 276 * <tr> 277 * <td rowspan="2">Focus</td> 278 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 279 * <td>Called when the view gains or loses focus. 280 * </td> 281 * </tr> 282 * 283 * <tr> 284 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 285 * <td>Called when the window containing the view gains or loses focus. 286 * </td> 287 * </tr> 288 * 289 * <tr> 290 * <td rowspan="3">Attaching</td> 291 * <td><code>{@link #onAttachedToWindow()}</code></td> 292 * <td>Called when the view is attached to a window. 293 * </td> 294 * </tr> 295 * 296 * <tr> 297 * <td><code>{@link #onDetachedFromWindow}</code></td> 298 * <td>Called when the view is detached from its window. 299 * </td> 300 * </tr> 301 * 302 * <tr> 303 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 304 * <td>Called when the visibility of the window containing the view 305 * has changed. 306 * </td> 307 * </tr> 308 * </tbody> 309 * 310 * </table> 311 * </p> 312 * 313 * <a name="IDs"></a> 314 * <h3>IDs</h3> 315 * Views may have an integer id associated with them. These ids are typically 316 * assigned in the layout XML files, and are used to find specific views within 317 * the view tree. A common pattern is to: 318 * <ul> 319 * <li>Define a Button in the layout file and assign it a unique ID. 320 * <pre> 321 * <Button 322 * android:id="@+id/my_button" 323 * android:layout_width="wrap_content" 324 * android:layout_height="wrap_content" 325 * android:text="@string/my_button_text"/> 326 * </pre></li> 327 * <li>From the onCreate method of an Activity, find the Button 328 * <pre class="prettyprint"> 329 * Button myButton = (Button) findViewById(R.id.my_button); 330 * </pre></li> 331 * </ul> 332 * <p> 333 * View IDs need not be unique throughout the tree, but it is good practice to 334 * ensure that they are at least unique within the part of the tree you are 335 * searching. 336 * </p> 337 * 338 * <a name="Position"></a> 339 * <h3>Position</h3> 340 * <p> 341 * The geometry of a view is that of a rectangle. A view has a location, 342 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 343 * two dimensions, expressed as a width and a height. The unit for location 344 * and dimensions is the pixel. 345 * </p> 346 * 347 * <p> 348 * It is possible to retrieve the location of a view by invoking the methods 349 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 350 * coordinate of the rectangle representing the view. The latter returns the 351 * top, or Y, coordinate of the rectangle representing the view. These methods 352 * both return the location of the view relative to its parent. For instance, 353 * when getLeft() returns 20, that means the view is located 20 pixels to the 354 * right of the left edge of its direct parent. 355 * </p> 356 * 357 * <p> 358 * In addition, several convenience methods are offered to avoid unnecessary 359 * computations, namely {@link #getRight()} and {@link #getBottom()}. 360 * These methods return the coordinates of the right and bottom edges of the 361 * rectangle representing the view. For instance, calling {@link #getRight()} 362 * is similar to the following computation: <code>getLeft() + getWidth()</code> 363 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 364 * </p> 365 * 366 * <a name="SizePaddingMargins"></a> 367 * <h3>Size, padding and margins</h3> 368 * <p> 369 * The size of a view is expressed with a width and a height. A view actually 370 * possess two pairs of width and height values. 371 * </p> 372 * 373 * <p> 374 * The first pair is known as <em>measured width</em> and 375 * <em>measured height</em>. These dimensions define how big a view wants to be 376 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 377 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 378 * and {@link #getMeasuredHeight()}. 379 * </p> 380 * 381 * <p> 382 * The second pair is simply known as <em>width</em> and <em>height</em>, or 383 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 384 * dimensions define the actual size of the view on screen, at drawing time and 385 * after layout. These values may, but do not have to, be different from the 386 * measured width and height. The width and height can be obtained by calling 387 * {@link #getWidth()} and {@link #getHeight()}. 388 * </p> 389 * 390 * <p> 391 * To measure its dimensions, a view takes into account its padding. The padding 392 * is expressed in pixels for the left, top, right and bottom parts of the view. 393 * Padding can be used to offset the content of the view by a specific amount of 394 * pixels. For instance, a left padding of 2 will push the view's content by 395 * 2 pixels to the right of the left edge. Padding can be set using the 396 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 397 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 398 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 399 * {@link #getPaddingEnd()}. 400 * </p> 401 * 402 * <p> 403 * Even though a view can define a padding, it does not provide any support for 404 * margins. However, view groups provide such a support. Refer to 405 * {@link android.view.ViewGroup} and 406 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 407 * </p> 408 * 409 * <a name="Layout"></a> 410 * <h3>Layout</h3> 411 * <p> 412 * Layout is a two pass process: a measure pass and a layout pass. The measuring 413 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 414 * of the view tree. Each view pushes dimension specifications down the tree 415 * during the recursion. At the end of the measure pass, every view has stored 416 * its measurements. The second pass happens in 417 * {@link #layout(int,int,int,int)} and is also top-down. During 418 * this pass each parent is responsible for positioning all of its children 419 * using the sizes computed in the measure pass. 420 * </p> 421 * 422 * <p> 423 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 424 * {@link #getMeasuredHeight()} values must be set, along with those for all of 425 * that view's descendants. A view's measured width and measured height values 426 * must respect the constraints imposed by the view's parents. This guarantees 427 * that at the end of the measure pass, all parents accept all of their 428 * children's measurements. A parent view may call measure() more than once on 429 * its children. For example, the parent may measure each child once with 430 * unspecified dimensions to find out how big they want to be, then call 431 * measure() on them again with actual numbers if the sum of all the children's 432 * unconstrained sizes is too big or too small. 433 * </p> 434 * 435 * <p> 436 * The measure pass uses two classes to communicate dimensions. The 437 * {@link MeasureSpec} class is used by views to tell their parents how they 438 * want to be measured and positioned. The base LayoutParams class just 439 * describes how big the view wants to be for both width and height. For each 440 * dimension, it can specify one of: 441 * <ul> 442 * <li> an exact number 443 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 444 * (minus padding) 445 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 446 * enclose its content (plus padding). 447 * </ul> 448 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 449 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 450 * an X and Y value. 451 * </p> 452 * 453 * <p> 454 * MeasureSpecs are used to push requirements down the tree from parent to 455 * child. A MeasureSpec can be in one of three modes: 456 * <ul> 457 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 458 * of a child view. For example, a LinearLayout may call measure() on its child 459 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 460 * tall the child view wants to be given a width of 240 pixels. 461 * <li>EXACTLY: This is used by the parent to impose an exact size on the 462 * child. The child must use this size, and guarantee that all of its 463 * descendants will fit within this size. 464 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 465 * child. The child must guarantee that it and all of its descendants will fit 466 * within this size. 467 * </ul> 468 * </p> 469 * 470 * <p> 471 * To initiate a layout, call {@link #requestLayout}. This method is typically 472 * called by a view on itself when it believes that is can no longer fit within 473 * its current bounds. 474 * </p> 475 * 476 * <a name="Drawing"></a> 477 * <h3>Drawing</h3> 478 * <p> 479 * Drawing is handled by walking the tree and recording the drawing commands of 480 * any View that needs to update. After this, the drawing commands of the 481 * entire tree are issued to screen, clipped to the newly damaged area. 482 * </p> 483 * 484 * <p> 485 * The tree is largely recorded and drawn in order, with parents drawn before 486 * (i.e., behind) their children, with siblings drawn in the order they appear 487 * in the tree. If you set a background drawable for a View, then the View will 488 * draw it before calling back to its <code>onDraw()</code> method. The child 489 * drawing order can be overridden with 490 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 491 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 492 * </p> 493 * 494 * <p> 495 * To force a view to draw, call {@link #invalidate()}. 496 * </p> 497 * 498 * <a name="EventHandlingThreading"></a> 499 * <h3>Event Handling and Threading</h3> 500 * <p> 501 * The basic cycle of a view is as follows: 502 * <ol> 503 * <li>An event comes in and is dispatched to the appropriate view. The view 504 * handles the event and notifies any listeners.</li> 505 * <li>If in the course of processing the event, the view's bounds may need 506 * to be changed, the view will call {@link #requestLayout()}.</li> 507 * <li>Similarly, if in the course of processing the event the view's appearance 508 * may need to be changed, the view will call {@link #invalidate()}.</li> 509 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 510 * the framework will take care of measuring, laying out, and drawing the tree 511 * as appropriate.</li> 512 * </ol> 513 * </p> 514 * 515 * <p><em>Note: The entire view tree is single threaded. You must always be on 516 * the UI thread when calling any method on any view.</em> 517 * If you are doing work on other threads and want to update the state of a view 518 * from that thread, you should use a {@link Handler}. 519 * </p> 520 * 521 * <a name="FocusHandling"></a> 522 * <h3>Focus Handling</h3> 523 * <p> 524 * The framework will handle routine focus movement in response to user input. 525 * This includes changing the focus as views are removed or hidden, or as new 526 * views become available. Views indicate their willingness to take focus 527 * through the {@link #isFocusable} method. To change whether a view can take 528 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 529 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 530 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 531 * </p> 532 * <p> 533 * Focus movement is based on an algorithm which finds the nearest neighbor in a 534 * given direction. In rare cases, the default algorithm may not match the 535 * intended behavior of the developer. In these situations, you can provide 536 * explicit overrides by using these XML attributes in the layout file: 537 * <pre> 538 * nextFocusDown 539 * nextFocusLeft 540 * nextFocusRight 541 * nextFocusUp 542 * </pre> 543 * </p> 544 * 545 * 546 * <p> 547 * To get a particular view to take focus, call {@link #requestFocus()}. 548 * </p> 549 * 550 * <a name="TouchMode"></a> 551 * <h3>Touch Mode</h3> 552 * <p> 553 * When a user is navigating a user interface via directional keys such as a D-pad, it is 554 * necessary to give focus to actionable items such as buttons so the user can see 555 * what will take input. If the device has touch capabilities, however, and the user 556 * begins interacting with the interface by touching it, it is no longer necessary to 557 * always highlight, or give focus to, a particular view. This motivates a mode 558 * for interaction named 'touch mode'. 559 * </p> 560 * <p> 561 * For a touch capable device, once the user touches the screen, the device 562 * will enter touch mode. From this point onward, only views for which 563 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 564 * Other views that are touchable, like buttons, will not take focus when touched; they will 565 * only fire the on click listeners. 566 * </p> 567 * <p> 568 * Any time a user hits a directional key, such as a D-pad direction, the view device will 569 * exit touch mode, and find a view to take focus, so that the user may resume interacting 570 * with the user interface without touching the screen again. 571 * </p> 572 * <p> 573 * The touch mode state is maintained across {@link android.app.Activity}s. Call 574 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 575 * </p> 576 * 577 * <a name="Scrolling"></a> 578 * <h3>Scrolling</h3> 579 * <p> 580 * The framework provides basic support for views that wish to internally 581 * scroll their content. This includes keeping track of the X and Y scroll 582 * offset as well as mechanisms for drawing scrollbars. See 583 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 584 * {@link #awakenScrollBars()} for more details. 585 * </p> 586 * 587 * <a name="Tags"></a> 588 * <h3>Tags</h3> 589 * <p> 590 * Unlike IDs, tags are not used to identify views. Tags are essentially an 591 * extra piece of information that can be associated with a view. They are most 592 * often used as a convenience to store data related to views in the views 593 * themselves rather than by putting them in a separate structure. 594 * </p> 595 * <p> 596 * Tags may be specified with character sequence values in layout XML as either 597 * a single tag using the {@link android.R.styleable#View_tag android:tag} 598 * attribute or multiple tags using the {@code <tag>} child element: 599 * <pre> 600 * <View ... 601 * android:tag="@string/mytag_value" /> 602 * <View ...> 603 * <tag android:id="@+id/mytag" 604 * android:value="@string/mytag_value" /> 605 * </View> 606 * </pre> 607 * </p> 608 * <p> 609 * Tags may also be specified with arbitrary objects from code using 610 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 611 * </p> 612 * 613 * <a name="Themes"></a> 614 * <h3>Themes</h3> 615 * <p> 616 * By default, Views are created using the theme of the Context object supplied 617 * to their constructor; however, a different theme may be specified by using 618 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 619 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 620 * code. 621 * </p> 622 * <p> 623 * When the {@link android.R.styleable#View_theme android:theme} attribute is 624 * used in XML, the specified theme is applied on top of the inflation 625 * context's theme (see {@link LayoutInflater}) and used for the view itself as 626 * well as any child elements. 627 * </p> 628 * <p> 629 * In the following example, both views will be created using the Material dark 630 * color scheme; however, because an overlay theme is used which only defines a 631 * subset of attributes, the value of 632 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 633 * the inflation context's theme (e.g. the Activity theme) will be preserved. 634 * <pre> 635 * <LinearLayout 636 * ... 637 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 638 * <View ...> 639 * </LinearLayout> 640 * </pre> 641 * </p> 642 * 643 * <a name="Properties"></a> 644 * <h3>Properties</h3> 645 * <p> 646 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 647 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 648 * available both in the {@link Property} form as well as in similarly-named setter/getter 649 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 650 * be used to set persistent state associated with these rendering-related properties on the view. 651 * The properties and methods can also be used in conjunction with 652 * {@link android.animation.Animator Animator}-based animations, described more in the 653 * <a href="#Animation">Animation</a> section. 654 * </p> 655 * 656 * <a name="Animation"></a> 657 * <h3>Animation</h3> 658 * <p> 659 * Starting with Android 3.0, the preferred way of animating views is to use the 660 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 661 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 662 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 663 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 664 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 665 * makes animating these View properties particularly easy and efficient. 666 * </p> 667 * <p> 668 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 669 * You can attach an {@link Animation} object to a view using 670 * {@link #setAnimation(Animation)} or 671 * {@link #startAnimation(Animation)}. The animation can alter the scale, 672 * rotation, translation and alpha of a view over time. If the animation is 673 * attached to a view that has children, the animation will affect the entire 674 * subtree rooted by that node. When an animation is started, the framework will 675 * take care of redrawing the appropriate views until the animation completes. 676 * </p> 677 * 678 * <a name="Security"></a> 679 * <h3>Security</h3> 680 * <p> 681 * Sometimes it is essential that an application be able to verify that an action 682 * is being performed with the full knowledge and consent of the user, such as 683 * granting a permission request, making a purchase or clicking on an advertisement. 684 * Unfortunately, a malicious application could try to spoof the user into 685 * performing these actions, unaware, by concealing the intended purpose of the view. 686 * As a remedy, the framework offers a touch filtering mechanism that can be used to 687 * improve the security of views that provide access to sensitive functionality. 688 * </p><p> 689 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 690 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 691 * will discard touches that are received whenever the view's window is obscured by 692 * another visible window. As a result, the view will not receive touches whenever a 693 * toast, dialog or other window appears above the view's window. 694 * </p><p> 695 * For more fine-grained control over security, consider overriding the 696 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 697 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 698 * </p> 699 * 700 * @attr ref android.R.styleable#View_alpha 701 * @attr ref android.R.styleable#View_background 702 * @attr ref android.R.styleable#View_clickable 703 * @attr ref android.R.styleable#View_contentDescription 704 * @attr ref android.R.styleable#View_drawingCacheQuality 705 * @attr ref android.R.styleable#View_duplicateParentState 706 * @attr ref android.R.styleable#View_id 707 * @attr ref android.R.styleable#View_requiresFadingEdge 708 * @attr ref android.R.styleable#View_fadeScrollbars 709 * @attr ref android.R.styleable#View_fadingEdgeLength 710 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 711 * @attr ref android.R.styleable#View_fitsSystemWindows 712 * @attr ref android.R.styleable#View_isScrollContainer 713 * @attr ref android.R.styleable#View_focusable 714 * @attr ref android.R.styleable#View_focusableInTouchMode 715 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 716 * @attr ref android.R.styleable#View_keepScreenOn 717 * @attr ref android.R.styleable#View_layerType 718 * @attr ref android.R.styleable#View_layoutDirection 719 * @attr ref android.R.styleable#View_longClickable 720 * @attr ref android.R.styleable#View_minHeight 721 * @attr ref android.R.styleable#View_minWidth 722 * @attr ref android.R.styleable#View_nextFocusDown 723 * @attr ref android.R.styleable#View_nextFocusLeft 724 * @attr ref android.R.styleable#View_nextFocusRight 725 * @attr ref android.R.styleable#View_nextFocusUp 726 * @attr ref android.R.styleable#View_onClick 727 * @attr ref android.R.styleable#View_padding 728 * @attr ref android.R.styleable#View_paddingBottom 729 * @attr ref android.R.styleable#View_paddingLeft 730 * @attr ref android.R.styleable#View_paddingRight 731 * @attr ref android.R.styleable#View_paddingTop 732 * @attr ref android.R.styleable#View_paddingStart 733 * @attr ref android.R.styleable#View_paddingEnd 734 * @attr ref android.R.styleable#View_saveEnabled 735 * @attr ref android.R.styleable#View_rotation 736 * @attr ref android.R.styleable#View_rotationX 737 * @attr ref android.R.styleable#View_rotationY 738 * @attr ref android.R.styleable#View_scaleX 739 * @attr ref android.R.styleable#View_scaleY 740 * @attr ref android.R.styleable#View_scrollX 741 * @attr ref android.R.styleable#View_scrollY 742 * @attr ref android.R.styleable#View_scrollbarSize 743 * @attr ref android.R.styleable#View_scrollbarStyle 744 * @attr ref android.R.styleable#View_scrollbars 745 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 746 * @attr ref android.R.styleable#View_scrollbarFadeDuration 747 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 748 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 749 * @attr ref android.R.styleable#View_scrollbarThumbVertical 750 * @attr ref android.R.styleable#View_scrollbarTrackVertical 751 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 752 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 753 * @attr ref android.R.styleable#View_stateListAnimator 754 * @attr ref android.R.styleable#View_transitionName 755 * @attr ref android.R.styleable#View_soundEffectsEnabled 756 * @attr ref android.R.styleable#View_tag 757 * @attr ref android.R.styleable#View_textAlignment 758 * @attr ref android.R.styleable#View_textDirection 759 * @attr ref android.R.styleable#View_transformPivotX 760 * @attr ref android.R.styleable#View_transformPivotY 761 * @attr ref android.R.styleable#View_translationX 762 * @attr ref android.R.styleable#View_translationY 763 * @attr ref android.R.styleable#View_translationZ 764 * @attr ref android.R.styleable#View_visibility 765 * @attr ref android.R.styleable#View_theme 766 * 767 * @see android.view.ViewGroup 768 */ 769@UiThread 770public class View implements Drawable.Callback, KeyEvent.Callback, 771 AccessibilityEventSource { 772 private static final boolean DBG = false; 773 774 /** @hide */ 775 public static boolean DEBUG_DRAW = false; 776 777 /** 778 * The logging tag used by this class with android.util.Log. 779 */ 780 protected static final String VIEW_LOG_TAG = "View"; 781 782 /** 783 * When set to true, apps will draw debugging information about their layouts. 784 * 785 * @hide 786 */ 787 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 788 789 /** 790 * When set to true, this view will save its attribute data. 791 * 792 * @hide 793 */ 794 public static boolean mDebugViewAttributes = false; 795 796 /** 797 * Used to mark a View that has no ID. 798 */ 799 public static final int NO_ID = -1; 800 801 /** 802 * Signals that compatibility booleans have been initialized according to 803 * target SDK versions. 804 */ 805 private static boolean sCompatibilityDone = false; 806 807 /** 808 * Use the old (broken) way of building MeasureSpecs. 809 */ 810 private static boolean sUseBrokenMakeMeasureSpec = false; 811 812 /** 813 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 814 */ 815 static boolean sUseZeroUnspecifiedMeasureSpec = false; 816 817 /** 818 * Ignore any optimizations using the measure cache. 819 */ 820 private static boolean sIgnoreMeasureCache = false; 821 822 /** 823 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 824 */ 825 private static boolean sAlwaysRemeasureExactly = false; 826 827 /** 828 * Relax constraints around whether setLayoutParams() must be called after 829 * modifying the layout params. 830 */ 831 private static boolean sLayoutParamsAlwaysChanged = false; 832 833 /** 834 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 835 * without throwing 836 */ 837 static boolean sTextureViewIgnoresDrawableSetters = false; 838 839 /** 840 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 841 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 842 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 843 * check is implemented for backwards compatibility. 844 * 845 * {@hide} 846 */ 847 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 848 849 /** 850 * Prior to N, when drag enters into child of a view that has already received an 851 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 852 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 853 * false from its event handler for these events. 854 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 855 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 856 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 857 */ 858 static boolean sCascadedDragDrop; 859 860 /** @hide */ 861 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 862 @Retention(RetentionPolicy.SOURCE) 863 public @interface Focusable {} 864 865 /** 866 * This view does not want keystrokes. 867 * <p> 868 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 869 * android:focusable}. 870 */ 871 public static final int NOT_FOCUSABLE = 0x00000000; 872 873 /** 874 * This view wants keystrokes. 875 * <p> 876 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 877 * android:focusable}. 878 */ 879 public static final int FOCUSABLE = 0x00000001; 880 881 /** 882 * This view determines focusability automatically. This is the default. 883 * <p> 884 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 885 * android:focusable}. 886 */ 887 public static final int FOCUSABLE_AUTO = 0x00000010; 888 889 /** 890 * Mask for use with setFlags indicating bits used for focus. 891 */ 892 private static final int FOCUSABLE_MASK = 0x00000011; 893 894 /** 895 * This view will adjust its padding to fit sytem windows (e.g. status bar) 896 */ 897 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 898 899 /** @hide */ 900 @IntDef({VISIBLE, INVISIBLE, GONE}) 901 @Retention(RetentionPolicy.SOURCE) 902 public @interface Visibility {} 903 904 /** 905 * This view is visible. 906 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 907 * android:visibility}. 908 */ 909 public static final int VISIBLE = 0x00000000; 910 911 /** 912 * This view is invisible, but it still takes up space for layout purposes. 913 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 914 * android:visibility}. 915 */ 916 public static final int INVISIBLE = 0x00000004; 917 918 /** 919 * This view is invisible, and it doesn't take any space for layout 920 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 921 * android:visibility}. 922 */ 923 public static final int GONE = 0x00000008; 924 925 /** 926 * Mask for use with setFlags indicating bits used for visibility. 927 * {@hide} 928 */ 929 static final int VISIBILITY_MASK = 0x0000000C; 930 931 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 932 933 /** 934 * This view is enabled. Interpretation varies by subclass. 935 * Use with ENABLED_MASK when calling setFlags. 936 * {@hide} 937 */ 938 static final int ENABLED = 0x00000000; 939 940 /** 941 * This view is disabled. Interpretation varies by subclass. 942 * Use with ENABLED_MASK when calling setFlags. 943 * {@hide} 944 */ 945 static final int DISABLED = 0x00000020; 946 947 /** 948 * Mask for use with setFlags indicating bits used for indicating whether 949 * this view is enabled 950 * {@hide} 951 */ 952 static final int ENABLED_MASK = 0x00000020; 953 954 /** 955 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 956 * called and further optimizations will be performed. It is okay to have 957 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 958 * {@hide} 959 */ 960 static final int WILL_NOT_DRAW = 0x00000080; 961 962 /** 963 * Mask for use with setFlags indicating bits used for indicating whether 964 * this view is will draw 965 * {@hide} 966 */ 967 static final int DRAW_MASK = 0x00000080; 968 969 /** 970 * <p>This view doesn't show scrollbars.</p> 971 * {@hide} 972 */ 973 static final int SCROLLBARS_NONE = 0x00000000; 974 975 /** 976 * <p>This view shows horizontal scrollbars.</p> 977 * {@hide} 978 */ 979 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 980 981 /** 982 * <p>This view shows vertical scrollbars.</p> 983 * {@hide} 984 */ 985 static final int SCROLLBARS_VERTICAL = 0x00000200; 986 987 /** 988 * <p>Mask for use with setFlags indicating bits used for indicating which 989 * scrollbars are enabled.</p> 990 * {@hide} 991 */ 992 static final int SCROLLBARS_MASK = 0x00000300; 993 994 /** 995 * Indicates that the view should filter touches when its window is obscured. 996 * Refer to the class comments for more information about this security feature. 997 * {@hide} 998 */ 999 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1000 1001 /** 1002 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1003 * that they are optional and should be skipped if the window has 1004 * requested system UI flags that ignore those insets for layout. 1005 */ 1006 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1007 1008 /** 1009 * <p>This view doesn't show fading edges.</p> 1010 * {@hide} 1011 */ 1012 static final int FADING_EDGE_NONE = 0x00000000; 1013 1014 /** 1015 * <p>This view shows horizontal fading edges.</p> 1016 * {@hide} 1017 */ 1018 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1019 1020 /** 1021 * <p>This view shows vertical fading edges.</p> 1022 * {@hide} 1023 */ 1024 static final int FADING_EDGE_VERTICAL = 0x00002000; 1025 1026 /** 1027 * <p>Mask for use with setFlags indicating bits used for indicating which 1028 * fading edges are enabled.</p> 1029 * {@hide} 1030 */ 1031 static final int FADING_EDGE_MASK = 0x00003000; 1032 1033 /** 1034 * <p>Indicates this view can be clicked. When clickable, a View reacts 1035 * to clicks by notifying the OnClickListener.<p> 1036 * {@hide} 1037 */ 1038 static final int CLICKABLE = 0x00004000; 1039 1040 /** 1041 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1042 * {@hide} 1043 */ 1044 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1045 1046 /** 1047 * <p>Indicates that no icicle should be saved for this view.<p> 1048 * {@hide} 1049 */ 1050 static final int SAVE_DISABLED = 0x000010000; 1051 1052 /** 1053 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1054 * property.</p> 1055 * {@hide} 1056 */ 1057 static final int SAVE_DISABLED_MASK = 0x000010000; 1058 1059 /** 1060 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1061 * {@hide} 1062 */ 1063 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1064 1065 /** 1066 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1067 * {@hide} 1068 */ 1069 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1070 1071 /** @hide */ 1072 @Retention(RetentionPolicy.SOURCE) 1073 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1074 public @interface DrawingCacheQuality {} 1075 1076 /** 1077 * <p>Enables low quality mode for the drawing cache.</p> 1078 */ 1079 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1080 1081 /** 1082 * <p>Enables high quality mode for the drawing cache.</p> 1083 */ 1084 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1085 1086 /** 1087 * <p>Enables automatic quality mode for the drawing cache.</p> 1088 */ 1089 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1090 1091 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1092 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1093 }; 1094 1095 /** 1096 * <p>Mask for use with setFlags indicating bits used for the cache 1097 * quality property.</p> 1098 * {@hide} 1099 */ 1100 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1101 1102 /** 1103 * <p> 1104 * Indicates this view can be long clicked. When long clickable, a View 1105 * reacts to long clicks by notifying the OnLongClickListener or showing a 1106 * context menu. 1107 * </p> 1108 * {@hide} 1109 */ 1110 static final int LONG_CLICKABLE = 0x00200000; 1111 1112 /** 1113 * <p>Indicates that this view gets its drawable states from its direct parent 1114 * and ignores its original internal states.</p> 1115 * 1116 * @hide 1117 */ 1118 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1119 1120 /** 1121 * <p> 1122 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1123 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1124 * OnContextClickListener. 1125 * </p> 1126 * {@hide} 1127 */ 1128 static final int CONTEXT_CLICKABLE = 0x00800000; 1129 1130 1131 /** @hide */ 1132 @IntDef({ 1133 SCROLLBARS_INSIDE_OVERLAY, 1134 SCROLLBARS_INSIDE_INSET, 1135 SCROLLBARS_OUTSIDE_OVERLAY, 1136 SCROLLBARS_OUTSIDE_INSET 1137 }) 1138 @Retention(RetentionPolicy.SOURCE) 1139 public @interface ScrollBarStyle {} 1140 1141 /** 1142 * The scrollbar style to display the scrollbars inside the content area, 1143 * without increasing the padding. The scrollbars will be overlaid with 1144 * translucency on the view's content. 1145 */ 1146 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1147 1148 /** 1149 * The scrollbar style to display the scrollbars inside the padded area, 1150 * increasing the padding of the view. The scrollbars will not overlap the 1151 * content area of the view. 1152 */ 1153 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1154 1155 /** 1156 * The scrollbar style to display the scrollbars at the edge of the view, 1157 * without increasing the padding. The scrollbars will be overlaid with 1158 * translucency. 1159 */ 1160 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1161 1162 /** 1163 * The scrollbar style to display the scrollbars at the edge of the view, 1164 * increasing the padding of the view. The scrollbars will only overlap the 1165 * background, if any. 1166 */ 1167 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1168 1169 /** 1170 * Mask to check if the scrollbar style is overlay or inset. 1171 * {@hide} 1172 */ 1173 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1174 1175 /** 1176 * Mask to check if the scrollbar style is inside or outside. 1177 * {@hide} 1178 */ 1179 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1180 1181 /** 1182 * Mask for scrollbar style. 1183 * {@hide} 1184 */ 1185 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1186 1187 /** 1188 * View flag indicating that the screen should remain on while the 1189 * window containing this view is visible to the user. This effectively 1190 * takes care of automatically setting the WindowManager's 1191 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1192 */ 1193 public static final int KEEP_SCREEN_ON = 0x04000000; 1194 1195 /** 1196 * View flag indicating whether this view should have sound effects enabled 1197 * for events such as clicking and touching. 1198 */ 1199 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1200 1201 /** 1202 * View flag indicating whether this view should have haptic feedback 1203 * enabled for events such as long presses. 1204 */ 1205 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1206 1207 /** 1208 * <p>Indicates that the view hierarchy should stop saving state when 1209 * it reaches this view. If state saving is initiated immediately at 1210 * the view, it will be allowed. 1211 * {@hide} 1212 */ 1213 static final int PARENT_SAVE_DISABLED = 0x20000000; 1214 1215 /** 1216 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1217 * {@hide} 1218 */ 1219 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1220 1221 private static Paint sDebugPaint; 1222 1223 /** 1224 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1225 * {@hide} 1226 */ 1227 static final int TOOLTIP = 0x40000000; 1228 1229 /** @hide */ 1230 @IntDef(flag = true, 1231 value = { 1232 FOCUSABLES_ALL, 1233 FOCUSABLES_TOUCH_MODE 1234 }) 1235 @Retention(RetentionPolicy.SOURCE) 1236 public @interface FocusableMode {} 1237 1238 /** 1239 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1240 * should add all focusable Views regardless if they are focusable in touch mode. 1241 */ 1242 public static final int FOCUSABLES_ALL = 0x00000000; 1243 1244 /** 1245 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1246 * should add only Views focusable in touch mode. 1247 */ 1248 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1249 1250 /** @hide */ 1251 @IntDef({ 1252 FOCUS_BACKWARD, 1253 FOCUS_FORWARD, 1254 FOCUS_LEFT, 1255 FOCUS_UP, 1256 FOCUS_RIGHT, 1257 FOCUS_DOWN 1258 }) 1259 @Retention(RetentionPolicy.SOURCE) 1260 public @interface FocusDirection {} 1261 1262 /** @hide */ 1263 @IntDef({ 1264 FOCUS_LEFT, 1265 FOCUS_UP, 1266 FOCUS_RIGHT, 1267 FOCUS_DOWN 1268 }) 1269 @Retention(RetentionPolicy.SOURCE) 1270 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1271 1272 /** 1273 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1274 * item. 1275 */ 1276 public static final int FOCUS_BACKWARD = 0x00000001; 1277 1278 /** 1279 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1280 * item. 1281 */ 1282 public static final int FOCUS_FORWARD = 0x00000002; 1283 1284 /** 1285 * Use with {@link #focusSearch(int)}. Move focus to the left. 1286 */ 1287 public static final int FOCUS_LEFT = 0x00000011; 1288 1289 /** 1290 * Use with {@link #focusSearch(int)}. Move focus up. 1291 */ 1292 public static final int FOCUS_UP = 0x00000021; 1293 1294 /** 1295 * Use with {@link #focusSearch(int)}. Move focus to the right. 1296 */ 1297 public static final int FOCUS_RIGHT = 0x00000042; 1298 1299 /** 1300 * Use with {@link #focusSearch(int)}. Move focus down. 1301 */ 1302 public static final int FOCUS_DOWN = 0x00000082; 1303 1304 /** 1305 * Bits of {@link #getMeasuredWidthAndState()} and 1306 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1307 */ 1308 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1309 1310 /** 1311 * Bits of {@link #getMeasuredWidthAndState()} and 1312 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1313 */ 1314 public static final int MEASURED_STATE_MASK = 0xff000000; 1315 1316 /** 1317 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1318 * for functions that combine both width and height into a single int, 1319 * such as {@link #getMeasuredState()} and the childState argument of 1320 * {@link #resolveSizeAndState(int, int, int)}. 1321 */ 1322 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1323 1324 /** 1325 * Bit of {@link #getMeasuredWidthAndState()} and 1326 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1327 * is smaller that the space the view would like to have. 1328 */ 1329 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1330 1331 /** 1332 * Base View state sets 1333 */ 1334 // Singles 1335 /** 1336 * Indicates the view has no states set. States are used with 1337 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1338 * view depending on its state. 1339 * 1340 * @see android.graphics.drawable.Drawable 1341 * @see #getDrawableState() 1342 */ 1343 protected static final int[] EMPTY_STATE_SET; 1344 /** 1345 * Indicates the view is enabled. States are used with 1346 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1347 * view depending on its state. 1348 * 1349 * @see android.graphics.drawable.Drawable 1350 * @see #getDrawableState() 1351 */ 1352 protected static final int[] ENABLED_STATE_SET; 1353 /** 1354 * Indicates the view is focused. States are used with 1355 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1356 * view depending on its state. 1357 * 1358 * @see android.graphics.drawable.Drawable 1359 * @see #getDrawableState() 1360 */ 1361 protected static final int[] FOCUSED_STATE_SET; 1362 /** 1363 * Indicates the view is selected. States are used with 1364 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1365 * view depending on its state. 1366 * 1367 * @see android.graphics.drawable.Drawable 1368 * @see #getDrawableState() 1369 */ 1370 protected static final int[] SELECTED_STATE_SET; 1371 /** 1372 * Indicates the view is pressed. States are used with 1373 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1374 * view depending on its state. 1375 * 1376 * @see android.graphics.drawable.Drawable 1377 * @see #getDrawableState() 1378 */ 1379 protected static final int[] PRESSED_STATE_SET; 1380 /** 1381 * Indicates the view's window has focus. States are used with 1382 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1383 * view depending on its state. 1384 * 1385 * @see android.graphics.drawable.Drawable 1386 * @see #getDrawableState() 1387 */ 1388 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1389 // Doubles 1390 /** 1391 * Indicates the view is enabled and has the focus. 1392 * 1393 * @see #ENABLED_STATE_SET 1394 * @see #FOCUSED_STATE_SET 1395 */ 1396 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1397 /** 1398 * Indicates the view is enabled and selected. 1399 * 1400 * @see #ENABLED_STATE_SET 1401 * @see #SELECTED_STATE_SET 1402 */ 1403 protected static final int[] ENABLED_SELECTED_STATE_SET; 1404 /** 1405 * Indicates the view is enabled and that its window has focus. 1406 * 1407 * @see #ENABLED_STATE_SET 1408 * @see #WINDOW_FOCUSED_STATE_SET 1409 */ 1410 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1411 /** 1412 * Indicates the view is focused and selected. 1413 * 1414 * @see #FOCUSED_STATE_SET 1415 * @see #SELECTED_STATE_SET 1416 */ 1417 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1418 /** 1419 * Indicates the view has the focus and that its window has the focus. 1420 * 1421 * @see #FOCUSED_STATE_SET 1422 * @see #WINDOW_FOCUSED_STATE_SET 1423 */ 1424 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1425 /** 1426 * Indicates the view is selected and that its window has the focus. 1427 * 1428 * @see #SELECTED_STATE_SET 1429 * @see #WINDOW_FOCUSED_STATE_SET 1430 */ 1431 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1432 // Triples 1433 /** 1434 * Indicates the view is enabled, focused and selected. 1435 * 1436 * @see #ENABLED_STATE_SET 1437 * @see #FOCUSED_STATE_SET 1438 * @see #SELECTED_STATE_SET 1439 */ 1440 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1441 /** 1442 * Indicates the view is enabled, focused and its window has the focus. 1443 * 1444 * @see #ENABLED_STATE_SET 1445 * @see #FOCUSED_STATE_SET 1446 * @see #WINDOW_FOCUSED_STATE_SET 1447 */ 1448 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1449 /** 1450 * Indicates the view is enabled, selected and its window has the focus. 1451 * 1452 * @see #ENABLED_STATE_SET 1453 * @see #SELECTED_STATE_SET 1454 * @see #WINDOW_FOCUSED_STATE_SET 1455 */ 1456 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1457 /** 1458 * Indicates the view is focused, selected and its window has the focus. 1459 * 1460 * @see #FOCUSED_STATE_SET 1461 * @see #SELECTED_STATE_SET 1462 * @see #WINDOW_FOCUSED_STATE_SET 1463 */ 1464 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1465 /** 1466 * Indicates the view is enabled, focused, selected and its window 1467 * has the focus. 1468 * 1469 * @see #ENABLED_STATE_SET 1470 * @see #FOCUSED_STATE_SET 1471 * @see #SELECTED_STATE_SET 1472 * @see #WINDOW_FOCUSED_STATE_SET 1473 */ 1474 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1475 /** 1476 * Indicates the view is pressed and its window has the focus. 1477 * 1478 * @see #PRESSED_STATE_SET 1479 * @see #WINDOW_FOCUSED_STATE_SET 1480 */ 1481 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1482 /** 1483 * Indicates the view is pressed and selected. 1484 * 1485 * @see #PRESSED_STATE_SET 1486 * @see #SELECTED_STATE_SET 1487 */ 1488 protected static final int[] PRESSED_SELECTED_STATE_SET; 1489 /** 1490 * Indicates the view is pressed, selected and its window has the focus. 1491 * 1492 * @see #PRESSED_STATE_SET 1493 * @see #SELECTED_STATE_SET 1494 * @see #WINDOW_FOCUSED_STATE_SET 1495 */ 1496 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1497 /** 1498 * Indicates the view is pressed and focused. 1499 * 1500 * @see #PRESSED_STATE_SET 1501 * @see #FOCUSED_STATE_SET 1502 */ 1503 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1504 /** 1505 * Indicates the view is pressed, focused and its window has the focus. 1506 * 1507 * @see #PRESSED_STATE_SET 1508 * @see #FOCUSED_STATE_SET 1509 * @see #WINDOW_FOCUSED_STATE_SET 1510 */ 1511 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1512 /** 1513 * Indicates the view is pressed, focused and selected. 1514 * 1515 * @see #PRESSED_STATE_SET 1516 * @see #SELECTED_STATE_SET 1517 * @see #FOCUSED_STATE_SET 1518 */ 1519 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1520 /** 1521 * Indicates the view is pressed, focused, selected and its window has the focus. 1522 * 1523 * @see #PRESSED_STATE_SET 1524 * @see #FOCUSED_STATE_SET 1525 * @see #SELECTED_STATE_SET 1526 * @see #WINDOW_FOCUSED_STATE_SET 1527 */ 1528 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1529 /** 1530 * Indicates the view is pressed and enabled. 1531 * 1532 * @see #PRESSED_STATE_SET 1533 * @see #ENABLED_STATE_SET 1534 */ 1535 protected static final int[] PRESSED_ENABLED_STATE_SET; 1536 /** 1537 * Indicates the view is pressed, enabled and its window has the focus. 1538 * 1539 * @see #PRESSED_STATE_SET 1540 * @see #ENABLED_STATE_SET 1541 * @see #WINDOW_FOCUSED_STATE_SET 1542 */ 1543 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1544 /** 1545 * Indicates the view is pressed, enabled and selected. 1546 * 1547 * @see #PRESSED_STATE_SET 1548 * @see #ENABLED_STATE_SET 1549 * @see #SELECTED_STATE_SET 1550 */ 1551 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1552 /** 1553 * Indicates the view is pressed, enabled, selected and its window has the 1554 * focus. 1555 * 1556 * @see #PRESSED_STATE_SET 1557 * @see #ENABLED_STATE_SET 1558 * @see #SELECTED_STATE_SET 1559 * @see #WINDOW_FOCUSED_STATE_SET 1560 */ 1561 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1562 /** 1563 * Indicates the view is pressed, enabled and focused. 1564 * 1565 * @see #PRESSED_STATE_SET 1566 * @see #ENABLED_STATE_SET 1567 * @see #FOCUSED_STATE_SET 1568 */ 1569 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1570 /** 1571 * Indicates the view is pressed, enabled, focused and its window has the 1572 * focus. 1573 * 1574 * @see #PRESSED_STATE_SET 1575 * @see #ENABLED_STATE_SET 1576 * @see #FOCUSED_STATE_SET 1577 * @see #WINDOW_FOCUSED_STATE_SET 1578 */ 1579 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1580 /** 1581 * Indicates the view is pressed, enabled, focused and selected. 1582 * 1583 * @see #PRESSED_STATE_SET 1584 * @see #ENABLED_STATE_SET 1585 * @see #SELECTED_STATE_SET 1586 * @see #FOCUSED_STATE_SET 1587 */ 1588 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1589 /** 1590 * Indicates the view is pressed, enabled, focused, selected and its window 1591 * has the focus. 1592 * 1593 * @see #PRESSED_STATE_SET 1594 * @see #ENABLED_STATE_SET 1595 * @see #SELECTED_STATE_SET 1596 * @see #FOCUSED_STATE_SET 1597 * @see #WINDOW_FOCUSED_STATE_SET 1598 */ 1599 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1600 1601 static { 1602 EMPTY_STATE_SET = StateSet.get(0); 1603 1604 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1605 1606 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1607 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1608 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1609 1610 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1611 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1612 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1613 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1614 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1615 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1616 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1617 | StateSet.VIEW_STATE_FOCUSED); 1618 1619 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1620 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1621 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1622 ENABLED_SELECTED_STATE_SET = StateSet.get( 1623 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1624 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1625 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1626 | StateSet.VIEW_STATE_ENABLED); 1627 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1628 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1629 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1630 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1631 | StateSet.VIEW_STATE_ENABLED); 1632 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1633 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1634 | StateSet.VIEW_STATE_ENABLED); 1635 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1636 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1637 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1638 1639 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1640 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1641 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1642 PRESSED_SELECTED_STATE_SET = StateSet.get( 1643 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1644 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1645 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1646 | StateSet.VIEW_STATE_PRESSED); 1647 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1648 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1649 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1650 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1651 | StateSet.VIEW_STATE_PRESSED); 1652 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1653 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1654 | StateSet.VIEW_STATE_PRESSED); 1655 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1656 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1657 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1658 PRESSED_ENABLED_STATE_SET = StateSet.get( 1659 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1660 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1661 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1662 | StateSet.VIEW_STATE_PRESSED); 1663 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1664 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1665 | StateSet.VIEW_STATE_PRESSED); 1666 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1667 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1668 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1669 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 1670 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 1671 | StateSet.VIEW_STATE_PRESSED); 1672 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1673 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1674 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1675 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1676 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1677 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1678 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1679 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1680 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 1681 | StateSet.VIEW_STATE_PRESSED); 1682 } 1683 1684 /** 1685 * Accessibility event types that are dispatched for text population. 1686 */ 1687 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 1688 AccessibilityEvent.TYPE_VIEW_CLICKED 1689 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 1690 | AccessibilityEvent.TYPE_VIEW_SELECTED 1691 | AccessibilityEvent.TYPE_VIEW_FOCUSED 1692 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 1693 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 1694 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 1695 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 1696 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 1697 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 1698 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 1699 1700 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 1701 1702 static final int DEBUG_CORNERS_SIZE_DIP = 8; 1703 1704 /** 1705 * Temporary Rect currently for use in setBackground(). This will probably 1706 * be extended in the future to hold our own class with more than just 1707 * a Rect. :) 1708 */ 1709 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 1710 1711 /** 1712 * Map used to store views' tags. 1713 */ 1714 private SparseArray<Object> mKeyedTags; 1715 1716 /** 1717 * The next available accessibility id. 1718 */ 1719 private static int sNextAccessibilityViewId; 1720 1721 /** 1722 * The animation currently associated with this view. 1723 * @hide 1724 */ 1725 protected Animation mCurrentAnimation = null; 1726 1727 /** 1728 * Width as measured during measure pass. 1729 * {@hide} 1730 */ 1731 @ViewDebug.ExportedProperty(category = "measurement") 1732 int mMeasuredWidth; 1733 1734 /** 1735 * Height as measured during measure pass. 1736 * {@hide} 1737 */ 1738 @ViewDebug.ExportedProperty(category = "measurement") 1739 int mMeasuredHeight; 1740 1741 /** 1742 * Flag to indicate that this view was marked INVALIDATED, or had its display list 1743 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 1744 * its display list. This flag, used only when hw accelerated, allows us to clear the 1745 * flag while retaining this information until it's needed (at getDisplayList() time and 1746 * in drawChild(), when we decide to draw a view's children's display lists into our own). 1747 * 1748 * {@hide} 1749 */ 1750 boolean mRecreateDisplayList = false; 1751 1752 /** 1753 * The view's identifier. 1754 * {@hide} 1755 * 1756 * @see #setId(int) 1757 * @see #getId() 1758 */ 1759 @IdRes 1760 @ViewDebug.ExportedProperty(resolveId = true) 1761 int mID = NO_ID; 1762 1763 /** 1764 * The stable ID of this view for accessibility purposes. 1765 */ 1766 int mAccessibilityViewId = NO_ID; 1767 1768 /** 1769 * The stable ID of this view for auto-fill purposes. 1770 */ 1771 private int mAutoFillId = NO_ID; 1772 1773 1774 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 1775 1776 SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent; 1777 1778 /** 1779 * The view's tag. 1780 * {@hide} 1781 * 1782 * @see #setTag(Object) 1783 * @see #getTag() 1784 */ 1785 protected Object mTag = null; 1786 1787 // for mPrivateFlags: 1788 /** {@hide} */ 1789 static final int PFLAG_WANTS_FOCUS = 0x00000001; 1790 /** {@hide} */ 1791 static final int PFLAG_FOCUSED = 0x00000002; 1792 /** {@hide} */ 1793 static final int PFLAG_SELECTED = 0x00000004; 1794 /** {@hide} */ 1795 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 1796 /** {@hide} */ 1797 static final int PFLAG_HAS_BOUNDS = 0x00000010; 1798 /** {@hide} */ 1799 static final int PFLAG_DRAWN = 0x00000020; 1800 /** 1801 * When this flag is set, this view is running an animation on behalf of its 1802 * children and should therefore not cancel invalidate requests, even if they 1803 * lie outside of this view's bounds. 1804 * 1805 * {@hide} 1806 */ 1807 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 1808 /** {@hide} */ 1809 static final int PFLAG_SKIP_DRAW = 0x00000080; 1810 /** {@hide} */ 1811 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 1812 /** {@hide} */ 1813 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 1814 /** {@hide} */ 1815 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 1816 /** {@hide} */ 1817 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 1818 /** {@hide} */ 1819 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 1820 1821 private static final int PFLAG_PRESSED = 0x00004000; 1822 1823 /** {@hide} */ 1824 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 1825 /** 1826 * Flag used to indicate that this view should be drawn once more (and only once 1827 * more) after its animation has completed. 1828 * {@hide} 1829 */ 1830 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 1831 1832 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 1833 1834 /** 1835 * Indicates that the View returned true when onSetAlpha() was called and that 1836 * the alpha must be restored. 1837 * {@hide} 1838 */ 1839 static final int PFLAG_ALPHA_SET = 0x00040000; 1840 1841 /** 1842 * Set by {@link #setScrollContainer(boolean)}. 1843 */ 1844 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 1845 1846 /** 1847 * Set by {@link #setScrollContainer(boolean)}. 1848 */ 1849 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 1850 1851 /** 1852 * View flag indicating whether this view was invalidated (fully or partially.) 1853 * 1854 * @hide 1855 */ 1856 static final int PFLAG_DIRTY = 0x00200000; 1857 1858 /** 1859 * View flag indicating whether this view was invalidated by an opaque 1860 * invalidate request. 1861 * 1862 * @hide 1863 */ 1864 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 1865 1866 /** 1867 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 1868 * 1869 * @hide 1870 */ 1871 static final int PFLAG_DIRTY_MASK = 0x00600000; 1872 1873 /** 1874 * Indicates whether the background is opaque. 1875 * 1876 * @hide 1877 */ 1878 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 1879 1880 /** 1881 * Indicates whether the scrollbars are opaque. 1882 * 1883 * @hide 1884 */ 1885 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 1886 1887 /** 1888 * Indicates whether the view is opaque. 1889 * 1890 * @hide 1891 */ 1892 static final int PFLAG_OPAQUE_MASK = 0x01800000; 1893 1894 /** 1895 * Indicates a prepressed state; 1896 * the short time between ACTION_DOWN and recognizing 1897 * a 'real' press. Prepressed is used to recognize quick taps 1898 * even when they are shorter than ViewConfiguration.getTapTimeout(). 1899 * 1900 * @hide 1901 */ 1902 private static final int PFLAG_PREPRESSED = 0x02000000; 1903 1904 /** 1905 * Indicates whether the view is temporarily detached. 1906 * 1907 * @hide 1908 */ 1909 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 1910 1911 /** 1912 * Indicates that we should awaken scroll bars once attached 1913 * 1914 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 1915 * during window attachment and it is no longer needed. Feel free to repurpose it. 1916 * 1917 * @hide 1918 */ 1919 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 1920 1921 /** 1922 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 1923 * @hide 1924 */ 1925 private static final int PFLAG_HOVERED = 0x10000000; 1926 1927 /** 1928 * no longer needed, should be reused 1929 */ 1930 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 1931 1932 /** {@hide} */ 1933 static final int PFLAG_ACTIVATED = 0x40000000; 1934 1935 /** 1936 * Indicates that this view was specifically invalidated, not just dirtied because some 1937 * child view was invalidated. The flag is used to determine when we need to recreate 1938 * a view's display list (as opposed to just returning a reference to its existing 1939 * display list). 1940 * 1941 * @hide 1942 */ 1943 static final int PFLAG_INVALIDATED = 0x80000000; 1944 1945 /** 1946 * Masks for mPrivateFlags2, as generated by dumpFlags(): 1947 * 1948 * |-------|-------|-------|-------| 1949 * 1 PFLAG2_DRAG_CAN_ACCEPT 1950 * 1 PFLAG2_DRAG_HOVERED 1951 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 1952 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 1953 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 1954 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 1955 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 1956 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 1957 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 1958 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 1959 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 1960 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 1961 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 1962 * 111 PFLAG2_TEXT_DIRECTION_MASK 1963 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 1964 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 1965 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 1966 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 1967 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 1968 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 1969 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 1970 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 1971 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 1972 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 1973 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 1974 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 1975 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 1976 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 1977 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 1978 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 1979 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 1980 * 1 PFLAG2_VIEW_QUICK_REJECTED 1981 * 1 PFLAG2_PADDING_RESOLVED 1982 * 1 PFLAG2_DRAWABLE_RESOLVED 1983 * 1 PFLAG2_HAS_TRANSIENT_STATE 1984 * |-------|-------|-------|-------| 1985 */ 1986 1987 /** 1988 * Indicates that this view has reported that it can accept the current drag's content. 1989 * Cleared when the drag operation concludes. 1990 * @hide 1991 */ 1992 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 1993 1994 /** 1995 * Indicates that this view is currently directly under the drag location in a 1996 * drag-and-drop operation involving content that it can accept. Cleared when 1997 * the drag exits the view, or when the drag operation concludes. 1998 * @hide 1999 */ 2000 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2001 2002 /** @hide */ 2003 @IntDef({ 2004 LAYOUT_DIRECTION_LTR, 2005 LAYOUT_DIRECTION_RTL, 2006 LAYOUT_DIRECTION_INHERIT, 2007 LAYOUT_DIRECTION_LOCALE 2008 }) 2009 @Retention(RetentionPolicy.SOURCE) 2010 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2011 public @interface LayoutDir {} 2012 2013 /** @hide */ 2014 @IntDef({ 2015 LAYOUT_DIRECTION_LTR, 2016 LAYOUT_DIRECTION_RTL 2017 }) 2018 @Retention(RetentionPolicy.SOURCE) 2019 public @interface ResolvedLayoutDir {} 2020 2021 /** 2022 * A flag to indicate that the layout direction of this view has not been defined yet. 2023 * @hide 2024 */ 2025 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2026 2027 /** 2028 * Horizontal layout direction of this view is from Left to Right. 2029 * Use with {@link #setLayoutDirection}. 2030 */ 2031 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2032 2033 /** 2034 * Horizontal layout direction of this view is from Right to Left. 2035 * Use with {@link #setLayoutDirection}. 2036 */ 2037 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2038 2039 /** 2040 * Horizontal layout direction of this view is inherited from its parent. 2041 * Use with {@link #setLayoutDirection}. 2042 */ 2043 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2044 2045 /** 2046 * Horizontal layout direction of this view is from deduced from the default language 2047 * script for the locale. Use with {@link #setLayoutDirection}. 2048 */ 2049 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2050 2051 /** 2052 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2053 * @hide 2054 */ 2055 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2056 2057 /** 2058 * Mask for use with private flags indicating bits used for horizontal layout direction. 2059 * @hide 2060 */ 2061 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2062 2063 /** 2064 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2065 * right-to-left direction. 2066 * @hide 2067 */ 2068 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2069 2070 /** 2071 * Indicates whether the view horizontal layout direction has been resolved. 2072 * @hide 2073 */ 2074 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2075 2076 /** 2077 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2078 * @hide 2079 */ 2080 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2081 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2082 2083 /* 2084 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2085 * flag value. 2086 * @hide 2087 */ 2088 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2089 LAYOUT_DIRECTION_LTR, 2090 LAYOUT_DIRECTION_RTL, 2091 LAYOUT_DIRECTION_INHERIT, 2092 LAYOUT_DIRECTION_LOCALE 2093 }; 2094 2095 /** 2096 * Default horizontal layout direction. 2097 */ 2098 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2099 2100 /** 2101 * Default horizontal layout direction. 2102 * @hide 2103 */ 2104 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2105 2106 /** 2107 * Text direction is inherited through {@link ViewGroup} 2108 */ 2109 public static final int TEXT_DIRECTION_INHERIT = 0; 2110 2111 /** 2112 * Text direction is using "first strong algorithm". The first strong directional character 2113 * determines the paragraph direction. If there is no strong directional character, the 2114 * paragraph direction is the view's resolved layout direction. 2115 */ 2116 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2117 2118 /** 2119 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2120 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2121 * If there are neither, the paragraph direction is the view's resolved layout direction. 2122 */ 2123 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2124 2125 /** 2126 * Text direction is forced to LTR. 2127 */ 2128 public static final int TEXT_DIRECTION_LTR = 3; 2129 2130 /** 2131 * Text direction is forced to RTL. 2132 */ 2133 public static final int TEXT_DIRECTION_RTL = 4; 2134 2135 /** 2136 * Text direction is coming from the system Locale. 2137 */ 2138 public static final int TEXT_DIRECTION_LOCALE = 5; 2139 2140 /** 2141 * Text direction is using "first strong algorithm". The first strong directional character 2142 * determines the paragraph direction. If there is no strong directional character, the 2143 * paragraph direction is LTR. 2144 */ 2145 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2146 2147 /** 2148 * Text direction is using "first strong algorithm". The first strong directional character 2149 * determines the paragraph direction. If there is no strong directional character, the 2150 * paragraph direction is RTL. 2151 */ 2152 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2153 2154 /** 2155 * Default text direction is inherited 2156 */ 2157 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2158 2159 /** 2160 * Default resolved text direction 2161 * @hide 2162 */ 2163 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2164 2165 /** 2166 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2167 * @hide 2168 */ 2169 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2170 2171 /** 2172 * Mask for use with private flags indicating bits used for text direction. 2173 * @hide 2174 */ 2175 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2176 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2177 2178 /** 2179 * Array of text direction flags for mapping attribute "textDirection" to correct 2180 * flag value. 2181 * @hide 2182 */ 2183 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2184 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2185 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2186 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2187 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2188 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2189 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2190 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2191 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2192 }; 2193 2194 /** 2195 * Indicates whether the view text direction has been resolved. 2196 * @hide 2197 */ 2198 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2199 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2200 2201 /** 2202 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2203 * @hide 2204 */ 2205 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2206 2207 /** 2208 * Mask for use with private flags indicating bits used for resolved text direction. 2209 * @hide 2210 */ 2211 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2212 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2213 2214 /** 2215 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2216 * @hide 2217 */ 2218 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2219 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2220 2221 /** @hide */ 2222 @IntDef({ 2223 TEXT_ALIGNMENT_INHERIT, 2224 TEXT_ALIGNMENT_GRAVITY, 2225 TEXT_ALIGNMENT_CENTER, 2226 TEXT_ALIGNMENT_TEXT_START, 2227 TEXT_ALIGNMENT_TEXT_END, 2228 TEXT_ALIGNMENT_VIEW_START, 2229 TEXT_ALIGNMENT_VIEW_END 2230 }) 2231 @Retention(RetentionPolicy.SOURCE) 2232 public @interface TextAlignment {} 2233 2234 /** 2235 * Default text alignment. The text alignment of this View is inherited from its parent. 2236 * Use with {@link #setTextAlignment(int)} 2237 */ 2238 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2239 2240 /** 2241 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2242 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2243 * 2244 * Use with {@link #setTextAlignment(int)} 2245 */ 2246 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2247 2248 /** 2249 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2250 * 2251 * Use with {@link #setTextAlignment(int)} 2252 */ 2253 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2254 2255 /** 2256 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2257 * 2258 * Use with {@link #setTextAlignment(int)} 2259 */ 2260 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2261 2262 /** 2263 * Center the paragraph, e.g. ALIGN_CENTER. 2264 * 2265 * Use with {@link #setTextAlignment(int)} 2266 */ 2267 public static final int TEXT_ALIGNMENT_CENTER = 4; 2268 2269 /** 2270 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2271 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2272 * 2273 * Use with {@link #setTextAlignment(int)} 2274 */ 2275 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2276 2277 /** 2278 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2279 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2280 * 2281 * Use with {@link #setTextAlignment(int)} 2282 */ 2283 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2284 2285 /** 2286 * Default text alignment is inherited 2287 */ 2288 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2289 2290 /** 2291 * Default resolved text alignment 2292 * @hide 2293 */ 2294 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2295 2296 /** 2297 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2298 * @hide 2299 */ 2300 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2301 2302 /** 2303 * Mask for use with private flags indicating bits used for text alignment. 2304 * @hide 2305 */ 2306 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2307 2308 /** 2309 * Array of text direction flags for mapping attribute "textAlignment" to correct 2310 * flag value. 2311 * @hide 2312 */ 2313 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2314 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2315 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2316 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2317 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2318 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2319 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2320 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2321 }; 2322 2323 /** 2324 * Indicates whether the view text alignment has been resolved. 2325 * @hide 2326 */ 2327 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2328 2329 /** 2330 * Bit shift to get the resolved text alignment. 2331 * @hide 2332 */ 2333 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2334 2335 /** 2336 * Mask for use with private flags indicating bits used for text alignment. 2337 * @hide 2338 */ 2339 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2340 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2341 2342 /** 2343 * Indicates whether if the view text alignment has been resolved to gravity 2344 */ 2345 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2346 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2347 2348 // Accessiblity constants for mPrivateFlags2 2349 2350 /** 2351 * Shift for the bits in {@link #mPrivateFlags2} related to the 2352 * "importantForAccessibility" attribute. 2353 */ 2354 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2355 2356 /** 2357 * Automatically determine whether a view is important for accessibility. 2358 */ 2359 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2360 2361 /** 2362 * The view is important for accessibility. 2363 */ 2364 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2365 2366 /** 2367 * The view is not important for accessibility. 2368 */ 2369 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2370 2371 /** 2372 * The view is not important for accessibility, nor are any of its 2373 * descendant views. 2374 */ 2375 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2376 2377 /** 2378 * The default whether the view is important for accessibility. 2379 */ 2380 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2381 2382 /** 2383 * Mask for obtaining the bits which specify how to determine 2384 * whether a view is important for accessibility. 2385 */ 2386 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2387 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2388 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2389 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2390 2391 /** 2392 * Shift for the bits in {@link #mPrivateFlags2} related to the 2393 * "accessibilityLiveRegion" attribute. 2394 */ 2395 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2396 2397 /** 2398 * Live region mode specifying that accessibility services should not 2399 * automatically announce changes to this view. This is the default live 2400 * region mode for most views. 2401 * <p> 2402 * Use with {@link #setAccessibilityLiveRegion(int)}. 2403 */ 2404 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2405 2406 /** 2407 * Live region mode specifying that accessibility services should announce 2408 * changes to this view. 2409 * <p> 2410 * Use with {@link #setAccessibilityLiveRegion(int)}. 2411 */ 2412 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2413 2414 /** 2415 * Live region mode specifying that accessibility services should interrupt 2416 * ongoing speech to immediately announce changes to this view. 2417 * <p> 2418 * Use with {@link #setAccessibilityLiveRegion(int)}. 2419 */ 2420 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2421 2422 /** 2423 * The default whether the view is important for accessibility. 2424 */ 2425 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2426 2427 /** 2428 * Mask for obtaining the bits which specify a view's accessibility live 2429 * region mode. 2430 */ 2431 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2432 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2433 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2434 2435 /** 2436 * Flag indicating whether a view has accessibility focus. 2437 */ 2438 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2439 2440 /** 2441 * Flag whether the accessibility state of the subtree rooted at this view changed. 2442 */ 2443 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2444 2445 /** 2446 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2447 * is used to check whether later changes to the view's transform should invalidate the 2448 * view to force the quickReject test to run again. 2449 */ 2450 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2451 2452 /** 2453 * Flag indicating that start/end padding has been resolved into left/right padding 2454 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2455 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2456 * during measurement. In some special cases this is required such as when an adapter-based 2457 * view measures prospective children without attaching them to a window. 2458 */ 2459 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2460 2461 /** 2462 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2463 */ 2464 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2465 2466 /** 2467 * Indicates that the view is tracking some sort of transient state 2468 * that the app should not need to be aware of, but that the framework 2469 * should take special care to preserve. 2470 */ 2471 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2472 2473 /** 2474 * Group of bits indicating that RTL properties resolution is done. 2475 */ 2476 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2477 PFLAG2_TEXT_DIRECTION_RESOLVED | 2478 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2479 PFLAG2_PADDING_RESOLVED | 2480 PFLAG2_DRAWABLE_RESOLVED; 2481 2482 // There are a couple of flags left in mPrivateFlags2 2483 2484 /* End of masks for mPrivateFlags2 */ 2485 2486 /** 2487 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2488 * 2489 * |-------|-------|-------|-------| 2490 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2491 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2492 * 1 PFLAG3_IS_LAID_OUT 2493 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2494 * 1 PFLAG3_CALLED_SUPER 2495 * 1 PFLAG3_APPLYING_INSETS 2496 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2497 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2498 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2499 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2500 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2501 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2502 * 1 PFLAG3_SCROLL_INDICATOR_START 2503 * 1 PFLAG3_SCROLL_INDICATOR_END 2504 * 1 PFLAG3_ASSIST_BLOCKED 2505 * 1 PFLAG3_CLUSTER 2506 * x * NO LONGER NEEDED, SHOULD BE REUSED * 2507 * 1 PFLAG3_FINGER_DOWN 2508 * 1 PFLAG3_FOCUSED_BY_DEFAULT 2509 * xxxx * NO LONGER NEEDED, SHOULD BE REUSED * 2510 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2511 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2512 * 1 PFLAG3_TEMPORARY_DETACH 2513 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2514 * |-------|-------|-------|-------| 2515 */ 2516 2517 /** 2518 * Flag indicating that view has a transform animation set on it. This is used to track whether 2519 * an animation is cleared between successive frames, in order to tell the associated 2520 * DisplayList to clear its animation matrix. 2521 */ 2522 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2523 2524 /** 2525 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2526 * animation is cleared between successive frames, in order to tell the associated 2527 * DisplayList to restore its alpha value. 2528 */ 2529 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2530 2531 /** 2532 * Flag indicating that the view has been through at least one layout since it 2533 * was last attached to a window. 2534 */ 2535 static final int PFLAG3_IS_LAID_OUT = 0x4; 2536 2537 /** 2538 * Flag indicating that a call to measure() was skipped and should be done 2539 * instead when layout() is invoked. 2540 */ 2541 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2542 2543 /** 2544 * Flag indicating that an overridden method correctly called down to 2545 * the superclass implementation as required by the API spec. 2546 */ 2547 static final int PFLAG3_CALLED_SUPER = 0x10; 2548 2549 /** 2550 * Flag indicating that we're in the process of applying window insets. 2551 */ 2552 static final int PFLAG3_APPLYING_INSETS = 0x20; 2553 2554 /** 2555 * Flag indicating that we're in the process of fitting system windows using the old method. 2556 */ 2557 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2558 2559 /** 2560 * Flag indicating that nested scrolling is enabled for this view. 2561 * The view will optionally cooperate with views up its parent chain to allow for 2562 * integrated nested scrolling along the same axis. 2563 */ 2564 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2565 2566 /** 2567 * Flag indicating that the bottom scroll indicator should be displayed 2568 * when this view can scroll up. 2569 */ 2570 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2571 2572 /** 2573 * Flag indicating that the bottom scroll indicator should be displayed 2574 * when this view can scroll down. 2575 */ 2576 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2577 2578 /** 2579 * Flag indicating that the left scroll indicator should be displayed 2580 * when this view can scroll left. 2581 */ 2582 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2583 2584 /** 2585 * Flag indicating that the right scroll indicator should be displayed 2586 * when this view can scroll right. 2587 */ 2588 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2589 2590 /** 2591 * Flag indicating that the start scroll indicator should be displayed 2592 * when this view can scroll in the start direction. 2593 */ 2594 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2595 2596 /** 2597 * Flag indicating that the end scroll indicator should be displayed 2598 * when this view can scroll in the end direction. 2599 */ 2600 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2601 2602 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2603 2604 static final int SCROLL_INDICATORS_NONE = 0x0000; 2605 2606 /** 2607 * Mask for use with setFlags indicating bits used for indicating which 2608 * scroll indicators are enabled. 2609 */ 2610 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2611 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2612 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2613 | PFLAG3_SCROLL_INDICATOR_END; 2614 2615 /** 2616 * Left-shift required to translate between public scroll indicator flags 2617 * and internal PFLAGS3 flags. When used as a right-shift, translates 2618 * PFLAGS3 flags to public flags. 2619 */ 2620 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2621 2622 /** @hide */ 2623 @Retention(RetentionPolicy.SOURCE) 2624 @IntDef(flag = true, 2625 value = { 2626 SCROLL_INDICATOR_TOP, 2627 SCROLL_INDICATOR_BOTTOM, 2628 SCROLL_INDICATOR_LEFT, 2629 SCROLL_INDICATOR_RIGHT, 2630 SCROLL_INDICATOR_START, 2631 SCROLL_INDICATOR_END, 2632 }) 2633 public @interface ScrollIndicators {} 2634 2635 /** 2636 * Scroll indicator direction for the top edge of the view. 2637 * 2638 * @see #setScrollIndicators(int) 2639 * @see #setScrollIndicators(int, int) 2640 * @see #getScrollIndicators() 2641 */ 2642 public static final int SCROLL_INDICATOR_TOP = 2643 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2644 2645 /** 2646 * Scroll indicator direction for the bottom edge of the view. 2647 * 2648 * @see #setScrollIndicators(int) 2649 * @see #setScrollIndicators(int, int) 2650 * @see #getScrollIndicators() 2651 */ 2652 public static final int SCROLL_INDICATOR_BOTTOM = 2653 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2654 2655 /** 2656 * Scroll indicator direction for the left edge of the view. 2657 * 2658 * @see #setScrollIndicators(int) 2659 * @see #setScrollIndicators(int, int) 2660 * @see #getScrollIndicators() 2661 */ 2662 public static final int SCROLL_INDICATOR_LEFT = 2663 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2664 2665 /** 2666 * Scroll indicator direction for the right edge of the view. 2667 * 2668 * @see #setScrollIndicators(int) 2669 * @see #setScrollIndicators(int, int) 2670 * @see #getScrollIndicators() 2671 */ 2672 public static final int SCROLL_INDICATOR_RIGHT = 2673 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2674 2675 /** 2676 * Scroll indicator direction for the starting edge of the view. 2677 * <p> 2678 * Resolved according to the view's layout direction, see 2679 * {@link #getLayoutDirection()} for more information. 2680 * 2681 * @see #setScrollIndicators(int) 2682 * @see #setScrollIndicators(int, int) 2683 * @see #getScrollIndicators() 2684 */ 2685 public static final int SCROLL_INDICATOR_START = 2686 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2687 2688 /** 2689 * Scroll indicator direction for the ending edge of the view. 2690 * <p> 2691 * Resolved according to the view's layout direction, see 2692 * {@link #getLayoutDirection()} for more information. 2693 * 2694 * @see #setScrollIndicators(int) 2695 * @see #setScrollIndicators(int, int) 2696 * @see #getScrollIndicators() 2697 */ 2698 public static final int SCROLL_INDICATOR_END = 2699 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2700 2701 /** 2702 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 2703 * into this view.<p> 2704 */ 2705 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 2706 2707 /** 2708 * Flag indicating that the view is a root of a keyboard navigation cluster. 2709 * 2710 * @see #isKeyboardNavigationCluster() 2711 * @see #setKeyboardNavigationCluster(boolean) 2712 */ 2713 private static final int PFLAG3_CLUSTER = 0x8000; 2714 2715 /** 2716 * Indicates that the user is currently touching the screen. 2717 * Currently used for the tooltip positioning only. 2718 */ 2719 private static final int PFLAG3_FINGER_DOWN = 0x20000; 2720 2721 /** 2722 * Flag indicating that this view is the default-focus view. 2723 * 2724 * @see #isFocusedByDefault() 2725 * @see #setFocusedByDefault(boolean) 2726 */ 2727 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 2728 2729 /** 2730 * Whether this view has rendered elements that overlap (see {@link 2731 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 2732 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 2733 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 2734 * determined by whatever {@link #hasOverlappingRendering()} returns. 2735 */ 2736 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 2737 2738 /** 2739 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 2740 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 2741 */ 2742 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 2743 2744 /** 2745 * Flag indicating that the view is temporarily detached from the parent view. 2746 * 2747 * @see #onStartTemporaryDetach() 2748 * @see #onFinishTemporaryDetach() 2749 */ 2750 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 2751 2752 /** 2753 * Flag indicating that the view does not wish to be revealed within its parent 2754 * hierarchy when it gains focus. Expressed in the negative since the historical 2755 * default behavior is to reveal on focus; this flag suppresses that behavior. 2756 * 2757 * @see #setRevealOnFocusHint(boolean) 2758 * @see #getRevealOnFocusHint() 2759 */ 2760 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 2761 2762 /* End of masks for mPrivateFlags3 */ 2763 2764 /** 2765 * Always allow a user to over-scroll this view, provided it is a 2766 * view that can scroll. 2767 * 2768 * @see #getOverScrollMode() 2769 * @see #setOverScrollMode(int) 2770 */ 2771 public static final int OVER_SCROLL_ALWAYS = 0; 2772 2773 /** 2774 * Allow a user to over-scroll this view only if the content is large 2775 * enough to meaningfully scroll, provided it is a view that can scroll. 2776 * 2777 * @see #getOverScrollMode() 2778 * @see #setOverScrollMode(int) 2779 */ 2780 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 2781 2782 /** 2783 * Never allow a user to over-scroll this view. 2784 * 2785 * @see #getOverScrollMode() 2786 * @see #setOverScrollMode(int) 2787 */ 2788 public static final int OVER_SCROLL_NEVER = 2; 2789 2790 /** 2791 * Special constant for {@link #setSystemUiVisibility(int)}: View has 2792 * requested the system UI (status bar) to be visible (the default). 2793 * 2794 * @see #setSystemUiVisibility(int) 2795 */ 2796 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 2797 2798 /** 2799 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 2800 * system UI to enter an unobtrusive "low profile" mode. 2801 * 2802 * <p>This is for use in games, book readers, video players, or any other 2803 * "immersive" application where the usual system chrome is deemed too distracting. 2804 * 2805 * <p>In low profile mode, the status bar and/or navigation icons may dim. 2806 * 2807 * @see #setSystemUiVisibility(int) 2808 */ 2809 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 2810 2811 /** 2812 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 2813 * system navigation be temporarily hidden. 2814 * 2815 * <p>This is an even less obtrusive state than that called for by 2816 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 2817 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 2818 * those to disappear. This is useful (in conjunction with the 2819 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 2820 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 2821 * window flags) for displaying content using every last pixel on the display. 2822 * 2823 * <p>There is a limitation: because navigation controls are so important, the least user 2824 * interaction will cause them to reappear immediately. When this happens, both 2825 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 2826 * so that both elements reappear at the same time. 2827 * 2828 * @see #setSystemUiVisibility(int) 2829 */ 2830 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 2831 2832 /** 2833 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 2834 * into the normal fullscreen mode so that its content can take over the screen 2835 * while still allowing the user to interact with the application. 2836 * 2837 * <p>This has the same visual effect as 2838 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 2839 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 2840 * meaning that non-critical screen decorations (such as the status bar) will be 2841 * hidden while the user is in the View's window, focusing the experience on 2842 * that content. Unlike the window flag, if you are using ActionBar in 2843 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2844 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 2845 * hide the action bar. 2846 * 2847 * <p>This approach to going fullscreen is best used over the window flag when 2848 * it is a transient state -- that is, the application does this at certain 2849 * points in its user interaction where it wants to allow the user to focus 2850 * on content, but not as a continuous state. For situations where the application 2851 * would like to simply stay full screen the entire time (such as a game that 2852 * wants to take over the screen), the 2853 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 2854 * is usually a better approach. The state set here will be removed by the system 2855 * in various situations (such as the user moving to another application) like 2856 * the other system UI states. 2857 * 2858 * <p>When using this flag, the application should provide some easy facility 2859 * for the user to go out of it. A common example would be in an e-book 2860 * reader, where tapping on the screen brings back whatever screen and UI 2861 * decorations that had been hidden while the user was immersed in reading 2862 * the book. 2863 * 2864 * @see #setSystemUiVisibility(int) 2865 */ 2866 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 2867 2868 /** 2869 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 2870 * flags, we would like a stable view of the content insets given to 2871 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 2872 * will always represent the worst case that the application can expect 2873 * as a continuous state. In the stock Android UI this is the space for 2874 * the system bar, nav bar, and status bar, but not more transient elements 2875 * such as an input method. 2876 * 2877 * The stable layout your UI sees is based on the system UI modes you can 2878 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 2879 * then you will get a stable layout for changes of the 2880 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 2881 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 2882 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 2883 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 2884 * with a stable layout. (Note that you should avoid using 2885 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 2886 * 2887 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 2888 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 2889 * then a hidden status bar will be considered a "stable" state for purposes 2890 * here. This allows your UI to continually hide the status bar, while still 2891 * using the system UI flags to hide the action bar while still retaining 2892 * a stable layout. Note that changing the window fullscreen flag will never 2893 * provide a stable layout for a clean transition. 2894 * 2895 * <p>If you are using ActionBar in 2896 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2897 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 2898 * insets it adds to those given to the application. 2899 */ 2900 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 2901 2902 /** 2903 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2904 * to be laid out as if it has requested 2905 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 2906 * allows it to avoid artifacts when switching in and out of that mode, at 2907 * the expense that some of its user interface may be covered by screen 2908 * decorations when they are shown. You can perform layout of your inner 2909 * UI elements to account for the navigation system UI through the 2910 * {@link #fitSystemWindows(Rect)} method. 2911 */ 2912 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 2913 2914 /** 2915 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2916 * to be laid out as if it has requested 2917 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 2918 * allows it to avoid artifacts when switching in and out of that mode, at 2919 * the expense that some of its user interface may be covered by screen 2920 * decorations when they are shown. You can perform layout of your inner 2921 * UI elements to account for non-fullscreen system UI through the 2922 * {@link #fitSystemWindows(Rect)} method. 2923 */ 2924 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 2925 2926 /** 2927 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2928 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 2929 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 2930 * user interaction. 2931 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 2932 * has an effect when used in combination with that flag.</p> 2933 */ 2934 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 2935 2936 /** 2937 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2938 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 2939 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 2940 * experience while also hiding the system bars. If this flag is not set, 2941 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 2942 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 2943 * if the user swipes from the top of the screen. 2944 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 2945 * system gestures, such as swiping from the top of the screen. These transient system bars 2946 * will overlay app’s content, may have some degree of transparency, and will automatically 2947 * hide after a short timeout. 2948 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 2949 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 2950 * with one or both of those flags.</p> 2951 */ 2952 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 2953 2954 /** 2955 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 2956 * is compatible with light status bar backgrounds. 2957 * 2958 * <p>For this to take effect, the window must request 2959 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2960 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2961 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 2962 * FLAG_TRANSLUCENT_STATUS}. 2963 * 2964 * @see android.R.attr#windowLightStatusBar 2965 */ 2966 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 2967 2968 /** 2969 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 2970 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 2971 */ 2972 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 2973 2974 /** 2975 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 2976 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 2977 */ 2978 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 2979 2980 /** 2981 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 2982 * that is compatible with light navigation bar backgrounds. 2983 * 2984 * <p>For this to take effect, the window must request 2985 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2986 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2987 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 2988 * FLAG_TRANSLUCENT_NAVIGATION}. 2989 */ 2990 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 2991 2992 /** 2993 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 2994 */ 2995 @Deprecated 2996 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 2997 2998 /** 2999 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3000 */ 3001 @Deprecated 3002 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3003 3004 /** 3005 * @hide 3006 * 3007 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3008 * out of the public fields to keep the undefined bits out of the developer's way. 3009 * 3010 * Flag to make the status bar not expandable. Unless you also 3011 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3012 */ 3013 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3014 3015 /** 3016 * @hide 3017 * 3018 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3019 * out of the public fields to keep the undefined bits out of the developer's way. 3020 * 3021 * Flag to hide notification icons and scrolling ticker text. 3022 */ 3023 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3024 3025 /** 3026 * @hide 3027 * 3028 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3029 * out of the public fields to keep the undefined bits out of the developer's way. 3030 * 3031 * Flag to disable incoming notification alerts. This will not block 3032 * icons, but it will block sound, vibrating and other visual or aural notifications. 3033 */ 3034 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3035 3036 /** 3037 * @hide 3038 * 3039 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3040 * out of the public fields to keep the undefined bits out of the developer's way. 3041 * 3042 * Flag to hide only the scrolling ticker. Note that 3043 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3044 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3045 */ 3046 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3047 3048 /** 3049 * @hide 3050 * 3051 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3052 * out of the public fields to keep the undefined bits out of the developer's way. 3053 * 3054 * Flag to hide the center system info area. 3055 */ 3056 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3057 3058 /** 3059 * @hide 3060 * 3061 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3062 * out of the public fields to keep the undefined bits out of the developer's way. 3063 * 3064 * Flag to hide only the home button. Don't use this 3065 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3066 */ 3067 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3068 3069 /** 3070 * @hide 3071 * 3072 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3073 * out of the public fields to keep the undefined bits out of the developer's way. 3074 * 3075 * Flag to hide only the back button. Don't use this 3076 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3077 */ 3078 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3079 3080 /** 3081 * @hide 3082 * 3083 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3084 * out of the public fields to keep the undefined bits out of the developer's way. 3085 * 3086 * Flag to hide only the clock. You might use this if your activity has 3087 * its own clock making the status bar's clock redundant. 3088 */ 3089 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3090 3091 /** 3092 * @hide 3093 * 3094 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3095 * out of the public fields to keep the undefined bits out of the developer's way. 3096 * 3097 * Flag to hide only the recent apps button. Don't use this 3098 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3099 */ 3100 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3101 3102 /** 3103 * @hide 3104 * 3105 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3106 * out of the public fields to keep the undefined bits out of the developer's way. 3107 * 3108 * Flag to disable the global search gesture. Don't use this 3109 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3110 */ 3111 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3112 3113 /** 3114 * @hide 3115 * 3116 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3117 * out of the public fields to keep the undefined bits out of the developer's way. 3118 * 3119 * Flag to specify that the status bar is displayed in transient mode. 3120 */ 3121 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3122 3123 /** 3124 * @hide 3125 * 3126 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3127 * out of the public fields to keep the undefined bits out of the developer's way. 3128 * 3129 * Flag to specify that the navigation bar is displayed in transient mode. 3130 */ 3131 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3132 3133 /** 3134 * @hide 3135 * 3136 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3137 * out of the public fields to keep the undefined bits out of the developer's way. 3138 * 3139 * Flag to specify that the hidden status bar would like to be shown. 3140 */ 3141 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3142 3143 /** 3144 * @hide 3145 * 3146 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3147 * out of the public fields to keep the undefined bits out of the developer's way. 3148 * 3149 * Flag to specify that the hidden navigation bar would like to be shown. 3150 */ 3151 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3152 3153 /** 3154 * @hide 3155 * 3156 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3157 * out of the public fields to keep the undefined bits out of the developer's way. 3158 * 3159 * Flag to specify that the status bar is displayed in translucent mode. 3160 */ 3161 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3162 3163 /** 3164 * @hide 3165 * 3166 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3167 * out of the public fields to keep the undefined bits out of the developer's way. 3168 * 3169 * Flag to specify that the navigation bar is displayed in translucent mode. 3170 */ 3171 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3172 3173 /** 3174 * @hide 3175 * 3176 * Makes navigation bar transparent (but not the status bar). 3177 */ 3178 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3179 3180 /** 3181 * @hide 3182 * 3183 * Makes status bar transparent (but not the navigation bar). 3184 */ 3185 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3186 3187 /** 3188 * @hide 3189 * 3190 * Makes both status bar and navigation bar transparent. 3191 */ 3192 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3193 | STATUS_BAR_TRANSPARENT; 3194 3195 /** 3196 * @hide 3197 */ 3198 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3199 3200 /** 3201 * These are the system UI flags that can be cleared by events outside 3202 * of an application. Currently this is just the ability to tap on the 3203 * screen while hiding the navigation bar to have it return. 3204 * @hide 3205 */ 3206 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3207 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3208 | SYSTEM_UI_FLAG_FULLSCREEN; 3209 3210 /** 3211 * Flags that can impact the layout in relation to system UI. 3212 */ 3213 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3214 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3215 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3216 3217 /** @hide */ 3218 @IntDef(flag = true, 3219 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3220 @Retention(RetentionPolicy.SOURCE) 3221 public @interface FindViewFlags {} 3222 3223 /** 3224 * Find views that render the specified text. 3225 * 3226 * @see #findViewsWithText(ArrayList, CharSequence, int) 3227 */ 3228 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3229 3230 /** 3231 * Find find views that contain the specified content description. 3232 * 3233 * @see #findViewsWithText(ArrayList, CharSequence, int) 3234 */ 3235 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3236 3237 /** 3238 * Find views that contain {@link AccessibilityNodeProvider}. Such 3239 * a View is a root of virtual view hierarchy and may contain the searched 3240 * text. If this flag is set Views with providers are automatically 3241 * added and it is a responsibility of the client to call the APIs of 3242 * the provider to determine whether the virtual tree rooted at this View 3243 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3244 * representing the virtual views with this text. 3245 * 3246 * @see #findViewsWithText(ArrayList, CharSequence, int) 3247 * 3248 * @hide 3249 */ 3250 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3251 3252 /** 3253 * The undefined cursor position. 3254 * 3255 * @hide 3256 */ 3257 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3258 3259 /** 3260 * Indicates that the screen has changed state and is now off. 3261 * 3262 * @see #onScreenStateChanged(int) 3263 */ 3264 public static final int SCREEN_STATE_OFF = 0x0; 3265 3266 /** 3267 * Indicates that the screen has changed state and is now on. 3268 * 3269 * @see #onScreenStateChanged(int) 3270 */ 3271 public static final int SCREEN_STATE_ON = 0x1; 3272 3273 /** 3274 * Indicates no axis of view scrolling. 3275 */ 3276 public static final int SCROLL_AXIS_NONE = 0; 3277 3278 /** 3279 * Indicates scrolling along the horizontal axis. 3280 */ 3281 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3282 3283 /** 3284 * Indicates scrolling along the vertical axis. 3285 */ 3286 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3287 3288 /** 3289 * Controls the over-scroll mode for this view. 3290 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3291 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3292 * and {@link #OVER_SCROLL_NEVER}. 3293 */ 3294 private int mOverScrollMode; 3295 3296 /** 3297 * The parent this view is attached to. 3298 * {@hide} 3299 * 3300 * @see #getParent() 3301 */ 3302 protected ViewParent mParent; 3303 3304 /** 3305 * {@hide} 3306 */ 3307 AttachInfo mAttachInfo; 3308 3309 /** 3310 * {@hide} 3311 */ 3312 @ViewDebug.ExportedProperty(flagMapping = { 3313 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3314 name = "FORCE_LAYOUT"), 3315 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3316 name = "LAYOUT_REQUIRED"), 3317 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3318 name = "DRAWING_CACHE_INVALID", outputIf = false), 3319 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3320 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3321 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3322 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3323 }, formatToHexString = true) 3324 3325 /* @hide */ 3326 public int mPrivateFlags; 3327 int mPrivateFlags2; 3328 int mPrivateFlags3; 3329 3330 /** 3331 * This view's request for the visibility of the status bar. 3332 * @hide 3333 */ 3334 @ViewDebug.ExportedProperty(flagMapping = { 3335 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3336 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3337 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3338 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3339 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3340 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3341 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3342 equals = SYSTEM_UI_FLAG_VISIBLE, 3343 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3344 }, formatToHexString = true) 3345 int mSystemUiVisibility; 3346 3347 /** 3348 * Reference count for transient state. 3349 * @see #setHasTransientState(boolean) 3350 */ 3351 int mTransientStateCount = 0; 3352 3353 /** 3354 * Count of how many windows this view has been attached to. 3355 */ 3356 int mWindowAttachCount; 3357 3358 /** 3359 * The layout parameters associated with this view and used by the parent 3360 * {@link android.view.ViewGroup} to determine how this view should be 3361 * laid out. 3362 * {@hide} 3363 */ 3364 protected ViewGroup.LayoutParams mLayoutParams; 3365 3366 /** 3367 * The view flags hold various views states. 3368 * {@hide} 3369 */ 3370 @ViewDebug.ExportedProperty(formatToHexString = true) 3371 int mViewFlags; 3372 3373 static class TransformationInfo { 3374 /** 3375 * The transform matrix for the View. This transform is calculated internally 3376 * based on the translation, rotation, and scale properties. 3377 * 3378 * Do *not* use this variable directly; instead call getMatrix(), which will 3379 * load the value from the View's RenderNode. 3380 */ 3381 private final Matrix mMatrix = new Matrix(); 3382 3383 /** 3384 * The inverse transform matrix for the View. This transform is calculated 3385 * internally based on the translation, rotation, and scale properties. 3386 * 3387 * Do *not* use this variable directly; instead call getInverseMatrix(), 3388 * which will load the value from the View's RenderNode. 3389 */ 3390 private Matrix mInverseMatrix; 3391 3392 /** 3393 * The opacity of the View. This is a value from 0 to 1, where 0 means 3394 * completely transparent and 1 means completely opaque. 3395 */ 3396 @ViewDebug.ExportedProperty 3397 float mAlpha = 1f; 3398 3399 /** 3400 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3401 * property only used by transitions, which is composited with the other alpha 3402 * values to calculate the final visual alpha value. 3403 */ 3404 float mTransitionAlpha = 1f; 3405 } 3406 3407 /** @hide */ 3408 public TransformationInfo mTransformationInfo; 3409 3410 /** 3411 * Current clip bounds. to which all drawing of this view are constrained. 3412 */ 3413 Rect mClipBounds = null; 3414 3415 private boolean mLastIsOpaque; 3416 3417 /** 3418 * The distance in pixels from the left edge of this view's parent 3419 * to the left edge of this view. 3420 * {@hide} 3421 */ 3422 @ViewDebug.ExportedProperty(category = "layout") 3423 protected int mLeft; 3424 /** 3425 * The distance in pixels from the left edge of this view's parent 3426 * to the right edge of this view. 3427 * {@hide} 3428 */ 3429 @ViewDebug.ExportedProperty(category = "layout") 3430 protected int mRight; 3431 /** 3432 * The distance in pixels from the top edge of this view's parent 3433 * to the top edge of this view. 3434 * {@hide} 3435 */ 3436 @ViewDebug.ExportedProperty(category = "layout") 3437 protected int mTop; 3438 /** 3439 * The distance in pixels from the top edge of this view's parent 3440 * to the bottom edge of this view. 3441 * {@hide} 3442 */ 3443 @ViewDebug.ExportedProperty(category = "layout") 3444 protected int mBottom; 3445 3446 /** 3447 * The offset, in pixels, by which the content of this view is scrolled 3448 * horizontally. 3449 * {@hide} 3450 */ 3451 @ViewDebug.ExportedProperty(category = "scrolling") 3452 protected int mScrollX; 3453 /** 3454 * The offset, in pixels, by which the content of this view is scrolled 3455 * vertically. 3456 * {@hide} 3457 */ 3458 @ViewDebug.ExportedProperty(category = "scrolling") 3459 protected int mScrollY; 3460 3461 /** 3462 * The left padding in pixels, that is the distance in pixels between the 3463 * left edge of this view and the left edge of its content. 3464 * {@hide} 3465 */ 3466 @ViewDebug.ExportedProperty(category = "padding") 3467 protected int mPaddingLeft = 0; 3468 /** 3469 * The right padding in pixels, that is the distance in pixels between the 3470 * right edge of this view and the right edge of its content. 3471 * {@hide} 3472 */ 3473 @ViewDebug.ExportedProperty(category = "padding") 3474 protected int mPaddingRight = 0; 3475 /** 3476 * The top padding in pixels, that is the distance in pixels between the 3477 * top edge of this view and the top edge of its content. 3478 * {@hide} 3479 */ 3480 @ViewDebug.ExportedProperty(category = "padding") 3481 protected int mPaddingTop; 3482 /** 3483 * The bottom padding in pixels, that is the distance in pixels between the 3484 * bottom edge of this view and the bottom edge of its content. 3485 * {@hide} 3486 */ 3487 @ViewDebug.ExportedProperty(category = "padding") 3488 protected int mPaddingBottom; 3489 3490 /** 3491 * The layout insets in pixels, that is the distance in pixels between the 3492 * visible edges of this view its bounds. 3493 */ 3494 private Insets mLayoutInsets; 3495 3496 /** 3497 * Briefly describes the view and is primarily used for accessibility support. 3498 */ 3499 private CharSequence mContentDescription; 3500 3501 /** 3502 * Specifies the id of a view for which this view serves as a label for 3503 * accessibility purposes. 3504 */ 3505 private int mLabelForId = View.NO_ID; 3506 3507 /** 3508 * Predicate for matching labeled view id with its label for 3509 * accessibility purposes. 3510 */ 3511 private MatchLabelForPredicate mMatchLabelForPredicate; 3512 3513 /** 3514 * Specifies a view before which this one is visited in accessibility traversal. 3515 */ 3516 private int mAccessibilityTraversalBeforeId = NO_ID; 3517 3518 /** 3519 * Specifies a view after which this one is visited in accessibility traversal. 3520 */ 3521 private int mAccessibilityTraversalAfterId = NO_ID; 3522 3523 /** 3524 * Predicate for matching a view by its id. 3525 */ 3526 private MatchIdPredicate mMatchIdPredicate; 3527 3528 /** 3529 * Cache the paddingRight set by the user to append to the scrollbar's size. 3530 * 3531 * @hide 3532 */ 3533 @ViewDebug.ExportedProperty(category = "padding") 3534 protected int mUserPaddingRight; 3535 3536 /** 3537 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3538 * 3539 * @hide 3540 */ 3541 @ViewDebug.ExportedProperty(category = "padding") 3542 protected int mUserPaddingBottom; 3543 3544 /** 3545 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3546 * 3547 * @hide 3548 */ 3549 @ViewDebug.ExportedProperty(category = "padding") 3550 protected int mUserPaddingLeft; 3551 3552 /** 3553 * Cache the paddingStart set by the user to append to the scrollbar's size. 3554 * 3555 */ 3556 @ViewDebug.ExportedProperty(category = "padding") 3557 int mUserPaddingStart; 3558 3559 /** 3560 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3561 * 3562 */ 3563 @ViewDebug.ExportedProperty(category = "padding") 3564 int mUserPaddingEnd; 3565 3566 /** 3567 * Cache initial left padding. 3568 * 3569 * @hide 3570 */ 3571 int mUserPaddingLeftInitial; 3572 3573 /** 3574 * Cache initial right padding. 3575 * 3576 * @hide 3577 */ 3578 int mUserPaddingRightInitial; 3579 3580 /** 3581 * Default undefined padding 3582 */ 3583 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3584 3585 /** 3586 * Cache if a left padding has been defined 3587 */ 3588 private boolean mLeftPaddingDefined = false; 3589 3590 /** 3591 * Cache if a right padding has been defined 3592 */ 3593 private boolean mRightPaddingDefined = false; 3594 3595 /** 3596 * @hide 3597 */ 3598 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3599 /** 3600 * @hide 3601 */ 3602 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3603 3604 private LongSparseLongArray mMeasureCache; 3605 3606 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3607 private Drawable mBackground; 3608 private TintInfo mBackgroundTint; 3609 3610 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3611 private ForegroundInfo mForegroundInfo; 3612 3613 private Drawable mScrollIndicatorDrawable; 3614 3615 /** 3616 * RenderNode used for backgrounds. 3617 * <p> 3618 * When non-null and valid, this is expected to contain an up-to-date copy 3619 * of the background drawable. It is cleared on temporary detach, and reset 3620 * on cleanup. 3621 */ 3622 private RenderNode mBackgroundRenderNode; 3623 3624 private int mBackgroundResource; 3625 private boolean mBackgroundSizeChanged; 3626 3627 private String mTransitionName; 3628 3629 static class TintInfo { 3630 ColorStateList mTintList; 3631 PorterDuff.Mode mTintMode; 3632 boolean mHasTintMode; 3633 boolean mHasTintList; 3634 } 3635 3636 private static class ForegroundInfo { 3637 private Drawable mDrawable; 3638 private TintInfo mTintInfo; 3639 private int mGravity = Gravity.FILL; 3640 private boolean mInsidePadding = true; 3641 private boolean mBoundsChanged = true; 3642 private final Rect mSelfBounds = new Rect(); 3643 private final Rect mOverlayBounds = new Rect(); 3644 } 3645 3646 static class ListenerInfo { 3647 /** 3648 * Listener used to dispatch focus change events. 3649 * This field should be made private, so it is hidden from the SDK. 3650 * {@hide} 3651 */ 3652 protected OnFocusChangeListener mOnFocusChangeListener; 3653 3654 /** 3655 * Listeners for layout change events. 3656 */ 3657 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 3658 3659 protected OnScrollChangeListener mOnScrollChangeListener; 3660 3661 /** 3662 * Listeners for attach events. 3663 */ 3664 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 3665 3666 /** 3667 * Listener used to dispatch click events. 3668 * This field should be made private, so it is hidden from the SDK. 3669 * {@hide} 3670 */ 3671 public OnClickListener mOnClickListener; 3672 3673 /** 3674 * Listener used to dispatch long click events. 3675 * This field should be made private, so it is hidden from the SDK. 3676 * {@hide} 3677 */ 3678 protected OnLongClickListener mOnLongClickListener; 3679 3680 /** 3681 * Listener used to dispatch context click events. This field should be made private, so it 3682 * is hidden from the SDK. 3683 * {@hide} 3684 */ 3685 protected OnContextClickListener mOnContextClickListener; 3686 3687 /** 3688 * Listener used to build the context menu. 3689 * This field should be made private, so it is hidden from the SDK. 3690 * {@hide} 3691 */ 3692 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 3693 3694 private OnKeyListener mOnKeyListener; 3695 3696 private OnTouchListener mOnTouchListener; 3697 3698 private OnHoverListener mOnHoverListener; 3699 3700 private OnGenericMotionListener mOnGenericMotionListener; 3701 3702 private OnDragListener mOnDragListener; 3703 3704 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 3705 3706 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 3707 } 3708 3709 ListenerInfo mListenerInfo; 3710 3711 private static class TooltipInfo { 3712 /** 3713 * Text to be displayed in a tooltip popup. 3714 */ 3715 @Nullable 3716 CharSequence mTooltipText; 3717 3718 /** 3719 * View-relative position of the tooltip anchor point. 3720 */ 3721 int mAnchorX; 3722 int mAnchorY; 3723 3724 /** 3725 * The tooltip popup. 3726 */ 3727 @Nullable 3728 TooltipPopup mTooltipPopup; 3729 3730 /** 3731 * Set to true if the tooltip was shown as a result of a long click. 3732 */ 3733 boolean mTooltipFromLongClick; 3734 3735 /** 3736 * Keep these Runnables so that they can be used to reschedule. 3737 */ 3738 Runnable mShowTooltipRunnable; 3739 Runnable mHideTooltipRunnable; 3740 } 3741 3742 TooltipInfo mTooltipInfo; 3743 3744 // Temporary values used to hold (x,y) coordinates when delegating from the 3745 // two-arg performLongClick() method to the legacy no-arg version. 3746 private float mLongClickX = Float.NaN; 3747 private float mLongClickY = Float.NaN; 3748 3749 /** 3750 * The application environment this view lives in. 3751 * This field should be made private, so it is hidden from the SDK. 3752 * {@hide} 3753 */ 3754 @ViewDebug.ExportedProperty(deepExport = true) 3755 protected Context mContext; 3756 3757 private final Resources mResources; 3758 3759 private ScrollabilityCache mScrollCache; 3760 3761 private int[] mDrawableState = null; 3762 3763 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 3764 3765 /** 3766 * Animator that automatically runs based on state changes. 3767 */ 3768 private StateListAnimator mStateListAnimator; 3769 3770 /** 3771 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 3772 * the user may specify which view to go to next. 3773 */ 3774 private int mNextFocusLeftId = View.NO_ID; 3775 3776 /** 3777 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 3778 * the user may specify which view to go to next. 3779 */ 3780 private int mNextFocusRightId = View.NO_ID; 3781 3782 /** 3783 * When this view has focus and the next focus is {@link #FOCUS_UP}, 3784 * the user may specify which view to go to next. 3785 */ 3786 private int mNextFocusUpId = View.NO_ID; 3787 3788 /** 3789 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 3790 * the user may specify which view to go to next. 3791 */ 3792 private int mNextFocusDownId = View.NO_ID; 3793 3794 /** 3795 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 3796 * the user may specify which view to go to next. 3797 */ 3798 int mNextFocusForwardId = View.NO_ID; 3799 3800 /** 3801 * User-specified next keyboard navigation cluster. 3802 */ 3803 int mNextClusterForwardId = View.NO_ID; 3804 3805 private CheckForLongPress mPendingCheckForLongPress; 3806 private CheckForTap mPendingCheckForTap = null; 3807 private PerformClick mPerformClick; 3808 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 3809 3810 private UnsetPressedState mUnsetPressedState; 3811 3812 /** 3813 * Whether the long press's action has been invoked. The tap's action is invoked on the 3814 * up event while a long press is invoked as soon as the long press duration is reached, so 3815 * a long press could be performed before the tap is checked, in which case the tap's action 3816 * should not be invoked. 3817 */ 3818 private boolean mHasPerformedLongPress; 3819 3820 /** 3821 * Whether a context click button is currently pressed down. This is true when the stylus is 3822 * touching the screen and the primary button has been pressed, or if a mouse's right button is 3823 * pressed. This is false once the button is released or if the stylus has been lifted. 3824 */ 3825 private boolean mInContextButtonPress; 3826 3827 /** 3828 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 3829 * true after a stylus button press has occured, when the next up event should not be recognized 3830 * as a tap. 3831 */ 3832 private boolean mIgnoreNextUpEvent; 3833 3834 /** 3835 * The minimum height of the view. We'll try our best to have the height 3836 * of this view to at least this amount. 3837 */ 3838 @ViewDebug.ExportedProperty(category = "measurement") 3839 private int mMinHeight; 3840 3841 /** 3842 * The minimum width of the view. We'll try our best to have the width 3843 * of this view to at least this amount. 3844 */ 3845 @ViewDebug.ExportedProperty(category = "measurement") 3846 private int mMinWidth; 3847 3848 /** 3849 * The delegate to handle touch events that are physically in this view 3850 * but should be handled by another view. 3851 */ 3852 private TouchDelegate mTouchDelegate = null; 3853 3854 /** 3855 * Solid color to use as a background when creating the drawing cache. Enables 3856 * the cache to use 16 bit bitmaps instead of 32 bit. 3857 */ 3858 private int mDrawingCacheBackgroundColor = 0; 3859 3860 /** 3861 * Special tree observer used when mAttachInfo is null. 3862 */ 3863 private ViewTreeObserver mFloatingTreeObserver; 3864 3865 /** 3866 * Cache the touch slop from the context that created the view. 3867 */ 3868 private int mTouchSlop; 3869 3870 /** 3871 * Object that handles automatic animation of view properties. 3872 */ 3873 private ViewPropertyAnimator mAnimator = null; 3874 3875 /** 3876 * List of registered FrameMetricsObservers. 3877 */ 3878 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 3879 3880 /** 3881 * Flag indicating that a drag can cross window boundaries. When 3882 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3883 * with this flag set, all visible applications with targetSdkVersion >= 3884 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 3885 * in the drag operation and receive the dragged content. 3886 * 3887 * <p>If this is the only flag set, then the drag recipient will only have access to text data 3888 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 3889 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 3890 */ 3891 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 3892 3893 /** 3894 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3895 * request read access to the content URI(s) contained in the {@link ClipData} object. 3896 * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION 3897 */ 3898 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 3899 3900 /** 3901 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3902 * request write access to the content URI(s) contained in the {@link ClipData} object. 3903 * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION 3904 */ 3905 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 3906 3907 /** 3908 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3909 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 3910 * reboots until explicitly revoked with 3911 * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}. 3912 * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION 3913 */ 3914 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 3915 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 3916 3917 /** 3918 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3919 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 3920 * match against the original granted URI. 3921 * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION 3922 */ 3923 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 3924 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 3925 3926 /** 3927 * Flag indicating that the drag shadow will be opaque. When 3928 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3929 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 3930 */ 3931 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 3932 3933 /** 3934 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 3935 */ 3936 private float mVerticalScrollFactor; 3937 3938 /** 3939 * Position of the vertical scroll bar. 3940 */ 3941 private int mVerticalScrollbarPosition; 3942 3943 /** 3944 * Position the scroll bar at the default position as determined by the system. 3945 */ 3946 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 3947 3948 /** 3949 * Position the scroll bar along the left edge. 3950 */ 3951 public static final int SCROLLBAR_POSITION_LEFT = 1; 3952 3953 /** 3954 * Position the scroll bar along the right edge. 3955 */ 3956 public static final int SCROLLBAR_POSITION_RIGHT = 2; 3957 3958 /** 3959 * Indicates that the view does not have a layer. 3960 * 3961 * @see #getLayerType() 3962 * @see #setLayerType(int, android.graphics.Paint) 3963 * @see #LAYER_TYPE_SOFTWARE 3964 * @see #LAYER_TYPE_HARDWARE 3965 */ 3966 public static final int LAYER_TYPE_NONE = 0; 3967 3968 /** 3969 * <p>Indicates that the view has a software layer. A software layer is backed 3970 * by a bitmap and causes the view to be rendered using Android's software 3971 * rendering pipeline, even if hardware acceleration is enabled.</p> 3972 * 3973 * <p>Software layers have various usages:</p> 3974 * <p>When the application is not using hardware acceleration, a software layer 3975 * is useful to apply a specific color filter and/or blending mode and/or 3976 * translucency to a view and all its children.</p> 3977 * <p>When the application is using hardware acceleration, a software layer 3978 * is useful to render drawing primitives not supported by the hardware 3979 * accelerated pipeline. It can also be used to cache a complex view tree 3980 * into a texture and reduce the complexity of drawing operations. For instance, 3981 * when animating a complex view tree with a translation, a software layer can 3982 * be used to render the view tree only once.</p> 3983 * <p>Software layers should be avoided when the affected view tree updates 3984 * often. Every update will require to re-render the software layer, which can 3985 * potentially be slow (particularly when hardware acceleration is turned on 3986 * since the layer will have to be uploaded into a hardware texture after every 3987 * update.)</p> 3988 * 3989 * @see #getLayerType() 3990 * @see #setLayerType(int, android.graphics.Paint) 3991 * @see #LAYER_TYPE_NONE 3992 * @see #LAYER_TYPE_HARDWARE 3993 */ 3994 public static final int LAYER_TYPE_SOFTWARE = 1; 3995 3996 /** 3997 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 3998 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 3999 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4000 * rendering pipeline, but only if hardware acceleration is turned on for the 4001 * view hierarchy. When hardware acceleration is turned off, hardware layers 4002 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4003 * 4004 * <p>A hardware layer is useful to apply a specific color filter and/or 4005 * blending mode and/or translucency to a view and all its children.</p> 4006 * <p>A hardware layer can be used to cache a complex view tree into a 4007 * texture and reduce the complexity of drawing operations. For instance, 4008 * when animating a complex view tree with a translation, a hardware layer can 4009 * be used to render the view tree only once.</p> 4010 * <p>A hardware layer can also be used to increase the rendering quality when 4011 * rotation transformations are applied on a view. It can also be used to 4012 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4013 * 4014 * @see #getLayerType() 4015 * @see #setLayerType(int, android.graphics.Paint) 4016 * @see #LAYER_TYPE_NONE 4017 * @see #LAYER_TYPE_SOFTWARE 4018 */ 4019 public static final int LAYER_TYPE_HARDWARE = 2; 4020 4021 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4022 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4023 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4024 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4025 }) 4026 int mLayerType = LAYER_TYPE_NONE; 4027 Paint mLayerPaint; 4028 4029 4030 /** 4031 * Set when a request was made to decide if views in an {@link android.app.Activity} can be 4032 * auto-filled by an {@link android.service.autofill.AutoFillService}. 4033 * 4034 * <p>Since this request is made without a explicit user consent, the resulting 4035 * {@link android.app.assist.AssistStructure} should not contain any PII 4036 * (Personally Identifiable Information). 4037 * 4038 * <p>Examples: 4039 * <ul> 4040 * <li>{@link android.widget.TextView} texts should only be included when they were set by 4041 * static resources. 4042 * <li>{@link android.webkit.WebView} virtual children should be restricted to a subset of 4043 * input fields and tags (like {@code id}). 4044 * </ul> 4045 */ 4046 // TODO(b/33197203) (b/34078930): improve documentation: mention all cases, show examples, etc. 4047 // In particular, be more specific about webview restrictions 4048 public static final int AUTO_FILL_FLAG_TYPE_FILL = 0x1; 4049 4050 /** 4051 * Set when the user explicitly asked a {@link android.service.autofill.AutoFillService} to save 4052 * the value of the {@link View}s in an {@link android.app.Activity}. 4053 * 4054 * <p>The resulting {@link android.app.assist.AssistStructure} can contain any kind of PII 4055 * (Personally Identifiable Information). For example, the text of password fields should be 4056 * included since that's what's typically saved. 4057 */ 4058 public static final int AUTO_FILL_FLAG_TYPE_SAVE = 0x2; 4059 4060 /** 4061 * Set to true when drawing cache is enabled and cannot be created. 4062 * 4063 * @hide 4064 */ 4065 public boolean mCachingFailed; 4066 private Bitmap mDrawingCache; 4067 private Bitmap mUnscaledDrawingCache; 4068 4069 /** 4070 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4071 * <p> 4072 * When non-null and valid, this is expected to contain an up-to-date copy 4073 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4074 * cleanup. 4075 */ 4076 final RenderNode mRenderNode; 4077 4078 /** 4079 * Set to true when the view is sending hover accessibility events because it 4080 * is the innermost hovered view. 4081 */ 4082 private boolean mSendingHoverAccessibilityEvents; 4083 4084 /** 4085 * Delegate for injecting accessibility functionality. 4086 */ 4087 AccessibilityDelegate mAccessibilityDelegate; 4088 4089 /** 4090 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4091 * and add/remove objects to/from the overlay directly through the Overlay methods. 4092 */ 4093 ViewOverlay mOverlay; 4094 4095 /** 4096 * The currently active parent view for receiving delegated nested scrolling events. 4097 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4098 * by {@link #stopNestedScroll()} at the same point where we clear 4099 * requestDisallowInterceptTouchEvent. 4100 */ 4101 private ViewParent mNestedScrollingParent; 4102 4103 /** 4104 * Consistency verifier for debugging purposes. 4105 * @hide 4106 */ 4107 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4108 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4109 new InputEventConsistencyVerifier(this, 0) : null; 4110 4111 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4112 4113 private int[] mTempNestedScrollConsumed; 4114 4115 /** 4116 * An overlay is going to draw this View instead of being drawn as part of this 4117 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4118 * when this view is invalidated. 4119 */ 4120 GhostView mGhostView; 4121 4122 /** 4123 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4124 * @hide 4125 */ 4126 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4127 public String[] mAttributes; 4128 4129 /** 4130 * Maps a Resource id to its name. 4131 */ 4132 private static SparseArray<String> mAttributeMap; 4133 4134 /** 4135 * Queue of pending runnables. Used to postpone calls to post() until this 4136 * view is attached and has a handler. 4137 */ 4138 private HandlerActionQueue mRunQueue; 4139 4140 /** 4141 * The pointer icon when the mouse hovers on this view. The default is null. 4142 */ 4143 private PointerIcon mPointerIcon; 4144 4145 /** 4146 * @hide 4147 */ 4148 String mStartActivityRequestWho; 4149 4150 @Nullable 4151 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4152 4153 /** 4154 * Simple constructor to use when creating a view from code. 4155 * 4156 * @param context The Context the view is running in, through which it can 4157 * access the current theme, resources, etc. 4158 */ 4159 public View(Context context) { 4160 mContext = context; 4161 mResources = context != null ? context.getResources() : null; 4162 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 4163 // Set some flags defaults 4164 mPrivateFlags2 = 4165 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4166 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4167 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4168 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4169 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4170 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4171 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4172 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4173 mUserPaddingStart = UNDEFINED_PADDING; 4174 mUserPaddingEnd = UNDEFINED_PADDING; 4175 mRenderNode = RenderNode.create(getClass().getName(), this); 4176 4177 if (!sCompatibilityDone && context != null) { 4178 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4179 4180 // Older apps may need this compatibility hack for measurement. 4181 sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1; 4182 4183 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4184 // of whether a layout was requested on that View. 4185 sIgnoreMeasureCache = targetSdkVersion < KITKAT; 4186 4187 Canvas.sCompatibilityRestore = targetSdkVersion < M; 4188 4189 // In M and newer, our widgets can pass a "hint" value in the size 4190 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4191 // know what the expected parent size is going to be, so e.g. list items can size 4192 // themselves at 1/3 the size of their container. It breaks older apps though, 4193 // specifically apps that use some popular open source libraries. 4194 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < M; 4195 4196 // Old versions of the platform would give different results from 4197 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4198 // modes, so we always need to run an additional EXACTLY pass. 4199 sAlwaysRemeasureExactly = targetSdkVersion <= M; 4200 4201 // Prior to N, layout params could change without requiring a 4202 // subsequent call to setLayoutParams() and they would usually 4203 // work. Partial layout breaks this assumption. 4204 sLayoutParamsAlwaysChanged = targetSdkVersion <= M; 4205 4206 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4207 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4208 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M; 4209 4210 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4211 // in apps so we target check it to avoid breaking existing apps. 4212 sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N; 4213 4214 sCascadedDragDrop = targetSdkVersion < N; 4215 4216 sCompatibilityDone = true; 4217 } 4218 } 4219 4220 /** 4221 * Constructor that is called when inflating a view from XML. This is called 4222 * when a view is being constructed from an XML file, supplying attributes 4223 * that were specified in the XML file. This version uses a default style of 4224 * 0, so the only attribute values applied are those in the Context's Theme 4225 * and the given AttributeSet. 4226 * 4227 * <p> 4228 * The method onFinishInflate() will be called after all children have been 4229 * added. 4230 * 4231 * @param context The Context the view is running in, through which it can 4232 * access the current theme, resources, etc. 4233 * @param attrs The attributes of the XML tag that is inflating the view. 4234 * @see #View(Context, AttributeSet, int) 4235 */ 4236 public View(Context context, @Nullable AttributeSet attrs) { 4237 this(context, attrs, 0); 4238 } 4239 4240 /** 4241 * Perform inflation from XML and apply a class-specific base style from a 4242 * theme attribute. This constructor of View allows subclasses to use their 4243 * own base style when they are inflating. For example, a Button class's 4244 * constructor would call this version of the super class constructor and 4245 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4246 * allows the theme's button style to modify all of the base view attributes 4247 * (in particular its background) as well as the Button class's attributes. 4248 * 4249 * @param context The Context the view is running in, through which it can 4250 * access the current theme, resources, etc. 4251 * @param attrs The attributes of the XML tag that is inflating the view. 4252 * @param defStyleAttr An attribute in the current theme that contains a 4253 * reference to a style resource that supplies default values for 4254 * the view. Can be 0 to not look for defaults. 4255 * @see #View(Context, AttributeSet) 4256 */ 4257 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4258 this(context, attrs, defStyleAttr, 0); 4259 } 4260 4261 /** 4262 * Perform inflation from XML and apply a class-specific base style from a 4263 * theme attribute or style resource. This constructor of View allows 4264 * subclasses to use their own base style when they are inflating. 4265 * <p> 4266 * When determining the final value of a particular attribute, there are 4267 * four inputs that come into play: 4268 * <ol> 4269 * <li>Any attribute values in the given AttributeSet. 4270 * <li>The style resource specified in the AttributeSet (named "style"). 4271 * <li>The default style specified by <var>defStyleAttr</var>. 4272 * <li>The default style specified by <var>defStyleRes</var>. 4273 * <li>The base values in this theme. 4274 * </ol> 4275 * <p> 4276 * Each of these inputs is considered in-order, with the first listed taking 4277 * precedence over the following ones. In other words, if in the 4278 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4279 * , then the button's text will <em>always</em> be black, regardless of 4280 * what is specified in any of the styles. 4281 * 4282 * @param context The Context the view is running in, through which it can 4283 * access the current theme, resources, etc. 4284 * @param attrs The attributes of the XML tag that is inflating the view. 4285 * @param defStyleAttr An attribute in the current theme that contains a 4286 * reference to a style resource that supplies default values for 4287 * the view. Can be 0 to not look for defaults. 4288 * @param defStyleRes A resource identifier of a style resource that 4289 * supplies default values for the view, used only if 4290 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4291 * to not look for defaults. 4292 * @see #View(Context, AttributeSet, int) 4293 */ 4294 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4295 this(context); 4296 4297 final TypedArray a = context.obtainStyledAttributes( 4298 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4299 4300 if (mDebugViewAttributes) { 4301 saveAttributeData(attrs, a); 4302 } 4303 4304 Drawable background = null; 4305 4306 int leftPadding = -1; 4307 int topPadding = -1; 4308 int rightPadding = -1; 4309 int bottomPadding = -1; 4310 int startPadding = UNDEFINED_PADDING; 4311 int endPadding = UNDEFINED_PADDING; 4312 4313 int padding = -1; 4314 int paddingHorizontal = -1; 4315 int paddingVertical = -1; 4316 4317 int viewFlagValues = 0; 4318 int viewFlagMasks = 0; 4319 4320 boolean setScrollContainer = false; 4321 4322 int x = 0; 4323 int y = 0; 4324 4325 float tx = 0; 4326 float ty = 0; 4327 float tz = 0; 4328 float elevation = 0; 4329 float rotation = 0; 4330 float rotationX = 0; 4331 float rotationY = 0; 4332 float sx = 1f; 4333 float sy = 1f; 4334 boolean transformSet = false; 4335 4336 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4337 int overScrollMode = mOverScrollMode; 4338 boolean initializeScrollbars = false; 4339 boolean initializeScrollIndicators = false; 4340 4341 boolean startPaddingDefined = false; 4342 boolean endPaddingDefined = false; 4343 boolean leftPaddingDefined = false; 4344 boolean rightPaddingDefined = false; 4345 4346 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4347 4348 // Set default values. 4349 viewFlagValues |= FOCUSABLE_AUTO; 4350 viewFlagMasks |= FOCUSABLE_AUTO; 4351 4352 final int N = a.getIndexCount(); 4353 for (int i = 0; i < N; i++) { 4354 int attr = a.getIndex(i); 4355 switch (attr) { 4356 case com.android.internal.R.styleable.View_background: 4357 background = a.getDrawable(attr); 4358 break; 4359 case com.android.internal.R.styleable.View_padding: 4360 padding = a.getDimensionPixelSize(attr, -1); 4361 mUserPaddingLeftInitial = padding; 4362 mUserPaddingRightInitial = padding; 4363 leftPaddingDefined = true; 4364 rightPaddingDefined = true; 4365 break; 4366 case com.android.internal.R.styleable.View_paddingHorizontal: 4367 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4368 mUserPaddingLeftInitial = paddingHorizontal; 4369 mUserPaddingRightInitial = paddingHorizontal; 4370 leftPaddingDefined = true; 4371 rightPaddingDefined = true; 4372 break; 4373 case com.android.internal.R.styleable.View_paddingVertical: 4374 paddingVertical = a.getDimensionPixelSize(attr, -1); 4375 break; 4376 case com.android.internal.R.styleable.View_paddingLeft: 4377 leftPadding = a.getDimensionPixelSize(attr, -1); 4378 mUserPaddingLeftInitial = leftPadding; 4379 leftPaddingDefined = true; 4380 break; 4381 case com.android.internal.R.styleable.View_paddingTop: 4382 topPadding = a.getDimensionPixelSize(attr, -1); 4383 break; 4384 case com.android.internal.R.styleable.View_paddingRight: 4385 rightPadding = a.getDimensionPixelSize(attr, -1); 4386 mUserPaddingRightInitial = rightPadding; 4387 rightPaddingDefined = true; 4388 break; 4389 case com.android.internal.R.styleable.View_paddingBottom: 4390 bottomPadding = a.getDimensionPixelSize(attr, -1); 4391 break; 4392 case com.android.internal.R.styleable.View_paddingStart: 4393 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4394 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4395 break; 4396 case com.android.internal.R.styleable.View_paddingEnd: 4397 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4398 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4399 break; 4400 case com.android.internal.R.styleable.View_scrollX: 4401 x = a.getDimensionPixelOffset(attr, 0); 4402 break; 4403 case com.android.internal.R.styleable.View_scrollY: 4404 y = a.getDimensionPixelOffset(attr, 0); 4405 break; 4406 case com.android.internal.R.styleable.View_alpha: 4407 setAlpha(a.getFloat(attr, 1f)); 4408 break; 4409 case com.android.internal.R.styleable.View_transformPivotX: 4410 setPivotX(a.getDimension(attr, 0)); 4411 break; 4412 case com.android.internal.R.styleable.View_transformPivotY: 4413 setPivotY(a.getDimension(attr, 0)); 4414 break; 4415 case com.android.internal.R.styleable.View_translationX: 4416 tx = a.getDimension(attr, 0); 4417 transformSet = true; 4418 break; 4419 case com.android.internal.R.styleable.View_translationY: 4420 ty = a.getDimension(attr, 0); 4421 transformSet = true; 4422 break; 4423 case com.android.internal.R.styleable.View_translationZ: 4424 tz = a.getDimension(attr, 0); 4425 transformSet = true; 4426 break; 4427 case com.android.internal.R.styleable.View_elevation: 4428 elevation = a.getDimension(attr, 0); 4429 transformSet = true; 4430 break; 4431 case com.android.internal.R.styleable.View_rotation: 4432 rotation = a.getFloat(attr, 0); 4433 transformSet = true; 4434 break; 4435 case com.android.internal.R.styleable.View_rotationX: 4436 rotationX = a.getFloat(attr, 0); 4437 transformSet = true; 4438 break; 4439 case com.android.internal.R.styleable.View_rotationY: 4440 rotationY = a.getFloat(attr, 0); 4441 transformSet = true; 4442 break; 4443 case com.android.internal.R.styleable.View_scaleX: 4444 sx = a.getFloat(attr, 1f); 4445 transformSet = true; 4446 break; 4447 case com.android.internal.R.styleable.View_scaleY: 4448 sy = a.getFloat(attr, 1f); 4449 transformSet = true; 4450 break; 4451 case com.android.internal.R.styleable.View_id: 4452 mID = a.getResourceId(attr, NO_ID); 4453 break; 4454 case com.android.internal.R.styleable.View_tag: 4455 mTag = a.getText(attr); 4456 break; 4457 case com.android.internal.R.styleable.View_fitsSystemWindows: 4458 if (a.getBoolean(attr, false)) { 4459 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4460 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4461 } 4462 break; 4463 case com.android.internal.R.styleable.View_focusable: 4464 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 4465 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 4466 viewFlagMasks |= FOCUSABLE_MASK; 4467 } 4468 break; 4469 case com.android.internal.R.styleable.View_focusableInTouchMode: 4470 if (a.getBoolean(attr, false)) { 4471 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4472 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4473 } 4474 break; 4475 case com.android.internal.R.styleable.View_clickable: 4476 if (a.getBoolean(attr, false)) { 4477 viewFlagValues |= CLICKABLE; 4478 viewFlagMasks |= CLICKABLE; 4479 } 4480 break; 4481 case com.android.internal.R.styleable.View_longClickable: 4482 if (a.getBoolean(attr, false)) { 4483 viewFlagValues |= LONG_CLICKABLE; 4484 viewFlagMasks |= LONG_CLICKABLE; 4485 } 4486 break; 4487 case com.android.internal.R.styleable.View_contextClickable: 4488 if (a.getBoolean(attr, false)) { 4489 viewFlagValues |= CONTEXT_CLICKABLE; 4490 viewFlagMasks |= CONTEXT_CLICKABLE; 4491 } 4492 break; 4493 case com.android.internal.R.styleable.View_saveEnabled: 4494 if (!a.getBoolean(attr, true)) { 4495 viewFlagValues |= SAVE_DISABLED; 4496 viewFlagMasks |= SAVE_DISABLED_MASK; 4497 } 4498 break; 4499 case com.android.internal.R.styleable.View_duplicateParentState: 4500 if (a.getBoolean(attr, false)) { 4501 viewFlagValues |= DUPLICATE_PARENT_STATE; 4502 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4503 } 4504 break; 4505 case com.android.internal.R.styleable.View_visibility: 4506 final int visibility = a.getInt(attr, 0); 4507 if (visibility != 0) { 4508 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4509 viewFlagMasks |= VISIBILITY_MASK; 4510 } 4511 break; 4512 case com.android.internal.R.styleable.View_layoutDirection: 4513 // Clear any layout direction flags (included resolved bits) already set 4514 mPrivateFlags2 &= 4515 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4516 // Set the layout direction flags depending on the value of the attribute 4517 final int layoutDirection = a.getInt(attr, -1); 4518 final int value = (layoutDirection != -1) ? 4519 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4520 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4521 break; 4522 case com.android.internal.R.styleable.View_drawingCacheQuality: 4523 final int cacheQuality = a.getInt(attr, 0); 4524 if (cacheQuality != 0) { 4525 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4526 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4527 } 4528 break; 4529 case com.android.internal.R.styleable.View_contentDescription: 4530 setContentDescription(a.getString(attr)); 4531 break; 4532 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4533 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4534 break; 4535 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4536 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4537 break; 4538 case com.android.internal.R.styleable.View_labelFor: 4539 setLabelFor(a.getResourceId(attr, NO_ID)); 4540 break; 4541 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4542 if (!a.getBoolean(attr, true)) { 4543 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4544 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4545 } 4546 break; 4547 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4548 if (!a.getBoolean(attr, true)) { 4549 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4550 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4551 } 4552 break; 4553 case R.styleable.View_scrollbars: 4554 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4555 if (scrollbars != SCROLLBARS_NONE) { 4556 viewFlagValues |= scrollbars; 4557 viewFlagMasks |= SCROLLBARS_MASK; 4558 initializeScrollbars = true; 4559 } 4560 break; 4561 //noinspection deprecation 4562 case R.styleable.View_fadingEdge: 4563 if (targetSdkVersion >= ICE_CREAM_SANDWICH) { 4564 // Ignore the attribute starting with ICS 4565 break; 4566 } 4567 // With builds < ICS, fall through and apply fading edges 4568 case R.styleable.View_requiresFadingEdge: 4569 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4570 if (fadingEdge != FADING_EDGE_NONE) { 4571 viewFlagValues |= fadingEdge; 4572 viewFlagMasks |= FADING_EDGE_MASK; 4573 initializeFadingEdgeInternal(a); 4574 } 4575 break; 4576 case R.styleable.View_scrollbarStyle: 4577 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4578 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4579 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4580 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4581 } 4582 break; 4583 case R.styleable.View_isScrollContainer: 4584 setScrollContainer = true; 4585 if (a.getBoolean(attr, false)) { 4586 setScrollContainer(true); 4587 } 4588 break; 4589 case com.android.internal.R.styleable.View_keepScreenOn: 4590 if (a.getBoolean(attr, false)) { 4591 viewFlagValues |= KEEP_SCREEN_ON; 4592 viewFlagMasks |= KEEP_SCREEN_ON; 4593 } 4594 break; 4595 case R.styleable.View_filterTouchesWhenObscured: 4596 if (a.getBoolean(attr, false)) { 4597 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4598 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4599 } 4600 break; 4601 case R.styleable.View_nextFocusLeft: 4602 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4603 break; 4604 case R.styleable.View_nextFocusRight: 4605 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4606 break; 4607 case R.styleable.View_nextFocusUp: 4608 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4609 break; 4610 case R.styleable.View_nextFocusDown: 4611 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4612 break; 4613 case R.styleable.View_nextFocusForward: 4614 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4615 break; 4616 case R.styleable.View_nextClusterForward: 4617 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 4618 break; 4619 case R.styleable.View_minWidth: 4620 mMinWidth = a.getDimensionPixelSize(attr, 0); 4621 break; 4622 case R.styleable.View_minHeight: 4623 mMinHeight = a.getDimensionPixelSize(attr, 0); 4624 break; 4625 case R.styleable.View_onClick: 4626 if (context.isRestricted()) { 4627 throw new IllegalStateException("The android:onClick attribute cannot " 4628 + "be used within a restricted context"); 4629 } 4630 4631 final String handlerName = a.getString(attr); 4632 if (handlerName != null) { 4633 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 4634 } 4635 break; 4636 case R.styleable.View_overScrollMode: 4637 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 4638 break; 4639 case R.styleable.View_verticalScrollbarPosition: 4640 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 4641 break; 4642 case R.styleable.View_layerType: 4643 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 4644 break; 4645 case R.styleable.View_textDirection: 4646 // Clear any text direction flag already set 4647 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 4648 // Set the text direction flags depending on the value of the attribute 4649 final int textDirection = a.getInt(attr, -1); 4650 if (textDirection != -1) { 4651 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 4652 } 4653 break; 4654 case R.styleable.View_textAlignment: 4655 // Clear any text alignment flag already set 4656 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 4657 // Set the text alignment flag depending on the value of the attribute 4658 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 4659 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 4660 break; 4661 case R.styleable.View_importantForAccessibility: 4662 setImportantForAccessibility(a.getInt(attr, 4663 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 4664 break; 4665 case R.styleable.View_accessibilityLiveRegion: 4666 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 4667 break; 4668 case R.styleable.View_transitionName: 4669 setTransitionName(a.getString(attr)); 4670 break; 4671 case R.styleable.View_nestedScrollingEnabled: 4672 setNestedScrollingEnabled(a.getBoolean(attr, false)); 4673 break; 4674 case R.styleable.View_stateListAnimator: 4675 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 4676 a.getResourceId(attr, 0))); 4677 break; 4678 case R.styleable.View_backgroundTint: 4679 // This will get applied later during setBackground(). 4680 if (mBackgroundTint == null) { 4681 mBackgroundTint = new TintInfo(); 4682 } 4683 mBackgroundTint.mTintList = a.getColorStateList( 4684 R.styleable.View_backgroundTint); 4685 mBackgroundTint.mHasTintList = true; 4686 break; 4687 case R.styleable.View_backgroundTintMode: 4688 // This will get applied later during setBackground(). 4689 if (mBackgroundTint == null) { 4690 mBackgroundTint = new TintInfo(); 4691 } 4692 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 4693 R.styleable.View_backgroundTintMode, -1), null); 4694 mBackgroundTint.mHasTintMode = true; 4695 break; 4696 case R.styleable.View_outlineProvider: 4697 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 4698 PROVIDER_BACKGROUND)); 4699 break; 4700 case R.styleable.View_foreground: 4701 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4702 setForeground(a.getDrawable(attr)); 4703 } 4704 break; 4705 case R.styleable.View_foregroundGravity: 4706 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4707 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 4708 } 4709 break; 4710 case R.styleable.View_foregroundTintMode: 4711 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4712 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 4713 } 4714 break; 4715 case R.styleable.View_foregroundTint: 4716 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4717 setForegroundTintList(a.getColorStateList(attr)); 4718 } 4719 break; 4720 case R.styleable.View_foregroundInsidePadding: 4721 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4722 if (mForegroundInfo == null) { 4723 mForegroundInfo = new ForegroundInfo(); 4724 } 4725 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 4726 mForegroundInfo.mInsidePadding); 4727 } 4728 break; 4729 case R.styleable.View_scrollIndicators: 4730 final int scrollIndicators = 4731 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 4732 & SCROLL_INDICATORS_PFLAG3_MASK; 4733 if (scrollIndicators != 0) { 4734 mPrivateFlags3 |= scrollIndicators; 4735 initializeScrollIndicators = true; 4736 } 4737 break; 4738 case R.styleable.View_pointerIcon: 4739 final int resourceId = a.getResourceId(attr, 0); 4740 if (resourceId != 0) { 4741 setPointerIcon(PointerIcon.load( 4742 context.getResources(), resourceId)); 4743 } else { 4744 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 4745 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 4746 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 4747 } 4748 } 4749 break; 4750 case R.styleable.View_forceHasOverlappingRendering: 4751 if (a.peekValue(attr) != null) { 4752 forceHasOverlappingRendering(a.getBoolean(attr, true)); 4753 } 4754 break; 4755 case R.styleable.View_tooltipText: 4756 setTooltipText(a.getText(attr)); 4757 break; 4758 case R.styleable.View_keyboardNavigationCluster: 4759 if (a.peekValue(attr) != null) { 4760 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 4761 } 4762 break; 4763 case R.styleable.View_focusedByDefault: 4764 if (a.peekValue(attr) != null) { 4765 setFocusedByDefault(a.getBoolean(attr, true)); 4766 } 4767 break; 4768 } 4769 } 4770 4771 setOverScrollMode(overScrollMode); 4772 4773 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 4774 // the resolved layout direction). Those cached values will be used later during padding 4775 // resolution. 4776 mUserPaddingStart = startPadding; 4777 mUserPaddingEnd = endPadding; 4778 4779 if (background != null) { 4780 setBackground(background); 4781 } 4782 4783 // setBackground above will record that padding is currently provided by the background. 4784 // If we have padding specified via xml, record that here instead and use it. 4785 mLeftPaddingDefined = leftPaddingDefined; 4786 mRightPaddingDefined = rightPaddingDefined; 4787 4788 if (padding >= 0) { 4789 leftPadding = padding; 4790 topPadding = padding; 4791 rightPadding = padding; 4792 bottomPadding = padding; 4793 mUserPaddingLeftInitial = padding; 4794 mUserPaddingRightInitial = padding; 4795 } else { 4796 if (paddingHorizontal >= 0) { 4797 leftPadding = paddingHorizontal; 4798 rightPadding = paddingHorizontal; 4799 mUserPaddingLeftInitial = paddingHorizontal; 4800 mUserPaddingRightInitial = paddingHorizontal; 4801 } 4802 if (paddingVertical >= 0) { 4803 topPadding = paddingVertical; 4804 bottomPadding = paddingVertical; 4805 } 4806 } 4807 4808 if (isRtlCompatibilityMode()) { 4809 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 4810 // left / right padding are used if defined (meaning here nothing to do). If they are not 4811 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 4812 // start / end and resolve them as left / right (layout direction is not taken into account). 4813 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4814 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4815 // defined. 4816 if (!mLeftPaddingDefined && startPaddingDefined) { 4817 leftPadding = startPadding; 4818 } 4819 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 4820 if (!mRightPaddingDefined && endPaddingDefined) { 4821 rightPadding = endPadding; 4822 } 4823 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 4824 } else { 4825 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 4826 // values defined. Otherwise, left /right values are used. 4827 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4828 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4829 // defined. 4830 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 4831 4832 if (mLeftPaddingDefined && !hasRelativePadding) { 4833 mUserPaddingLeftInitial = leftPadding; 4834 } 4835 if (mRightPaddingDefined && !hasRelativePadding) { 4836 mUserPaddingRightInitial = rightPadding; 4837 } 4838 } 4839 4840 internalSetPadding( 4841 mUserPaddingLeftInitial, 4842 topPadding >= 0 ? topPadding : mPaddingTop, 4843 mUserPaddingRightInitial, 4844 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 4845 4846 if (viewFlagMasks != 0) { 4847 setFlags(viewFlagValues, viewFlagMasks); 4848 } 4849 4850 if (initializeScrollbars) { 4851 initializeScrollbarsInternal(a); 4852 } 4853 4854 if (initializeScrollIndicators) { 4855 initializeScrollIndicatorsInternal(); 4856 } 4857 4858 a.recycle(); 4859 4860 // Needs to be called after mViewFlags is set 4861 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4862 recomputePadding(); 4863 } 4864 4865 if (x != 0 || y != 0) { 4866 scrollTo(x, y); 4867 } 4868 4869 if (transformSet) { 4870 setTranslationX(tx); 4871 setTranslationY(ty); 4872 setTranslationZ(tz); 4873 setElevation(elevation); 4874 setRotation(rotation); 4875 setRotationX(rotationX); 4876 setRotationY(rotationY); 4877 setScaleX(sx); 4878 setScaleY(sy); 4879 } 4880 4881 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 4882 setScrollContainer(true); 4883 } 4884 4885 computeOpaqueFlags(); 4886 } 4887 4888 /** 4889 * An implementation of OnClickListener that attempts to lazily load a 4890 * named click handling method from a parent or ancestor context. 4891 */ 4892 private static class DeclaredOnClickListener implements OnClickListener { 4893 private final View mHostView; 4894 private final String mMethodName; 4895 4896 private Method mResolvedMethod; 4897 private Context mResolvedContext; 4898 4899 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 4900 mHostView = hostView; 4901 mMethodName = methodName; 4902 } 4903 4904 @Override 4905 public void onClick(@NonNull View v) { 4906 if (mResolvedMethod == null) { 4907 resolveMethod(mHostView.getContext(), mMethodName); 4908 } 4909 4910 try { 4911 mResolvedMethod.invoke(mResolvedContext, v); 4912 } catch (IllegalAccessException e) { 4913 throw new IllegalStateException( 4914 "Could not execute non-public method for android:onClick", e); 4915 } catch (InvocationTargetException e) { 4916 throw new IllegalStateException( 4917 "Could not execute method for android:onClick", e); 4918 } 4919 } 4920 4921 @NonNull 4922 private void resolveMethod(@Nullable Context context, @NonNull String name) { 4923 while (context != null) { 4924 try { 4925 if (!context.isRestricted()) { 4926 final Method method = context.getClass().getMethod(mMethodName, View.class); 4927 if (method != null) { 4928 mResolvedMethod = method; 4929 mResolvedContext = context; 4930 return; 4931 } 4932 } 4933 } catch (NoSuchMethodException e) { 4934 // Failed to find method, keep searching up the hierarchy. 4935 } 4936 4937 if (context instanceof ContextWrapper) { 4938 context = ((ContextWrapper) context).getBaseContext(); 4939 } else { 4940 // Can't search up the hierarchy, null out and fail. 4941 context = null; 4942 } 4943 } 4944 4945 final int id = mHostView.getId(); 4946 final String idText = id == NO_ID ? "" : " with id '" 4947 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 4948 throw new IllegalStateException("Could not find method " + mMethodName 4949 + "(View) in a parent or ancestor Context for android:onClick " 4950 + "attribute defined on view " + mHostView.getClass() + idText); 4951 } 4952 } 4953 4954 /** 4955 * Non-public constructor for use in testing 4956 */ 4957 View() { 4958 mResources = null; 4959 mRenderNode = RenderNode.create(getClass().getName(), this); 4960 } 4961 4962 final boolean debugDraw() { 4963 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 4964 } 4965 4966 private static SparseArray<String> getAttributeMap() { 4967 if (mAttributeMap == null) { 4968 mAttributeMap = new SparseArray<>(); 4969 } 4970 return mAttributeMap; 4971 } 4972 4973 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 4974 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 4975 final int indexCount = t.getIndexCount(); 4976 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 4977 4978 int i = 0; 4979 4980 // Store raw XML attributes. 4981 for (int j = 0; j < attrsCount; ++j) { 4982 attributes[i] = attrs.getAttributeName(j); 4983 attributes[i + 1] = attrs.getAttributeValue(j); 4984 i += 2; 4985 } 4986 4987 // Store resolved styleable attributes. 4988 final Resources res = t.getResources(); 4989 final SparseArray<String> attributeMap = getAttributeMap(); 4990 for (int j = 0; j < indexCount; ++j) { 4991 final int index = t.getIndex(j); 4992 if (!t.hasValueOrEmpty(index)) { 4993 // Value is undefined. Skip it. 4994 continue; 4995 } 4996 4997 final int resourceId = t.getResourceId(index, 0); 4998 if (resourceId == 0) { 4999 // Value is not a reference. Skip it. 5000 continue; 5001 } 5002 5003 String resourceName = attributeMap.get(resourceId); 5004 if (resourceName == null) { 5005 try { 5006 resourceName = res.getResourceName(resourceId); 5007 } catch (Resources.NotFoundException e) { 5008 resourceName = "0x" + Integer.toHexString(resourceId); 5009 } 5010 attributeMap.put(resourceId, resourceName); 5011 } 5012 5013 attributes[i] = resourceName; 5014 attributes[i + 1] = t.getString(index); 5015 i += 2; 5016 } 5017 5018 // Trim to fit contents. 5019 final String[] trimmed = new String[i]; 5020 System.arraycopy(attributes, 0, trimmed, 0, i); 5021 mAttributes = trimmed; 5022 } 5023 5024 public String toString() { 5025 StringBuilder out = new StringBuilder(128); 5026 out.append(getClass().getName()); 5027 out.append('{'); 5028 out.append(Integer.toHexString(System.identityHashCode(this))); 5029 out.append(' '); 5030 switch (mViewFlags&VISIBILITY_MASK) { 5031 case VISIBLE: out.append('V'); break; 5032 case INVISIBLE: out.append('I'); break; 5033 case GONE: out.append('G'); break; 5034 default: out.append('.'); break; 5035 } 5036 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 5037 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5038 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5039 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5040 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5041 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5042 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5043 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5044 out.append(' '); 5045 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5046 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5047 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5048 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5049 out.append('p'); 5050 } else { 5051 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5052 } 5053 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5054 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5055 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5056 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5057 out.append(' '); 5058 out.append(mLeft); 5059 out.append(','); 5060 out.append(mTop); 5061 out.append('-'); 5062 out.append(mRight); 5063 out.append(','); 5064 out.append(mBottom); 5065 final int id = getId(); 5066 if (id != NO_ID) { 5067 out.append(" #"); 5068 out.append(Integer.toHexString(id)); 5069 final Resources r = mResources; 5070 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5071 try { 5072 String pkgname; 5073 switch (id&0xff000000) { 5074 case 0x7f000000: 5075 pkgname="app"; 5076 break; 5077 case 0x01000000: 5078 pkgname="android"; 5079 break; 5080 default: 5081 pkgname = r.getResourcePackageName(id); 5082 break; 5083 } 5084 String typename = r.getResourceTypeName(id); 5085 String entryname = r.getResourceEntryName(id); 5086 out.append(" "); 5087 out.append(pkgname); 5088 out.append(":"); 5089 out.append(typename); 5090 out.append("/"); 5091 out.append(entryname); 5092 } catch (Resources.NotFoundException e) { 5093 } 5094 } 5095 } 5096 out.append("}"); 5097 return out.toString(); 5098 } 5099 5100 /** 5101 * <p> 5102 * Initializes the fading edges from a given set of styled attributes. This 5103 * method should be called by subclasses that need fading edges and when an 5104 * instance of these subclasses is created programmatically rather than 5105 * being inflated from XML. This method is automatically called when the XML 5106 * is inflated. 5107 * </p> 5108 * 5109 * @param a the styled attributes set to initialize the fading edges from 5110 * 5111 * @removed 5112 */ 5113 protected void initializeFadingEdge(TypedArray a) { 5114 // This method probably shouldn't have been included in the SDK to begin with. 5115 // It relies on 'a' having been initialized using an attribute filter array that is 5116 // not publicly available to the SDK. The old method has been renamed 5117 // to initializeFadingEdgeInternal and hidden for framework use only; 5118 // this one initializes using defaults to make it safe to call for apps. 5119 5120 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5121 5122 initializeFadingEdgeInternal(arr); 5123 5124 arr.recycle(); 5125 } 5126 5127 /** 5128 * <p> 5129 * Initializes the fading edges from a given set of styled attributes. This 5130 * method should be called by subclasses that need fading edges and when an 5131 * instance of these subclasses is created programmatically rather than 5132 * being inflated from XML. This method is automatically called when the XML 5133 * is inflated. 5134 * </p> 5135 * 5136 * @param a the styled attributes set to initialize the fading edges from 5137 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5138 */ 5139 protected void initializeFadingEdgeInternal(TypedArray a) { 5140 initScrollCache(); 5141 5142 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5143 R.styleable.View_fadingEdgeLength, 5144 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5145 } 5146 5147 /** 5148 * Returns the size of the vertical faded edges used to indicate that more 5149 * content in this view is visible. 5150 * 5151 * @return The size in pixels of the vertical faded edge or 0 if vertical 5152 * faded edges are not enabled for this view. 5153 * @attr ref android.R.styleable#View_fadingEdgeLength 5154 */ 5155 public int getVerticalFadingEdgeLength() { 5156 if (isVerticalFadingEdgeEnabled()) { 5157 ScrollabilityCache cache = mScrollCache; 5158 if (cache != null) { 5159 return cache.fadingEdgeLength; 5160 } 5161 } 5162 return 0; 5163 } 5164 5165 /** 5166 * Set the size of the faded edge used to indicate that more content in this 5167 * view is available. Will not change whether the fading edge is enabled; use 5168 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5169 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5170 * for the vertical or horizontal fading edges. 5171 * 5172 * @param length The size in pixels of the faded edge used to indicate that more 5173 * content in this view is visible. 5174 */ 5175 public void setFadingEdgeLength(int length) { 5176 initScrollCache(); 5177 mScrollCache.fadingEdgeLength = length; 5178 } 5179 5180 /** 5181 * Returns the size of the horizontal faded edges used to indicate that more 5182 * content in this view is visible. 5183 * 5184 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5185 * faded edges are not enabled for this view. 5186 * @attr ref android.R.styleable#View_fadingEdgeLength 5187 */ 5188 public int getHorizontalFadingEdgeLength() { 5189 if (isHorizontalFadingEdgeEnabled()) { 5190 ScrollabilityCache cache = mScrollCache; 5191 if (cache != null) { 5192 return cache.fadingEdgeLength; 5193 } 5194 } 5195 return 0; 5196 } 5197 5198 /** 5199 * Returns the width of the vertical scrollbar. 5200 * 5201 * @return The width in pixels of the vertical scrollbar or 0 if there 5202 * is no vertical scrollbar. 5203 */ 5204 public int getVerticalScrollbarWidth() { 5205 ScrollabilityCache cache = mScrollCache; 5206 if (cache != null) { 5207 ScrollBarDrawable scrollBar = cache.scrollBar; 5208 if (scrollBar != null) { 5209 int size = scrollBar.getSize(true); 5210 if (size <= 0) { 5211 size = cache.scrollBarSize; 5212 } 5213 return size; 5214 } 5215 return 0; 5216 } 5217 return 0; 5218 } 5219 5220 /** 5221 * Returns the height of the horizontal scrollbar. 5222 * 5223 * @return The height in pixels of the horizontal scrollbar or 0 if 5224 * there is no horizontal scrollbar. 5225 */ 5226 protected int getHorizontalScrollbarHeight() { 5227 ScrollabilityCache cache = mScrollCache; 5228 if (cache != null) { 5229 ScrollBarDrawable scrollBar = cache.scrollBar; 5230 if (scrollBar != null) { 5231 int size = scrollBar.getSize(false); 5232 if (size <= 0) { 5233 size = cache.scrollBarSize; 5234 } 5235 return size; 5236 } 5237 return 0; 5238 } 5239 return 0; 5240 } 5241 5242 /** 5243 * <p> 5244 * Initializes the scrollbars from a given set of styled attributes. This 5245 * method should be called by subclasses that need scrollbars and when an 5246 * instance of these subclasses is created programmatically rather than 5247 * being inflated from XML. This method is automatically called when the XML 5248 * is inflated. 5249 * </p> 5250 * 5251 * @param a the styled attributes set to initialize the scrollbars from 5252 * 5253 * @removed 5254 */ 5255 protected void initializeScrollbars(TypedArray a) { 5256 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5257 // using the View filter array which is not available to the SDK. As such, internal 5258 // framework usage now uses initializeScrollbarsInternal and we grab a default 5259 // TypedArray with the right filter instead here. 5260 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5261 5262 initializeScrollbarsInternal(arr); 5263 5264 // We ignored the method parameter. Recycle the one we actually did use. 5265 arr.recycle(); 5266 } 5267 5268 /** 5269 * <p> 5270 * Initializes the scrollbars from a given set of styled attributes. This 5271 * method should be called by subclasses that need scrollbars and when an 5272 * instance of these subclasses is created programmatically rather than 5273 * being inflated from XML. This method is automatically called when the XML 5274 * is inflated. 5275 * </p> 5276 * 5277 * @param a the styled attributes set to initialize the scrollbars from 5278 * @hide 5279 */ 5280 protected void initializeScrollbarsInternal(TypedArray a) { 5281 initScrollCache(); 5282 5283 final ScrollabilityCache scrollabilityCache = mScrollCache; 5284 5285 if (scrollabilityCache.scrollBar == null) { 5286 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5287 scrollabilityCache.scrollBar.setState(getDrawableState()); 5288 scrollabilityCache.scrollBar.setCallback(this); 5289 } 5290 5291 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5292 5293 if (!fadeScrollbars) { 5294 scrollabilityCache.state = ScrollabilityCache.ON; 5295 } 5296 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5297 5298 5299 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5300 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5301 .getScrollBarFadeDuration()); 5302 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5303 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5304 ViewConfiguration.getScrollDefaultDelay()); 5305 5306 5307 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5308 com.android.internal.R.styleable.View_scrollbarSize, 5309 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5310 5311 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5312 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5313 5314 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5315 if (thumb != null) { 5316 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5317 } 5318 5319 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5320 false); 5321 if (alwaysDraw) { 5322 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5323 } 5324 5325 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5326 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5327 5328 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5329 if (thumb != null) { 5330 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5331 } 5332 5333 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5334 false); 5335 if (alwaysDraw) { 5336 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5337 } 5338 5339 // Apply layout direction to the new Drawables if needed 5340 final int layoutDirection = getLayoutDirection(); 5341 if (track != null) { 5342 track.setLayoutDirection(layoutDirection); 5343 } 5344 if (thumb != null) { 5345 thumb.setLayoutDirection(layoutDirection); 5346 } 5347 5348 // Re-apply user/background padding so that scrollbar(s) get added 5349 resolvePadding(); 5350 } 5351 5352 private void initializeScrollIndicatorsInternal() { 5353 // Some day maybe we'll break this into top/left/start/etc. and let the 5354 // client control it. Until then, you can have any scroll indicator you 5355 // want as long as it's a 1dp foreground-colored rectangle. 5356 if (mScrollIndicatorDrawable == null) { 5357 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5358 } 5359 } 5360 5361 /** 5362 * <p> 5363 * Initalizes the scrollability cache if necessary. 5364 * </p> 5365 */ 5366 private void initScrollCache() { 5367 if (mScrollCache == null) { 5368 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5369 } 5370 } 5371 5372 private ScrollabilityCache getScrollCache() { 5373 initScrollCache(); 5374 return mScrollCache; 5375 } 5376 5377 /** 5378 * Set the position of the vertical scroll bar. Should be one of 5379 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5380 * {@link #SCROLLBAR_POSITION_RIGHT}. 5381 * 5382 * @param position Where the vertical scroll bar should be positioned. 5383 */ 5384 public void setVerticalScrollbarPosition(int position) { 5385 if (mVerticalScrollbarPosition != position) { 5386 mVerticalScrollbarPosition = position; 5387 computeOpaqueFlags(); 5388 resolvePadding(); 5389 } 5390 } 5391 5392 /** 5393 * @return The position where the vertical scroll bar will show, if applicable. 5394 * @see #setVerticalScrollbarPosition(int) 5395 */ 5396 public int getVerticalScrollbarPosition() { 5397 return mVerticalScrollbarPosition; 5398 } 5399 5400 boolean isOnScrollbar(float x, float y) { 5401 if (mScrollCache == null) { 5402 return false; 5403 } 5404 x += getScrollX(); 5405 y += getScrollY(); 5406 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5407 final Rect bounds = mScrollCache.mScrollBarBounds; 5408 getVerticalScrollBarBounds(bounds); 5409 if (bounds.contains((int)x, (int)y)) { 5410 return true; 5411 } 5412 } 5413 if (isHorizontalScrollBarEnabled()) { 5414 final Rect bounds = mScrollCache.mScrollBarBounds; 5415 getHorizontalScrollBarBounds(bounds); 5416 if (bounds.contains((int)x, (int)y)) { 5417 return true; 5418 } 5419 } 5420 return false; 5421 } 5422 5423 boolean isOnScrollbarThumb(float x, float y) { 5424 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5425 } 5426 5427 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5428 if (mScrollCache == null) { 5429 return false; 5430 } 5431 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5432 x += getScrollX(); 5433 y += getScrollY(); 5434 final Rect bounds = mScrollCache.mScrollBarBounds; 5435 getVerticalScrollBarBounds(bounds); 5436 final int range = computeVerticalScrollRange(); 5437 final int offset = computeVerticalScrollOffset(); 5438 final int extent = computeVerticalScrollExtent(); 5439 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5440 extent, range); 5441 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5442 extent, range, offset); 5443 final int thumbTop = bounds.top + thumbOffset; 5444 if (x >= bounds.left && x <= bounds.right && y >= thumbTop 5445 && y <= thumbTop + thumbLength) { 5446 return true; 5447 } 5448 } 5449 return false; 5450 } 5451 5452 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5453 if (mScrollCache == null) { 5454 return false; 5455 } 5456 if (isHorizontalScrollBarEnabled()) { 5457 x += getScrollX(); 5458 y += getScrollY(); 5459 final Rect bounds = mScrollCache.mScrollBarBounds; 5460 getHorizontalScrollBarBounds(bounds); 5461 final int range = computeHorizontalScrollRange(); 5462 final int offset = computeHorizontalScrollOffset(); 5463 final int extent = computeHorizontalScrollExtent(); 5464 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5465 extent, range); 5466 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5467 extent, range, offset); 5468 final int thumbLeft = bounds.left + thumbOffset; 5469 if (x >= thumbLeft && x <= thumbLeft + thumbLength && y >= bounds.top 5470 && y <= bounds.bottom) { 5471 return true; 5472 } 5473 } 5474 return false; 5475 } 5476 5477 boolean isDraggingScrollBar() { 5478 return mScrollCache != null 5479 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5480 } 5481 5482 /** 5483 * Sets the state of all scroll indicators. 5484 * <p> 5485 * See {@link #setScrollIndicators(int, int)} for usage information. 5486 * 5487 * @param indicators a bitmask of indicators that should be enabled, or 5488 * {@code 0} to disable all indicators 5489 * @see #setScrollIndicators(int, int) 5490 * @see #getScrollIndicators() 5491 * @attr ref android.R.styleable#View_scrollIndicators 5492 */ 5493 public void setScrollIndicators(@ScrollIndicators int indicators) { 5494 setScrollIndicators(indicators, 5495 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5496 } 5497 5498 /** 5499 * Sets the state of the scroll indicators specified by the mask. To change 5500 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5501 * <p> 5502 * When a scroll indicator is enabled, it will be displayed if the view 5503 * can scroll in the direction of the indicator. 5504 * <p> 5505 * Multiple indicator types may be enabled or disabled by passing the 5506 * logical OR of the desired types. If multiple types are specified, they 5507 * will all be set to the same enabled state. 5508 * <p> 5509 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5510 * 5511 * @param indicators the indicator direction, or the logical OR of multiple 5512 * indicator directions. One or more of: 5513 * <ul> 5514 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5515 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5516 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5517 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5518 * <li>{@link #SCROLL_INDICATOR_START}</li> 5519 * <li>{@link #SCROLL_INDICATOR_END}</li> 5520 * </ul> 5521 * @see #setScrollIndicators(int) 5522 * @see #getScrollIndicators() 5523 * @attr ref android.R.styleable#View_scrollIndicators 5524 */ 5525 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5526 // Shift and sanitize mask. 5527 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5528 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5529 5530 // Shift and mask indicators. 5531 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5532 indicators &= mask; 5533 5534 // Merge with non-masked flags. 5535 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5536 5537 if (mPrivateFlags3 != updatedFlags) { 5538 mPrivateFlags3 = updatedFlags; 5539 5540 if (indicators != 0) { 5541 initializeScrollIndicatorsInternal(); 5542 } 5543 invalidate(); 5544 } 5545 } 5546 5547 /** 5548 * Returns a bitmask representing the enabled scroll indicators. 5549 * <p> 5550 * For example, if the top and left scroll indicators are enabled and all 5551 * other indicators are disabled, the return value will be 5552 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5553 * <p> 5554 * To check whether the bottom scroll indicator is enabled, use the value 5555 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5556 * 5557 * @return a bitmask representing the enabled scroll indicators 5558 */ 5559 @ScrollIndicators 5560 public int getScrollIndicators() { 5561 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5562 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5563 } 5564 5565 ListenerInfo getListenerInfo() { 5566 if (mListenerInfo != null) { 5567 return mListenerInfo; 5568 } 5569 mListenerInfo = new ListenerInfo(); 5570 return mListenerInfo; 5571 } 5572 5573 /** 5574 * Register a callback to be invoked when the scroll X or Y positions of 5575 * this view change. 5576 * <p> 5577 * <b>Note:</b> Some views handle scrolling independently from View and may 5578 * have their own separate listeners for scroll-type events. For example, 5579 * {@link android.widget.ListView ListView} allows clients to register an 5580 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 5581 * to listen for changes in list scroll position. 5582 * 5583 * @param l The listener to notify when the scroll X or Y position changes. 5584 * @see android.view.View#getScrollX() 5585 * @see android.view.View#getScrollY() 5586 */ 5587 public void setOnScrollChangeListener(OnScrollChangeListener l) { 5588 getListenerInfo().mOnScrollChangeListener = l; 5589 } 5590 5591 /** 5592 * Register a callback to be invoked when focus of this view changed. 5593 * 5594 * @param l The callback that will run. 5595 */ 5596 public void setOnFocusChangeListener(OnFocusChangeListener l) { 5597 getListenerInfo().mOnFocusChangeListener = l; 5598 } 5599 5600 /** 5601 * Add a listener that will be called when the bounds of the view change due to 5602 * layout processing. 5603 * 5604 * @param listener The listener that will be called when layout bounds change. 5605 */ 5606 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 5607 ListenerInfo li = getListenerInfo(); 5608 if (li.mOnLayoutChangeListeners == null) { 5609 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 5610 } 5611 if (!li.mOnLayoutChangeListeners.contains(listener)) { 5612 li.mOnLayoutChangeListeners.add(listener); 5613 } 5614 } 5615 5616 /** 5617 * Remove a listener for layout changes. 5618 * 5619 * @param listener The listener for layout bounds change. 5620 */ 5621 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 5622 ListenerInfo li = mListenerInfo; 5623 if (li == null || li.mOnLayoutChangeListeners == null) { 5624 return; 5625 } 5626 li.mOnLayoutChangeListeners.remove(listener); 5627 } 5628 5629 /** 5630 * Add a listener for attach state changes. 5631 * 5632 * This listener will be called whenever this view is attached or detached 5633 * from a window. Remove the listener using 5634 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 5635 * 5636 * @param listener Listener to attach 5637 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 5638 */ 5639 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5640 ListenerInfo li = getListenerInfo(); 5641 if (li.mOnAttachStateChangeListeners == null) { 5642 li.mOnAttachStateChangeListeners 5643 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 5644 } 5645 li.mOnAttachStateChangeListeners.add(listener); 5646 } 5647 5648 /** 5649 * Remove a listener for attach state changes. The listener will receive no further 5650 * notification of window attach/detach events. 5651 * 5652 * @param listener Listener to remove 5653 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 5654 */ 5655 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5656 ListenerInfo li = mListenerInfo; 5657 if (li == null || li.mOnAttachStateChangeListeners == null) { 5658 return; 5659 } 5660 li.mOnAttachStateChangeListeners.remove(listener); 5661 } 5662 5663 /** 5664 * Returns the focus-change callback registered for this view. 5665 * 5666 * @return The callback, or null if one is not registered. 5667 */ 5668 public OnFocusChangeListener getOnFocusChangeListener() { 5669 ListenerInfo li = mListenerInfo; 5670 return li != null ? li.mOnFocusChangeListener : null; 5671 } 5672 5673 /** 5674 * Register a callback to be invoked when this view is clicked. If this view is not 5675 * clickable, it becomes clickable. 5676 * 5677 * @param l The callback that will run 5678 * 5679 * @see #setClickable(boolean) 5680 */ 5681 public void setOnClickListener(@Nullable OnClickListener l) { 5682 if (!isClickable()) { 5683 setClickable(true); 5684 } 5685 getListenerInfo().mOnClickListener = l; 5686 } 5687 5688 /** 5689 * Return whether this view has an attached OnClickListener. Returns 5690 * true if there is a listener, false if there is none. 5691 */ 5692 public boolean hasOnClickListeners() { 5693 ListenerInfo li = mListenerInfo; 5694 return (li != null && li.mOnClickListener != null); 5695 } 5696 5697 /** 5698 * Register a callback to be invoked when this view is clicked and held. If this view is not 5699 * long clickable, it becomes long clickable. 5700 * 5701 * @param l The callback that will run 5702 * 5703 * @see #setLongClickable(boolean) 5704 */ 5705 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 5706 if (!isLongClickable()) { 5707 setLongClickable(true); 5708 } 5709 getListenerInfo().mOnLongClickListener = l; 5710 } 5711 5712 /** 5713 * Register a callback to be invoked when this view is context clicked. If the view is not 5714 * context clickable, it becomes context clickable. 5715 * 5716 * @param l The callback that will run 5717 * @see #setContextClickable(boolean) 5718 */ 5719 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 5720 if (!isContextClickable()) { 5721 setContextClickable(true); 5722 } 5723 getListenerInfo().mOnContextClickListener = l; 5724 } 5725 5726 /** 5727 * Register a callback to be invoked when the context menu for this view is 5728 * being built. If this view is not long clickable, it becomes long clickable. 5729 * 5730 * @param l The callback that will run 5731 * 5732 */ 5733 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 5734 if (!isLongClickable()) { 5735 setLongClickable(true); 5736 } 5737 getListenerInfo().mOnCreateContextMenuListener = l; 5738 } 5739 5740 /** 5741 * Set an observer to collect stats for each frame rendered for this view. 5742 * 5743 * @hide 5744 */ 5745 public void addFrameMetricsListener(Window window, 5746 Window.OnFrameMetricsAvailableListener listener, 5747 Handler handler) { 5748 if (mAttachInfo != null) { 5749 if (mAttachInfo.mThreadedRenderer != null) { 5750 if (mFrameMetricsObservers == null) { 5751 mFrameMetricsObservers = new ArrayList<>(); 5752 } 5753 5754 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5755 handler.getLooper(), listener); 5756 mFrameMetricsObservers.add(fmo); 5757 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 5758 } else { 5759 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5760 } 5761 } else { 5762 if (mFrameMetricsObservers == null) { 5763 mFrameMetricsObservers = new ArrayList<>(); 5764 } 5765 5766 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5767 handler.getLooper(), listener); 5768 mFrameMetricsObservers.add(fmo); 5769 } 5770 } 5771 5772 /** 5773 * Remove observer configured to collect frame stats for this view. 5774 * 5775 * @hide 5776 */ 5777 public void removeFrameMetricsListener( 5778 Window.OnFrameMetricsAvailableListener listener) { 5779 ThreadedRenderer renderer = getThreadedRenderer(); 5780 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 5781 if (fmo == null) { 5782 throw new IllegalArgumentException( 5783 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 5784 } 5785 5786 if (mFrameMetricsObservers != null) { 5787 mFrameMetricsObservers.remove(fmo); 5788 if (renderer != null) { 5789 renderer.removeFrameMetricsObserver(fmo); 5790 } 5791 } 5792 } 5793 5794 private void registerPendingFrameMetricsObservers() { 5795 if (mFrameMetricsObservers != null) { 5796 ThreadedRenderer renderer = getThreadedRenderer(); 5797 if (renderer != null) { 5798 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 5799 renderer.addFrameMetricsObserver(fmo); 5800 } 5801 } else { 5802 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5803 } 5804 } 5805 } 5806 5807 private FrameMetricsObserver findFrameMetricsObserver( 5808 Window.OnFrameMetricsAvailableListener listener) { 5809 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 5810 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 5811 if (observer.mListener == listener) { 5812 return observer; 5813 } 5814 } 5815 5816 return null; 5817 } 5818 5819 /** 5820 * Call this view's OnClickListener, if it is defined. Performs all normal 5821 * actions associated with clicking: reporting accessibility event, playing 5822 * a sound, etc. 5823 * 5824 * @return True there was an assigned OnClickListener that was called, false 5825 * otherwise is returned. 5826 */ 5827 public boolean performClick() { 5828 final boolean result; 5829 final ListenerInfo li = mListenerInfo; 5830 if (li != null && li.mOnClickListener != null) { 5831 playSoundEffect(SoundEffectConstants.CLICK); 5832 li.mOnClickListener.onClick(this); 5833 result = true; 5834 } else { 5835 result = false; 5836 } 5837 5838 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 5839 return result; 5840 } 5841 5842 /** 5843 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 5844 * this only calls the listener, and does not do any associated clicking 5845 * actions like reporting an accessibility event. 5846 * 5847 * @return True there was an assigned OnClickListener that was called, false 5848 * otherwise is returned. 5849 */ 5850 public boolean callOnClick() { 5851 ListenerInfo li = mListenerInfo; 5852 if (li != null && li.mOnClickListener != null) { 5853 li.mOnClickListener.onClick(this); 5854 return true; 5855 } 5856 return false; 5857 } 5858 5859 /** 5860 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5861 * context menu if the OnLongClickListener did not consume the event. 5862 * 5863 * @return {@code true} if one of the above receivers consumed the event, 5864 * {@code false} otherwise 5865 */ 5866 public boolean performLongClick() { 5867 return performLongClickInternal(mLongClickX, mLongClickY); 5868 } 5869 5870 /** 5871 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5872 * context menu if the OnLongClickListener did not consume the event, 5873 * anchoring it to an (x,y) coordinate. 5874 * 5875 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5876 * to disable anchoring 5877 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5878 * to disable anchoring 5879 * @return {@code true} if one of the above receivers consumed the event, 5880 * {@code false} otherwise 5881 */ 5882 public boolean performLongClick(float x, float y) { 5883 mLongClickX = x; 5884 mLongClickY = y; 5885 final boolean handled = performLongClick(); 5886 mLongClickX = Float.NaN; 5887 mLongClickY = Float.NaN; 5888 return handled; 5889 } 5890 5891 /** 5892 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5893 * context menu if the OnLongClickListener did not consume the event, 5894 * optionally anchoring it to an (x,y) coordinate. 5895 * 5896 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5897 * to disable anchoring 5898 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5899 * to disable anchoring 5900 * @return {@code true} if one of the above receivers consumed the event, 5901 * {@code false} otherwise 5902 */ 5903 private boolean performLongClickInternal(float x, float y) { 5904 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 5905 5906 boolean handled = false; 5907 final ListenerInfo li = mListenerInfo; 5908 if (li != null && li.mOnLongClickListener != null) { 5909 handled = li.mOnLongClickListener.onLongClick(View.this); 5910 } 5911 if (!handled) { 5912 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 5913 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 5914 } 5915 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 5916 if (!handled) { 5917 handled = showLongClickTooltip((int) x, (int) y); 5918 } 5919 } 5920 if (handled) { 5921 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 5922 } 5923 return handled; 5924 } 5925 5926 /** 5927 * Call this view's OnContextClickListener, if it is defined. 5928 * 5929 * @param x the x coordinate of the context click 5930 * @param y the y coordinate of the context click 5931 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5932 * otherwise. 5933 */ 5934 public boolean performContextClick(float x, float y) { 5935 return performContextClick(); 5936 } 5937 5938 /** 5939 * Call this view's OnContextClickListener, if it is defined. 5940 * 5941 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5942 * otherwise. 5943 */ 5944 public boolean performContextClick() { 5945 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 5946 5947 boolean handled = false; 5948 ListenerInfo li = mListenerInfo; 5949 if (li != null && li.mOnContextClickListener != null) { 5950 handled = li.mOnContextClickListener.onContextClick(View.this); 5951 } 5952 if (handled) { 5953 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 5954 } 5955 return handled; 5956 } 5957 5958 /** 5959 * Performs button-related actions during a touch down event. 5960 * 5961 * @param event The event. 5962 * @return True if the down was consumed. 5963 * 5964 * @hide 5965 */ 5966 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 5967 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 5968 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 5969 showContextMenu(event.getX(), event.getY()); 5970 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 5971 return true; 5972 } 5973 return false; 5974 } 5975 5976 /** 5977 * Shows the context menu for this view. 5978 * 5979 * @return {@code true} if the context menu was shown, {@code false} 5980 * otherwise 5981 * @see #showContextMenu(float, float) 5982 */ 5983 public boolean showContextMenu() { 5984 return getParent().showContextMenuForChild(this); 5985 } 5986 5987 /** 5988 * Shows the context menu for this view anchored to the specified 5989 * view-relative coordinate. 5990 * 5991 * @param x the X coordinate in pixels relative to the view to which the 5992 * menu should be anchored, or {@link Float#NaN} to disable anchoring 5993 * @param y the Y coordinate in pixels relative to the view to which the 5994 * menu should be anchored, or {@link Float#NaN} to disable anchoring 5995 * @return {@code true} if the context menu was shown, {@code false} 5996 * otherwise 5997 */ 5998 public boolean showContextMenu(float x, float y) { 5999 return getParent().showContextMenuForChild(this, x, y); 6000 } 6001 6002 /** 6003 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 6004 * 6005 * @param callback Callback that will control the lifecycle of the action mode 6006 * @return The new action mode if it is started, null otherwise 6007 * 6008 * @see ActionMode 6009 * @see #startActionMode(android.view.ActionMode.Callback, int) 6010 */ 6011 public ActionMode startActionMode(ActionMode.Callback callback) { 6012 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 6013 } 6014 6015 /** 6016 * Start an action mode with the given type. 6017 * 6018 * @param callback Callback that will control the lifecycle of the action mode 6019 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 6020 * @return The new action mode if it is started, null otherwise 6021 * 6022 * @see ActionMode 6023 */ 6024 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6025 ViewParent parent = getParent(); 6026 if (parent == null) return null; 6027 try { 6028 return parent.startActionModeForChild(this, callback, type); 6029 } catch (AbstractMethodError ame) { 6030 // Older implementations of custom views might not implement this. 6031 return parent.startActionModeForChild(this, callback); 6032 } 6033 } 6034 6035 /** 6036 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6037 * Context, creating a unique View identifier to retrieve the result. 6038 * 6039 * @param intent The Intent to be started. 6040 * @param requestCode The request code to use. 6041 * @hide 6042 */ 6043 public void startActivityForResult(Intent intent, int requestCode) { 6044 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6045 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6046 } 6047 6048 /** 6049 * If this View corresponds to the calling who, dispatches the activity result. 6050 * @param who The identifier for the targeted View to receive the result. 6051 * @param requestCode The integer request code originally supplied to 6052 * startActivityForResult(), allowing you to identify who this 6053 * result came from. 6054 * @param resultCode The integer result code returned by the child activity 6055 * through its setResult(). 6056 * @param data An Intent, which can return result data to the caller 6057 * (various data can be attached to Intent "extras"). 6058 * @return {@code true} if the activity result was dispatched. 6059 * @hide 6060 */ 6061 public boolean dispatchActivityResult( 6062 String who, int requestCode, int resultCode, Intent data) { 6063 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6064 onActivityResult(requestCode, resultCode, data); 6065 mStartActivityRequestWho = null; 6066 return true; 6067 } 6068 return false; 6069 } 6070 6071 /** 6072 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6073 * 6074 * @param requestCode The integer request code originally supplied to 6075 * startActivityForResult(), allowing you to identify who this 6076 * result came from. 6077 * @param resultCode The integer result code returned by the child activity 6078 * through its setResult(). 6079 * @param data An Intent, which can return result data to the caller 6080 * (various data can be attached to Intent "extras"). 6081 * @hide 6082 */ 6083 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6084 // Do nothing. 6085 } 6086 6087 /** 6088 * Register a callback to be invoked when a hardware key is pressed in this view. 6089 * Key presses in software input methods will generally not trigger the methods of 6090 * this listener. 6091 * @param l the key listener to attach to this view 6092 */ 6093 public void setOnKeyListener(OnKeyListener l) { 6094 getListenerInfo().mOnKeyListener = l; 6095 } 6096 6097 /** 6098 * Register a callback to be invoked when a touch event is sent to this view. 6099 * @param l the touch listener to attach to this view 6100 */ 6101 public void setOnTouchListener(OnTouchListener l) { 6102 getListenerInfo().mOnTouchListener = l; 6103 } 6104 6105 /** 6106 * Register a callback to be invoked when a generic motion event is sent to this view. 6107 * @param l the generic motion listener to attach to this view 6108 */ 6109 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6110 getListenerInfo().mOnGenericMotionListener = l; 6111 } 6112 6113 /** 6114 * Register a callback to be invoked when a hover event is sent to this view. 6115 * @param l the hover listener to attach to this view 6116 */ 6117 public void setOnHoverListener(OnHoverListener l) { 6118 getListenerInfo().mOnHoverListener = l; 6119 } 6120 6121 /** 6122 * Register a drag event listener callback object for this View. The parameter is 6123 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6124 * View, the system calls the 6125 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6126 * @param l An implementation of {@link android.view.View.OnDragListener}. 6127 */ 6128 public void setOnDragListener(OnDragListener l) { 6129 getListenerInfo().mOnDragListener = l; 6130 } 6131 6132 /** 6133 * Give this view focus. This will cause 6134 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6135 * 6136 * Note: this does not check whether this {@link View} should get focus, it just 6137 * gives it focus no matter what. It should only be called internally by framework 6138 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6139 * 6140 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6141 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6142 * focus moved when requestFocus() is called. It may not always 6143 * apply, in which case use the default View.FOCUS_DOWN. 6144 * @param previouslyFocusedRect The rectangle of the view that had focus 6145 * prior in this View's coordinate system. 6146 */ 6147 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6148 if (DBG) { 6149 System.out.println(this + " requestFocus()"); 6150 } 6151 6152 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6153 mPrivateFlags |= PFLAG_FOCUSED; 6154 6155 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6156 6157 if (mParent != null) { 6158 mParent.requestChildFocus(this, this); 6159 if (mParent instanceof ViewGroup) { 6160 ((ViewGroup) mParent).setDefaultFocus(this); 6161 } 6162 } 6163 6164 if (mAttachInfo != null) { 6165 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6166 } 6167 6168 onFocusChanged(true, direction, previouslyFocusedRect); 6169 refreshDrawableState(); 6170 } 6171 } 6172 6173 /** 6174 * Sets this view's preference for reveal behavior when it gains focus. 6175 * 6176 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6177 * this view would prefer to be brought fully into view when it gains focus. 6178 * For example, a text field that a user is meant to type into. Other views such 6179 * as scrolling containers may prefer to opt-out of this behavior.</p> 6180 * 6181 * <p>The default value for views is true, though subclasses may change this 6182 * based on their preferred behavior.</p> 6183 * 6184 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6185 * 6186 * @see #getRevealOnFocusHint() 6187 */ 6188 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6189 if (revealOnFocus) { 6190 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6191 } else { 6192 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6193 } 6194 } 6195 6196 /** 6197 * Returns this view's preference for reveal behavior when it gains focus. 6198 * 6199 * <p>When this method returns true for a child view requesting focus, ancestor 6200 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6201 * should make a best effort to make the newly focused child fully visible to the user. 6202 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6203 * other properties affecting visibility to the user as part of the focus change.</p> 6204 * 6205 * @return true if this view would prefer to become fully visible when it gains focus, 6206 * false if it would prefer not to disrupt scroll positioning 6207 * 6208 * @see #setRevealOnFocusHint(boolean) 6209 */ 6210 public final boolean getRevealOnFocusHint() { 6211 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6212 } 6213 6214 /** 6215 * Populates <code>outRect</code> with the hotspot bounds. By default, 6216 * the hotspot bounds are identical to the screen bounds. 6217 * 6218 * @param outRect rect to populate with hotspot bounds 6219 * @hide Only for internal use by views and widgets. 6220 */ 6221 public void getHotspotBounds(Rect outRect) { 6222 final Drawable background = getBackground(); 6223 if (background != null) { 6224 background.getHotspotBounds(outRect); 6225 } else { 6226 getBoundsOnScreen(outRect); 6227 } 6228 } 6229 6230 /** 6231 * Request that a rectangle of this view be visible on the screen, 6232 * scrolling if necessary just enough. 6233 * 6234 * <p>A View should call this if it maintains some notion of which part 6235 * of its content is interesting. For example, a text editing view 6236 * should call this when its cursor moves. 6237 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6238 * It should not be affected by which part of the View is currently visible or its scroll 6239 * position. 6240 * 6241 * @param rectangle The rectangle in the View's content coordinate space 6242 * @return Whether any parent scrolled. 6243 */ 6244 public boolean requestRectangleOnScreen(Rect rectangle) { 6245 return requestRectangleOnScreen(rectangle, false); 6246 } 6247 6248 /** 6249 * Request that a rectangle of this view be visible on the screen, 6250 * scrolling if necessary just enough. 6251 * 6252 * <p>A View should call this if it maintains some notion of which part 6253 * of its content is interesting. For example, a text editing view 6254 * should call this when its cursor moves. 6255 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6256 * It should not be affected by which part of the View is currently visible or its scroll 6257 * position. 6258 * <p>When <code>immediate</code> is set to true, scrolling will not be 6259 * animated. 6260 * 6261 * @param rectangle The rectangle in the View's content coordinate space 6262 * @param immediate True to forbid animated scrolling, false otherwise 6263 * @return Whether any parent scrolled. 6264 */ 6265 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6266 if (mParent == null) { 6267 return false; 6268 } 6269 6270 View child = this; 6271 6272 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6273 position.set(rectangle); 6274 6275 ViewParent parent = mParent; 6276 boolean scrolled = false; 6277 while (parent != null) { 6278 rectangle.set((int) position.left, (int) position.top, 6279 (int) position.right, (int) position.bottom); 6280 6281 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6282 6283 if (!(parent instanceof View)) { 6284 break; 6285 } 6286 6287 // move it from child's content coordinate space to parent's content coordinate space 6288 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6289 6290 child = (View) parent; 6291 parent = child.getParent(); 6292 } 6293 6294 return scrolled; 6295 } 6296 6297 /** 6298 * Called when this view wants to give up focus. If focus is cleared 6299 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6300 * <p> 6301 * <strong>Note:</strong> When a View clears focus the framework is trying 6302 * to give focus to the first focusable View from the top. Hence, if this 6303 * View is the first from the top that can take focus, then all callbacks 6304 * related to clearing focus will be invoked after which the framework will 6305 * give focus to this view. 6306 * </p> 6307 */ 6308 public void clearFocus() { 6309 if (DBG) { 6310 System.out.println(this + " clearFocus()"); 6311 } 6312 6313 clearFocusInternal(null, true, true); 6314 } 6315 6316 /** 6317 * Clears focus from the view, optionally propagating the change up through 6318 * the parent hierarchy and requesting that the root view place new focus. 6319 * 6320 * @param propagate whether to propagate the change up through the parent 6321 * hierarchy 6322 * @param refocus when propagate is true, specifies whether to request the 6323 * root view place new focus 6324 */ 6325 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6326 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6327 mPrivateFlags &= ~PFLAG_FOCUSED; 6328 6329 if (propagate && mParent != null) { 6330 mParent.clearChildFocus(this); 6331 } 6332 6333 onFocusChanged(false, 0, null); 6334 refreshDrawableState(); 6335 6336 if (propagate && (!refocus || !rootViewRequestFocus())) { 6337 notifyGlobalFocusCleared(this); 6338 } 6339 } 6340 } 6341 6342 void notifyGlobalFocusCleared(View oldFocus) { 6343 if (oldFocus != null && mAttachInfo != null) { 6344 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6345 } 6346 } 6347 6348 boolean rootViewRequestFocus() { 6349 final View root = getRootView(); 6350 return root != null && root.requestFocus(); 6351 } 6352 6353 /** 6354 * Called internally by the view system when a new view is getting focus. 6355 * This is what clears the old focus. 6356 * <p> 6357 * <b>NOTE:</b> The parent view's focused child must be updated manually 6358 * after calling this method. Otherwise, the view hierarchy may be left in 6359 * an inconstent state. 6360 */ 6361 void unFocus(View focused) { 6362 if (DBG) { 6363 System.out.println(this + " unFocus()"); 6364 } 6365 6366 clearFocusInternal(focused, false, false); 6367 } 6368 6369 /** 6370 * Returns true if this view has focus itself, or is the ancestor of the 6371 * view that has focus. 6372 * 6373 * @return True if this view has or contains focus, false otherwise. 6374 */ 6375 @ViewDebug.ExportedProperty(category = "focus") 6376 public boolean hasFocus() { 6377 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6378 } 6379 6380 /** 6381 * Returns true if this view is focusable or if it contains a reachable View 6382 * for which {@link #hasFocusable()} returns true. A "reachable hasFocusable()" 6383 * is a View whose parents do not block descendants focus. 6384 * 6385 * Only {@link #VISIBLE} views are considered focusable. 6386 * 6387 * @return True if the view is focusable or if the view contains a focusable 6388 * View, false otherwise. 6389 * 6390 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6391 * @see ViewGroup#getTouchscreenBlocksFocus() 6392 */ 6393 public boolean hasFocusable() { 6394 if (!isFocusableInTouchMode()) { 6395 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6396 final ViewGroup g = (ViewGroup) p; 6397 if (g.shouldBlockFocusForTouchscreen()) { 6398 return false; 6399 } 6400 } 6401 } 6402 return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable(); 6403 } 6404 6405 /** 6406 * Called by the view system when the focus state of this view changes. 6407 * When the focus change event is caused by directional navigation, direction 6408 * and previouslyFocusedRect provide insight into where the focus is coming from. 6409 * When overriding, be sure to call up through to the super class so that 6410 * the standard focus handling will occur. 6411 * 6412 * @param gainFocus True if the View has focus; false otherwise. 6413 * @param direction The direction focus has moved when requestFocus() 6414 * is called to give this view focus. Values are 6415 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6416 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6417 * It may not always apply, in which case use the default. 6418 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6419 * system, of the previously focused view. If applicable, this will be 6420 * passed in as finer grained information about where the focus is coming 6421 * from (in addition to direction). Will be <code>null</code> otherwise. 6422 */ 6423 @CallSuper 6424 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6425 @Nullable Rect previouslyFocusedRect) { 6426 if (gainFocus) { 6427 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6428 } else { 6429 notifyViewAccessibilityStateChangedIfNeeded( 6430 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6431 } 6432 6433 InputMethodManager imm = InputMethodManager.peekInstance(); 6434 if (!gainFocus) { 6435 if (isPressed()) { 6436 setPressed(false); 6437 } 6438 if (imm != null && mAttachInfo != null 6439 && mAttachInfo.mHasWindowFocus) { 6440 imm.focusOut(this); 6441 } 6442 onFocusLost(); 6443 } else if (imm != null && mAttachInfo != null 6444 && mAttachInfo.mHasWindowFocus) { 6445 imm.focusIn(this); 6446 } 6447 6448 invalidate(true); 6449 ListenerInfo li = mListenerInfo; 6450 if (li != null && li.mOnFocusChangeListener != null) { 6451 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6452 } 6453 6454 if (mAttachInfo != null) { 6455 mAttachInfo.mKeyDispatchState.reset(this); 6456 } 6457 } 6458 6459 /** 6460 * Sends an accessibility event of the given type. If accessibility is 6461 * not enabled this method has no effect. The default implementation calls 6462 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6463 * to populate information about the event source (this View), then calls 6464 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6465 * populate the text content of the event source including its descendants, 6466 * and last calls 6467 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6468 * on its parent to request sending of the event to interested parties. 6469 * <p> 6470 * If an {@link AccessibilityDelegate} has been specified via calling 6471 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6472 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6473 * responsible for handling this call. 6474 * </p> 6475 * 6476 * @param eventType The type of the event to send, as defined by several types from 6477 * {@link android.view.accessibility.AccessibilityEvent}, such as 6478 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6479 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6480 * 6481 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6482 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6483 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6484 * @see AccessibilityDelegate 6485 */ 6486 public void sendAccessibilityEvent(int eventType) { 6487 if (mAccessibilityDelegate != null) { 6488 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6489 } else { 6490 sendAccessibilityEventInternal(eventType); 6491 } 6492 } 6493 6494 /** 6495 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6496 * {@link AccessibilityEvent} to make an announcement which is related to some 6497 * sort of a context change for which none of the events representing UI transitions 6498 * is a good fit. For example, announcing a new page in a book. If accessibility 6499 * is not enabled this method does nothing. 6500 * 6501 * @param text The announcement text. 6502 */ 6503 public void announceForAccessibility(CharSequence text) { 6504 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6505 AccessibilityEvent event = AccessibilityEvent.obtain( 6506 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6507 onInitializeAccessibilityEvent(event); 6508 event.getText().add(text); 6509 event.setContentDescription(null); 6510 mParent.requestSendAccessibilityEvent(this, event); 6511 } 6512 } 6513 6514 /** 6515 * @see #sendAccessibilityEvent(int) 6516 * 6517 * Note: Called from the default {@link AccessibilityDelegate}. 6518 * 6519 * @hide 6520 */ 6521 public void sendAccessibilityEventInternal(int eventType) { 6522 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 6523 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 6524 } 6525 } 6526 6527 /** 6528 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 6529 * takes as an argument an empty {@link AccessibilityEvent} and does not 6530 * perform a check whether accessibility is enabled. 6531 * <p> 6532 * If an {@link AccessibilityDelegate} has been specified via calling 6533 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6534 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 6535 * is responsible for handling this call. 6536 * </p> 6537 * 6538 * @param event The event to send. 6539 * 6540 * @see #sendAccessibilityEvent(int) 6541 */ 6542 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 6543 if (mAccessibilityDelegate != null) { 6544 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 6545 } else { 6546 sendAccessibilityEventUncheckedInternal(event); 6547 } 6548 } 6549 6550 /** 6551 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 6552 * 6553 * Note: Called from the default {@link AccessibilityDelegate}. 6554 * 6555 * @hide 6556 */ 6557 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 6558 if (!isShown()) { 6559 return; 6560 } 6561 onInitializeAccessibilityEvent(event); 6562 // Only a subset of accessibility events populates text content. 6563 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 6564 dispatchPopulateAccessibilityEvent(event); 6565 } 6566 // In the beginning we called #isShown(), so we know that getParent() is not null. 6567 getParent().requestSendAccessibilityEvent(this, event); 6568 } 6569 6570 /** 6571 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 6572 * to its children for adding their text content to the event. Note that the 6573 * event text is populated in a separate dispatch path since we add to the 6574 * event not only the text of the source but also the text of all its descendants. 6575 * A typical implementation will call 6576 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 6577 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6578 * on each child. Override this method if custom population of the event text 6579 * content is required. 6580 * <p> 6581 * If an {@link AccessibilityDelegate} has been specified via calling 6582 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6583 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 6584 * is responsible for handling this call. 6585 * </p> 6586 * <p> 6587 * <em>Note:</em> Accessibility events of certain types are not dispatched for 6588 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 6589 * </p> 6590 * 6591 * @param event The event. 6592 * 6593 * @return True if the event population was completed. 6594 */ 6595 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 6596 if (mAccessibilityDelegate != null) { 6597 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 6598 } else { 6599 return dispatchPopulateAccessibilityEventInternal(event); 6600 } 6601 } 6602 6603 /** 6604 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6605 * 6606 * Note: Called from the default {@link AccessibilityDelegate}. 6607 * 6608 * @hide 6609 */ 6610 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6611 onPopulateAccessibilityEvent(event); 6612 return false; 6613 } 6614 6615 /** 6616 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6617 * giving a chance to this View to populate the accessibility event with its 6618 * text content. While this method is free to modify event 6619 * attributes other than text content, doing so should normally be performed in 6620 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 6621 * <p> 6622 * Example: Adding formatted date string to an accessibility event in addition 6623 * to the text added by the super implementation: 6624 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6625 * super.onPopulateAccessibilityEvent(event); 6626 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 6627 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 6628 * mCurrentDate.getTimeInMillis(), flags); 6629 * event.getText().add(selectedDateUtterance); 6630 * }</pre> 6631 * <p> 6632 * If an {@link AccessibilityDelegate} has been specified via calling 6633 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6634 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 6635 * is responsible for handling this call. 6636 * </p> 6637 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6638 * information to the event, in case the default implementation has basic information to add. 6639 * </p> 6640 * 6641 * @param event The accessibility event which to populate. 6642 * 6643 * @see #sendAccessibilityEvent(int) 6644 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6645 */ 6646 @CallSuper 6647 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6648 if (mAccessibilityDelegate != null) { 6649 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 6650 } else { 6651 onPopulateAccessibilityEventInternal(event); 6652 } 6653 } 6654 6655 /** 6656 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 6657 * 6658 * Note: Called from the default {@link AccessibilityDelegate}. 6659 * 6660 * @hide 6661 */ 6662 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6663 } 6664 6665 /** 6666 * Initializes an {@link AccessibilityEvent} with information about 6667 * this View which is the event source. In other words, the source of 6668 * an accessibility event is the view whose state change triggered firing 6669 * the event. 6670 * <p> 6671 * Example: Setting the password property of an event in addition 6672 * to properties set by the super implementation: 6673 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6674 * super.onInitializeAccessibilityEvent(event); 6675 * event.setPassword(true); 6676 * }</pre> 6677 * <p> 6678 * If an {@link AccessibilityDelegate} has been specified via calling 6679 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6680 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 6681 * is responsible for handling this call. 6682 * </p> 6683 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6684 * information to the event, in case the default implementation has basic information to add. 6685 * </p> 6686 * @param event The event to initialize. 6687 * 6688 * @see #sendAccessibilityEvent(int) 6689 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6690 */ 6691 @CallSuper 6692 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6693 if (mAccessibilityDelegate != null) { 6694 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 6695 } else { 6696 onInitializeAccessibilityEventInternal(event); 6697 } 6698 } 6699 6700 /** 6701 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6702 * 6703 * Note: Called from the default {@link AccessibilityDelegate}. 6704 * 6705 * @hide 6706 */ 6707 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 6708 event.setSource(this); 6709 event.setClassName(getAccessibilityClassName()); 6710 event.setPackageName(getContext().getPackageName()); 6711 event.setEnabled(isEnabled()); 6712 event.setContentDescription(mContentDescription); 6713 6714 switch (event.getEventType()) { 6715 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 6716 ArrayList<View> focusablesTempList = (mAttachInfo != null) 6717 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 6718 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 6719 event.setItemCount(focusablesTempList.size()); 6720 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 6721 if (mAttachInfo != null) { 6722 focusablesTempList.clear(); 6723 } 6724 } break; 6725 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 6726 CharSequence text = getIterableTextForAccessibility(); 6727 if (text != null && text.length() > 0) { 6728 event.setFromIndex(getAccessibilitySelectionStart()); 6729 event.setToIndex(getAccessibilitySelectionEnd()); 6730 event.setItemCount(text.length()); 6731 } 6732 } break; 6733 } 6734 } 6735 6736 /** 6737 * Returns an {@link AccessibilityNodeInfo} representing this view from the 6738 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 6739 * This method is responsible for obtaining an accessibility node info from a 6740 * pool of reusable instances and calling 6741 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 6742 * initialize the former. 6743 * <p> 6744 * Note: The client is responsible for recycling the obtained instance by calling 6745 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 6746 * </p> 6747 * 6748 * @return A populated {@link AccessibilityNodeInfo}. 6749 * 6750 * @see AccessibilityNodeInfo 6751 */ 6752 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 6753 if (mAccessibilityDelegate != null) { 6754 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 6755 } else { 6756 return createAccessibilityNodeInfoInternal(); 6757 } 6758 } 6759 6760 /** 6761 * @see #createAccessibilityNodeInfo() 6762 * 6763 * @hide 6764 */ 6765 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 6766 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 6767 if (provider != null) { 6768 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 6769 } else { 6770 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 6771 onInitializeAccessibilityNodeInfo(info); 6772 return info; 6773 } 6774 } 6775 6776 /** 6777 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 6778 * The base implementation sets: 6779 * <ul> 6780 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 6781 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 6782 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 6783 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 6784 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 6785 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 6786 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 6787 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 6788 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 6789 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 6790 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 6791 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 6792 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 6793 * </ul> 6794 * <p> 6795 * Subclasses should override this method, call the super implementation, 6796 * and set additional attributes. 6797 * </p> 6798 * <p> 6799 * If an {@link AccessibilityDelegate} has been specified via calling 6800 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6801 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 6802 * is responsible for handling this call. 6803 * </p> 6804 * 6805 * @param info The instance to initialize. 6806 */ 6807 @CallSuper 6808 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 6809 if (mAccessibilityDelegate != null) { 6810 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 6811 } else { 6812 onInitializeAccessibilityNodeInfoInternal(info); 6813 } 6814 } 6815 6816 /** 6817 * Gets the location of this view in screen coordinates. 6818 * 6819 * @param outRect The output location 6820 * @hide 6821 */ 6822 public void getBoundsOnScreen(Rect outRect) { 6823 getBoundsOnScreen(outRect, false); 6824 } 6825 6826 /** 6827 * Gets the location of this view in screen coordinates. 6828 * 6829 * @param outRect The output location 6830 * @param clipToParent Whether to clip child bounds to the parent ones. 6831 * @hide 6832 */ 6833 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 6834 if (mAttachInfo == null) { 6835 return; 6836 } 6837 6838 RectF position = mAttachInfo.mTmpTransformRect; 6839 position.set(0, 0, mRight - mLeft, mBottom - mTop); 6840 6841 if (!hasIdentityMatrix()) { 6842 getMatrix().mapRect(position); 6843 } 6844 6845 position.offset(mLeft, mTop); 6846 6847 ViewParent parent = mParent; 6848 while (parent instanceof View) { 6849 View parentView = (View) parent; 6850 6851 position.offset(-parentView.mScrollX, -parentView.mScrollY); 6852 6853 if (clipToParent) { 6854 position.left = Math.max(position.left, 0); 6855 position.top = Math.max(position.top, 0); 6856 position.right = Math.min(position.right, parentView.getWidth()); 6857 position.bottom = Math.min(position.bottom, parentView.getHeight()); 6858 } 6859 6860 if (!parentView.hasIdentityMatrix()) { 6861 parentView.getMatrix().mapRect(position); 6862 } 6863 6864 position.offset(parentView.mLeft, parentView.mTop); 6865 6866 parent = parentView.mParent; 6867 } 6868 6869 if (parent instanceof ViewRootImpl) { 6870 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 6871 position.offset(0, -viewRootImpl.mCurScrollY); 6872 } 6873 6874 position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 6875 6876 outRect.set(Math.round(position.left), Math.round(position.top), 6877 Math.round(position.right), Math.round(position.bottom)); 6878 } 6879 6880 /** 6881 * Return the class name of this object to be used for accessibility purposes. 6882 * Subclasses should only override this if they are implementing something that 6883 * should be seen as a completely new class of view when used by accessibility, 6884 * unrelated to the class it is deriving from. This is used to fill in 6885 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 6886 */ 6887 public CharSequence getAccessibilityClassName() { 6888 return View.class.getName(); 6889 } 6890 6891 /** 6892 * Called when assist structure is being retrieved from a view as part of 6893 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 6894 * @param structure Fill in with structured view data. The default implementation 6895 * fills in all data that can be inferred from the view itself. 6896 */ 6897 public void onProvideStructure(ViewStructure structure) { 6898 onProvideStructureForAssistOrAutoFill(structure, 0); 6899 } 6900 6901 /** 6902 * Called when assist structure is being retrieved from a view as part of an auto-fill request. 6903 * 6904 * <p>The structure must be filled according to the request type, which is set in the 6905 * {@code flags} parameter - see the documentation on each flag for more details. 6906 * 6907 * @param structure Fill in with structured view data. The default implementation 6908 * fills in all data that can be inferred from the view itself. 6909 * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and 6910 * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info). 6911 */ 6912 public void onProvideAutoFillStructure(ViewStructure structure, int flags) { 6913 onProvideStructureForAssistOrAutoFill(structure, flags); 6914 } 6915 6916 private void onProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) { 6917 // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well, 6918 // this method should take a boolean with the type of request. 6919 boolean forAutoFill = (flags 6920 & (View.AUTO_FILL_FLAG_TYPE_FILL 6921 | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0; 6922 final int id = mID; 6923 if (id != NO_ID && !isViewIdGenerated(id)) { 6924 String pkg, type, entry; 6925 try { 6926 final Resources res = getResources(); 6927 entry = res.getResourceEntryName(id); 6928 type = res.getResourceTypeName(id); 6929 pkg = res.getResourcePackageName(id); 6930 } catch (Resources.NotFoundException e) { 6931 entry = type = pkg = null; 6932 } 6933 structure.setId(id, pkg, type, entry); 6934 } else { 6935 structure.setId(id, null, null, null); 6936 } 6937 6938 if (forAutoFill) { 6939 // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to 6940 // reuse the accessibility id to save space. 6941 mAutoFillId = getAccessibilityViewId(); 6942 structure.setAutoFillId(mAutoFillId); 6943 structure.setAutoFillType(getAutoFillType()); 6944 } 6945 6946 structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop); 6947 if (!hasIdentityMatrix()) { 6948 structure.setTransformation(getMatrix()); 6949 } 6950 structure.setElevation(getZ()); 6951 structure.setVisibility(getVisibility()); 6952 structure.setEnabled(isEnabled()); 6953 if (isClickable()) { 6954 structure.setClickable(true); 6955 } 6956 if (isFocusable()) { 6957 structure.setFocusable(true); 6958 } 6959 if (isFocused()) { 6960 structure.setFocused(true); 6961 } 6962 if (isAccessibilityFocused()) { 6963 structure.setAccessibilityFocused(true); 6964 } 6965 if (isSelected()) { 6966 structure.setSelected(true); 6967 } 6968 if (isActivated()) { 6969 structure.setActivated(true); 6970 } 6971 if (isLongClickable()) { 6972 structure.setLongClickable(true); 6973 } 6974 if (this instanceof Checkable) { 6975 structure.setCheckable(true); 6976 if (((Checkable)this).isChecked()) { 6977 structure.setChecked(true); 6978 } 6979 } 6980 if (isContextClickable()) { 6981 structure.setContextClickable(true); 6982 } 6983 structure.setClassName(getAccessibilityClassName().toString()); 6984 structure.setContentDescription(getContentDescription()); 6985 } 6986 6987 /** 6988 * Called when assist structure is being retrieved from a view as part of 6989 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 6990 * generate additional virtual structure under this view. The defaullt implementation 6991 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 6992 * view's virtual accessibility nodes, if any. You can override this for a more 6993 * optimal implementation providing this data. 6994 */ 6995 public void onProvideVirtualStructure(ViewStructure structure) { 6996 onProvideVirtualStructureForAssistOrAutoFill(structure, 0); 6997 } 6998 6999 /** 7000 * Called when assist structure is being retrieved from a view as part of an auto-fill request 7001 * to generate additional virtual structure under this view. 7002 * 7003 * <p>The defaullt implementation uses {@link #getAccessibilityNodeProvider()} to try to 7004 * generate this from the view's virtual accessibility nodes, if any. You can override this 7005 * for a more optimal implementation providing this data. 7006 * 7007 * <p>The structure must be filled according to the request type, which is set in the 7008 * {@code flags} parameter - see the documentation on each flag for more details. 7009 * 7010 * @param structure Fill in with structured view data. 7011 * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and 7012 * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info). 7013 */ 7014 public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) { 7015 onProvideVirtualStructureForAssistOrAutoFill(structure, flags); 7016 } 7017 7018 private void onProvideVirtualStructureForAssistOrAutoFill(ViewStructure structure, int flags) { 7019 // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well, 7020 // this method should take a boolean with the type of request. 7021 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7022 if (provider != null) { 7023 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7024 structure.setChildCount(1); 7025 ViewStructure root = structure.newChild(0); 7026 populateVirtualStructure(root, provider, info, flags); 7027 info.recycle(); 7028 } 7029 } 7030 7031 /** 7032 * Gets the {@link VirtualViewDelegate} responsible for auto-filling the virtual children of 7033 * this view. 7034 * 7035 * <p>By default returns {@code null} but should be overridden when view provides a virtual 7036 * hierachy on {@link OnProvideAssistDataListener} that takes flags used by the AutoFill 7037 * Framework (such as {@link #AUTO_FILL_FLAG_TYPE_FILL} and 7038 * {@link #AUTO_FILL_FLAG_TYPE_SAVE}). 7039 */ 7040 @Nullable 7041 public VirtualViewDelegate getAutoFillVirtualViewDelegate( 7042 @SuppressWarnings("unused") VirtualViewDelegate.Callback callback) { 7043 return null; 7044 } 7045 7046 /** 7047 * Automatically fills the content of this view with the {@code value}. 7048 * 7049 * <p>By default does nothing, but views should override it (and {@link #getAutoFillType()} to 7050 * support the AutoFill Framework. 7051 * 7052 * <p>Typically, it is implemented by: 7053 * 7054 * <ol> 7055 * <li>Call the proper getter method on {@link AutoFillValue} to fetch the actual value. 7056 * <li>Pass the actual value to the equivalent setter in the view. 7057 * <ol> 7058 * 7059 * <p>For example, a text-field view would call: 7060 * 7061 * <pre class="prettyprint"> 7062 * CharSequence text = value.getTextValue(); 7063 * if (text != null) { 7064 * setText(text); 7065 * } 7066 * </pre> 7067 */ 7068 public void autoFill(@SuppressWarnings("unused") AutoFillValue value) { 7069 } 7070 7071 /** 7072 * Describes the auto-fill type that should be used on calls to 7073 * {@link #autoFill(AutoFillValue)} and 7074 * {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}. 7075 * 7076 * <p>By default returns {@code null}, but views should override it (and 7077 * {@link #autoFill(AutoFillValue)} to support the AutoFill Framework. 7078 */ 7079 @Nullable 7080 public AutoFillType getAutoFillType() { 7081 return null; 7082 } 7083 7084 private void populateVirtualStructure(ViewStructure structure, 7085 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, int flags) { 7086 // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well, 7087 // this method should take a boolean with the type of request. 7088 7089 final boolean sanitized = (flags & View.AUTO_FILL_FLAG_TYPE_FILL) != 0; 7090 7091 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 7092 null, null, null); 7093 Rect rect = structure.getTempRect(); 7094 info.getBoundsInParent(rect); 7095 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 7096 structure.setVisibility(VISIBLE); 7097 structure.setEnabled(info.isEnabled()); 7098 if (info.isClickable()) { 7099 structure.setClickable(true); 7100 } 7101 if (info.isFocusable()) { 7102 structure.setFocusable(true); 7103 } 7104 if (info.isFocused()) { 7105 structure.setFocused(true); 7106 } 7107 if (info.isAccessibilityFocused()) { 7108 structure.setAccessibilityFocused(true); 7109 } 7110 if (info.isSelected()) { 7111 structure.setSelected(true); 7112 } 7113 if (info.isLongClickable()) { 7114 structure.setLongClickable(true); 7115 } 7116 if (info.isCheckable()) { 7117 structure.setCheckable(true); 7118 if (info.isChecked()) { 7119 structure.setChecked(true); 7120 } 7121 } 7122 if (info.isContextClickable()) { 7123 structure.setContextClickable(true); 7124 } 7125 CharSequence cname = info.getClassName(); 7126 structure.setClassName(cname != null ? cname.toString() : null); 7127 structure.setContentDescription(info.getContentDescription()); 7128 if (!sanitized && (info.getText() != null || info.getError() != null)) { 7129 // TODO(b/33197203) (b/33269702): when sanitized, try to use the Accessibility API to 7130 // just set sanitized values (like text coming from resource files), rather than not 7131 // setting it at all. 7132 structure.setText(info.getText(), info.getTextSelectionStart(), 7133 info.getTextSelectionEnd()); 7134 } 7135 final int NCHILDREN = info.getChildCount(); 7136 if (NCHILDREN > 0) { 7137 structure.setChildCount(NCHILDREN); 7138 for (int i=0; i<NCHILDREN; i++) { 7139 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 7140 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 7141 ViewStructure child = structure.newChild(i); 7142 populateVirtualStructure(child, provider, cinfo, flags); 7143 cinfo.recycle(); 7144 } 7145 } 7146 } 7147 7148 /** 7149 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 7150 * implementation calls {@link #onProvideStructure} and 7151 * {@link #onProvideVirtualStructure}. 7152 */ 7153 public void dispatchProvideStructure(ViewStructure structure) { 7154 dispatchProvideStructureForAssistOrAutoFill(structure, 0); 7155 } 7156 7157 /** 7158 * Dispatch creation of {@link ViewStructure} down the hierarchy. 7159 * 7160 * <p>The structure must be filled according to the request type, which is set in the 7161 * {@code flags} parameter - see the documentation on each flag for more details. 7162 * 7163 * <p>The default implementation calls {@link #onProvideAutoFillStructure(ViewStructure, int)} 7164 * and {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)}. 7165 * 7166 * @param structure Fill in with structured view data. 7167 * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and 7168 * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info). 7169 */ 7170 public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) { 7171 dispatchProvideStructureForAssistOrAutoFill(structure, flags); 7172 } 7173 7174 private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) { 7175 // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well, 7176 // this method should take a boolean with the type of request. 7177 boolean forAutoFill = (flags 7178 & (View.AUTO_FILL_FLAG_TYPE_FILL 7179 | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0; 7180 7181 boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked(); 7182 if (!blocked) { 7183 if (forAutoFill) { 7184 onProvideAutoFillStructure(structure, flags); 7185 onProvideAutoFillVirtualStructure(structure, flags); 7186 } else { 7187 onProvideStructure(structure); 7188 onProvideVirtualStructure(structure); 7189 } 7190 } else { 7191 structure.setClassName(getAccessibilityClassName().toString()); 7192 structure.setAssistBlocked(true); 7193 } 7194 } 7195 7196 /** 7197 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 7198 * 7199 * Note: Called from the default {@link AccessibilityDelegate}. 7200 * 7201 * @hide 7202 */ 7203 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 7204 if (mAttachInfo == null) { 7205 return; 7206 } 7207 7208 Rect bounds = mAttachInfo.mTmpInvalRect; 7209 7210 getDrawingRect(bounds); 7211 info.setBoundsInParent(bounds); 7212 7213 getBoundsOnScreen(bounds, true); 7214 info.setBoundsInScreen(bounds); 7215 7216 ViewParent parent = getParentForAccessibility(); 7217 if (parent instanceof View) { 7218 info.setParent((View) parent); 7219 } 7220 7221 if (mID != View.NO_ID) { 7222 View rootView = getRootView(); 7223 if (rootView == null) { 7224 rootView = this; 7225 } 7226 7227 View label = rootView.findLabelForView(this, mID); 7228 if (label != null) { 7229 info.setLabeledBy(label); 7230 } 7231 7232 if ((mAttachInfo.mAccessibilityFetchFlags 7233 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 7234 && Resources.resourceHasPackage(mID)) { 7235 try { 7236 String viewId = getResources().getResourceName(mID); 7237 info.setViewIdResourceName(viewId); 7238 } catch (Resources.NotFoundException nfe) { 7239 /* ignore */ 7240 } 7241 } 7242 } 7243 7244 if (mLabelForId != View.NO_ID) { 7245 View rootView = getRootView(); 7246 if (rootView == null) { 7247 rootView = this; 7248 } 7249 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 7250 if (labeled != null) { 7251 info.setLabelFor(labeled); 7252 } 7253 } 7254 7255 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 7256 View rootView = getRootView(); 7257 if (rootView == null) { 7258 rootView = this; 7259 } 7260 View next = rootView.findViewInsideOutShouldExist(this, 7261 mAccessibilityTraversalBeforeId); 7262 if (next != null && next.includeForAccessibility()) { 7263 info.setTraversalBefore(next); 7264 } 7265 } 7266 7267 if (mAccessibilityTraversalAfterId != View.NO_ID) { 7268 View rootView = getRootView(); 7269 if (rootView == null) { 7270 rootView = this; 7271 } 7272 View next = rootView.findViewInsideOutShouldExist(this, 7273 mAccessibilityTraversalAfterId); 7274 if (next != null && next.includeForAccessibility()) { 7275 info.setTraversalAfter(next); 7276 } 7277 } 7278 7279 info.setVisibleToUser(isVisibleToUser()); 7280 7281 info.setImportantForAccessibility(isImportantForAccessibility()); 7282 info.setPackageName(mContext.getPackageName()); 7283 info.setClassName(getAccessibilityClassName()); 7284 info.setContentDescription(getContentDescription()); 7285 7286 info.setEnabled(isEnabled()); 7287 info.setClickable(isClickable()); 7288 info.setFocusable(isFocusable()); 7289 info.setFocused(isFocused()); 7290 info.setAccessibilityFocused(isAccessibilityFocused()); 7291 info.setSelected(isSelected()); 7292 info.setLongClickable(isLongClickable()); 7293 info.setContextClickable(isContextClickable()); 7294 info.setLiveRegion(getAccessibilityLiveRegion()); 7295 7296 // TODO: These make sense only if we are in an AdapterView but all 7297 // views can be selected. Maybe from accessibility perspective 7298 // we should report as selectable view in an AdapterView. 7299 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 7300 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 7301 7302 if (isFocusable()) { 7303 if (isFocused()) { 7304 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 7305 } else { 7306 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 7307 } 7308 } 7309 7310 if (!isAccessibilityFocused()) { 7311 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 7312 } else { 7313 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 7314 } 7315 7316 if (isClickable() && isEnabled()) { 7317 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 7318 } 7319 7320 if (isLongClickable() && isEnabled()) { 7321 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 7322 } 7323 7324 if (isContextClickable() && isEnabled()) { 7325 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 7326 } 7327 7328 CharSequence text = getIterableTextForAccessibility(); 7329 if (text != null && text.length() > 0) { 7330 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 7331 7332 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 7333 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 7334 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 7335 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 7336 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 7337 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 7338 } 7339 7340 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 7341 populateAccessibilityNodeInfoDrawingOrderInParent(info); 7342 } 7343 7344 /** 7345 * Determine the order in which this view will be drawn relative to its siblings for a11y 7346 * 7347 * @param info The info whose drawing order should be populated 7348 */ 7349 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 7350 /* 7351 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 7352 * drawing order may not be well-defined, and some Views with custom drawing order may 7353 * not be initialized sufficiently to respond properly getChildDrawingOrder. 7354 */ 7355 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 7356 info.setDrawingOrder(0); 7357 return; 7358 } 7359 int drawingOrderInParent = 1; 7360 // Iterate up the hierarchy if parents are not important for a11y 7361 View viewAtDrawingLevel = this; 7362 final ViewParent parent = getParentForAccessibility(); 7363 while (viewAtDrawingLevel != parent) { 7364 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 7365 if (!(currentParent instanceof ViewGroup)) { 7366 // Should only happen for the Decor 7367 drawingOrderInParent = 0; 7368 break; 7369 } else { 7370 final ViewGroup parentGroup = (ViewGroup) currentParent; 7371 final int childCount = parentGroup.getChildCount(); 7372 if (childCount > 1) { 7373 List<View> preorderedList = parentGroup.buildOrderedChildList(); 7374 if (preorderedList != null) { 7375 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 7376 for (int i = 0; i < childDrawIndex; i++) { 7377 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 7378 } 7379 } else { 7380 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 7381 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 7382 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 7383 .getChildDrawingOrder(childCount, childIndex) : childIndex; 7384 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 7385 if (childDrawIndex != 0) { 7386 for (int i = 0; i < numChildrenToIterate; i++) { 7387 final int otherDrawIndex = (customOrder ? 7388 parentGroup.getChildDrawingOrder(childCount, i) : i); 7389 if (otherDrawIndex < childDrawIndex) { 7390 drawingOrderInParent += 7391 numViewsForAccessibility(parentGroup.getChildAt(i)); 7392 } 7393 } 7394 } 7395 } 7396 } 7397 } 7398 viewAtDrawingLevel = (View) currentParent; 7399 } 7400 info.setDrawingOrder(drawingOrderInParent); 7401 } 7402 7403 private static int numViewsForAccessibility(View view) { 7404 if (view != null) { 7405 if (view.includeForAccessibility()) { 7406 return 1; 7407 } else if (view instanceof ViewGroup) { 7408 return ((ViewGroup) view).getNumChildrenForAccessibility(); 7409 } 7410 } 7411 return 0; 7412 } 7413 7414 private View findLabelForView(View view, int labeledId) { 7415 if (mMatchLabelForPredicate == null) { 7416 mMatchLabelForPredicate = new MatchLabelForPredicate(); 7417 } 7418 mMatchLabelForPredicate.mLabeledId = labeledId; 7419 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 7420 } 7421 7422 /** 7423 * Computes whether this view is visible to the user. Such a view is 7424 * attached, visible, all its predecessors are visible, it is not clipped 7425 * entirely by its predecessors, and has an alpha greater than zero. 7426 * 7427 * @return Whether the view is visible on the screen. 7428 * 7429 * @hide 7430 */ 7431 protected boolean isVisibleToUser() { 7432 return isVisibleToUser(null); 7433 } 7434 7435 /** 7436 * Computes whether the given portion of this view is visible to the user. 7437 * Such a view is attached, visible, all its predecessors are visible, 7438 * has an alpha greater than zero, and the specified portion is not 7439 * clipped entirely by its predecessors. 7440 * 7441 * @param boundInView the portion of the view to test; coordinates should be relative; may be 7442 * <code>null</code>, and the entire view will be tested in this case. 7443 * When <code>true</code> is returned by the function, the actual visible 7444 * region will be stored in this parameter; that is, if boundInView is fully 7445 * contained within the view, no modification will be made, otherwise regions 7446 * outside of the visible area of the view will be clipped. 7447 * 7448 * @return Whether the specified portion of the view is visible on the screen. 7449 * 7450 * @hide 7451 */ 7452 protected boolean isVisibleToUser(Rect boundInView) { 7453 if (mAttachInfo != null) { 7454 // Attached to invisible window means this view is not visible. 7455 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 7456 return false; 7457 } 7458 // An invisible predecessor or one with alpha zero means 7459 // that this view is not visible to the user. 7460 Object current = this; 7461 while (current instanceof View) { 7462 View view = (View) current; 7463 // We have attach info so this view is attached and there is no 7464 // need to check whether we reach to ViewRootImpl on the way up. 7465 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 7466 view.getVisibility() != VISIBLE) { 7467 return false; 7468 } 7469 current = view.mParent; 7470 } 7471 // Check if the view is entirely covered by its predecessors. 7472 Rect visibleRect = mAttachInfo.mTmpInvalRect; 7473 Point offset = mAttachInfo.mPoint; 7474 if (!getGlobalVisibleRect(visibleRect, offset)) { 7475 return false; 7476 } 7477 // Check if the visible portion intersects the rectangle of interest. 7478 if (boundInView != null) { 7479 visibleRect.offset(-offset.x, -offset.y); 7480 return boundInView.intersect(visibleRect); 7481 } 7482 return true; 7483 } 7484 return false; 7485 } 7486 7487 /** 7488 * Returns the delegate for implementing accessibility support via 7489 * composition. For more details see {@link AccessibilityDelegate}. 7490 * 7491 * @return The delegate, or null if none set. 7492 * 7493 * @hide 7494 */ 7495 public AccessibilityDelegate getAccessibilityDelegate() { 7496 return mAccessibilityDelegate; 7497 } 7498 7499 /** 7500 * Sets a delegate for implementing accessibility support via composition 7501 * (as opposed to inheritance). For more details, see 7502 * {@link AccessibilityDelegate}. 7503 * <p> 7504 * <strong>Note:</strong> On platform versions prior to 7505 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 7506 * views in the {@code android.widget.*} package are called <i>before</i> 7507 * host methods. This prevents certain properties such as class name from 7508 * being modified by overriding 7509 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 7510 * as any changes will be overwritten by the host class. 7511 * <p> 7512 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 7513 * methods are called <i>after</i> host methods, which all properties to be 7514 * modified without being overwritten by the host class. 7515 * 7516 * @param delegate the object to which accessibility method calls should be 7517 * delegated 7518 * @see AccessibilityDelegate 7519 */ 7520 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 7521 mAccessibilityDelegate = delegate; 7522 } 7523 7524 /** 7525 * Gets the provider for managing a virtual view hierarchy rooted at this View 7526 * and reported to {@link android.accessibilityservice.AccessibilityService}s 7527 * that explore the window content. 7528 * <p> 7529 * If this method returns an instance, this instance is responsible for managing 7530 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 7531 * View including the one representing the View itself. Similarly the returned 7532 * instance is responsible for performing accessibility actions on any virtual 7533 * view or the root view itself. 7534 * </p> 7535 * <p> 7536 * If an {@link AccessibilityDelegate} has been specified via calling 7537 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7538 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 7539 * is responsible for handling this call. 7540 * </p> 7541 * 7542 * @return The provider. 7543 * 7544 * @see AccessibilityNodeProvider 7545 */ 7546 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 7547 if (mAccessibilityDelegate != null) { 7548 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 7549 } else { 7550 return null; 7551 } 7552 } 7553 7554 /** 7555 * Gets the unique identifier of this view on the screen for accessibility purposes. 7556 * 7557 * @return The view accessibility id. 7558 * 7559 * @hide 7560 */ 7561 public int getAccessibilityViewId() { 7562 if (mAccessibilityViewId == NO_ID) { 7563 mAccessibilityViewId = sNextAccessibilityViewId++; 7564 } 7565 return mAccessibilityViewId; 7566 } 7567 7568 /** 7569 * Gets the unique identifier of this view for auto-fill purposes. 7570 * 7571 * <p>It's only set after {@link #onProvideAutoFillStructure(ViewStructure, int)} is called. 7572 * 7573 * @return The view autofill id or {@link #NO_ID} if 7574 * {@link #onProvideAutoFillStructure(ViewStructure, int)} was not called yet. 7575 * 7576 * @hide 7577 */ 7578 public int getAutoFillViewId() { 7579 return mAutoFillId; 7580 } 7581 7582 /** 7583 * Gets the unique identifier of the window in which this View reseides. 7584 * 7585 * @return The window accessibility id. 7586 * 7587 * @hide 7588 */ 7589 public int getAccessibilityWindowId() { 7590 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 7591 : AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 7592 } 7593 7594 /** 7595 * Returns the {@link View}'s content description. 7596 * <p> 7597 * <strong>Note:</strong> Do not override this method, as it will have no 7598 * effect on the content description presented to accessibility services. 7599 * You must call {@link #setContentDescription(CharSequence)} to modify the 7600 * content description. 7601 * 7602 * @return the content description 7603 * @see #setContentDescription(CharSequence) 7604 * @attr ref android.R.styleable#View_contentDescription 7605 */ 7606 @ViewDebug.ExportedProperty(category = "accessibility") 7607 public CharSequence getContentDescription() { 7608 return mContentDescription; 7609 } 7610 7611 /** 7612 * Sets the {@link View}'s content description. 7613 * <p> 7614 * A content description briefly describes the view and is primarily used 7615 * for accessibility support to determine how a view should be presented to 7616 * the user. In the case of a view with no textual representation, such as 7617 * {@link android.widget.ImageButton}, a useful content description 7618 * explains what the view does. For example, an image button with a phone 7619 * icon that is used to place a call may use "Call" as its content 7620 * description. An image of a floppy disk that is used to save a file may 7621 * use "Save". 7622 * 7623 * @param contentDescription The content description. 7624 * @see #getContentDescription() 7625 * @attr ref android.R.styleable#View_contentDescription 7626 */ 7627 @RemotableViewMethod 7628 public void setContentDescription(CharSequence contentDescription) { 7629 if (mContentDescription == null) { 7630 if (contentDescription == null) { 7631 return; 7632 } 7633 } else if (mContentDescription.equals(contentDescription)) { 7634 return; 7635 } 7636 mContentDescription = contentDescription; 7637 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 7638 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 7639 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 7640 notifySubtreeAccessibilityStateChangedIfNeeded(); 7641 } else { 7642 notifyViewAccessibilityStateChangedIfNeeded( 7643 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 7644 } 7645 } 7646 7647 /** 7648 * Sets the id of a view before which this one is visited in accessibility traversal. 7649 * A screen-reader must visit the content of this view before the content of the one 7650 * it precedes. For example, if view B is set to be before view A, then a screen-reader 7651 * will traverse the entire content of B before traversing the entire content of A, 7652 * regardles of what traversal strategy it is using. 7653 * <p> 7654 * Views that do not have specified before/after relationships are traversed in order 7655 * determined by the screen-reader. 7656 * </p> 7657 * <p> 7658 * Setting that this view is before a view that is not important for accessibility 7659 * or if this view is not important for accessibility will have no effect as the 7660 * screen-reader is not aware of unimportant views. 7661 * </p> 7662 * 7663 * @param beforeId The id of a view this one precedes in accessibility traversal. 7664 * 7665 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 7666 * 7667 * @see #setImportantForAccessibility(int) 7668 */ 7669 @RemotableViewMethod 7670 public void setAccessibilityTraversalBefore(int beforeId) { 7671 if (mAccessibilityTraversalBeforeId == beforeId) { 7672 return; 7673 } 7674 mAccessibilityTraversalBeforeId = beforeId; 7675 notifyViewAccessibilityStateChangedIfNeeded( 7676 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7677 } 7678 7679 /** 7680 * Gets the id of a view before which this one is visited in accessibility traversal. 7681 * 7682 * @return The id of a view this one precedes in accessibility traversal if 7683 * specified, otherwise {@link #NO_ID}. 7684 * 7685 * @see #setAccessibilityTraversalBefore(int) 7686 */ 7687 public int getAccessibilityTraversalBefore() { 7688 return mAccessibilityTraversalBeforeId; 7689 } 7690 7691 /** 7692 * Sets the id of a view after which this one is visited in accessibility traversal. 7693 * A screen-reader must visit the content of the other view before the content of this 7694 * one. For example, if view B is set to be after view A, then a screen-reader 7695 * will traverse the entire content of A before traversing the entire content of B, 7696 * regardles of what traversal strategy it is using. 7697 * <p> 7698 * Views that do not have specified before/after relationships are traversed in order 7699 * determined by the screen-reader. 7700 * </p> 7701 * <p> 7702 * Setting that this view is after a view that is not important for accessibility 7703 * or if this view is not important for accessibility will have no effect as the 7704 * screen-reader is not aware of unimportant views. 7705 * </p> 7706 * 7707 * @param afterId The id of a view this one succedees in accessibility traversal. 7708 * 7709 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 7710 * 7711 * @see #setImportantForAccessibility(int) 7712 */ 7713 @RemotableViewMethod 7714 public void setAccessibilityTraversalAfter(int afterId) { 7715 if (mAccessibilityTraversalAfterId == afterId) { 7716 return; 7717 } 7718 mAccessibilityTraversalAfterId = afterId; 7719 notifyViewAccessibilityStateChangedIfNeeded( 7720 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7721 } 7722 7723 /** 7724 * Gets the id of a view after which this one is visited in accessibility traversal. 7725 * 7726 * @return The id of a view this one succeedes in accessibility traversal if 7727 * specified, otherwise {@link #NO_ID}. 7728 * 7729 * @see #setAccessibilityTraversalAfter(int) 7730 */ 7731 public int getAccessibilityTraversalAfter() { 7732 return mAccessibilityTraversalAfterId; 7733 } 7734 7735 /** 7736 * Gets the id of a view for which this view serves as a label for 7737 * accessibility purposes. 7738 * 7739 * @return The labeled view id. 7740 */ 7741 @ViewDebug.ExportedProperty(category = "accessibility") 7742 public int getLabelFor() { 7743 return mLabelForId; 7744 } 7745 7746 /** 7747 * Sets the id of a view for which this view serves as a label for 7748 * accessibility purposes. 7749 * 7750 * @param id The labeled view id. 7751 */ 7752 @RemotableViewMethod 7753 public void setLabelFor(@IdRes int id) { 7754 if (mLabelForId == id) { 7755 return; 7756 } 7757 mLabelForId = id; 7758 if (mLabelForId != View.NO_ID 7759 && mID == View.NO_ID) { 7760 mID = generateViewId(); 7761 } 7762 notifyViewAccessibilityStateChangedIfNeeded( 7763 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7764 } 7765 7766 /** 7767 * Invoked whenever this view loses focus, either by losing window focus or by losing 7768 * focus within its window. This method can be used to clear any state tied to the 7769 * focus. For instance, if a button is held pressed with the trackball and the window 7770 * loses focus, this method can be used to cancel the press. 7771 * 7772 * Subclasses of View overriding this method should always call super.onFocusLost(). 7773 * 7774 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 7775 * @see #onWindowFocusChanged(boolean) 7776 * 7777 * @hide pending API council approval 7778 */ 7779 @CallSuper 7780 protected void onFocusLost() { 7781 resetPressedState(); 7782 } 7783 7784 private void resetPressedState() { 7785 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 7786 return; 7787 } 7788 7789 if (isPressed()) { 7790 setPressed(false); 7791 7792 if (!mHasPerformedLongPress) { 7793 removeLongPressCallback(); 7794 } 7795 } 7796 } 7797 7798 /** 7799 * Returns true if this view has focus 7800 * 7801 * @return True if this view has focus, false otherwise. 7802 */ 7803 @ViewDebug.ExportedProperty(category = "focus") 7804 public boolean isFocused() { 7805 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 7806 } 7807 7808 /** 7809 * Find the view in the hierarchy rooted at this view that currently has 7810 * focus. 7811 * 7812 * @return The view that currently has focus, or null if no focused view can 7813 * be found. 7814 */ 7815 public View findFocus() { 7816 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 7817 } 7818 7819 /** 7820 * Indicates whether this view is one of the set of scrollable containers in 7821 * its window. 7822 * 7823 * @return whether this view is one of the set of scrollable containers in 7824 * its window 7825 * 7826 * @attr ref android.R.styleable#View_isScrollContainer 7827 */ 7828 public boolean isScrollContainer() { 7829 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 7830 } 7831 7832 /** 7833 * Change whether this view is one of the set of scrollable containers in 7834 * its window. This will be used to determine whether the window can 7835 * resize or must pan when a soft input area is open -- scrollable 7836 * containers allow the window to use resize mode since the container 7837 * will appropriately shrink. 7838 * 7839 * @attr ref android.R.styleable#View_isScrollContainer 7840 */ 7841 public void setScrollContainer(boolean isScrollContainer) { 7842 if (isScrollContainer) { 7843 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 7844 mAttachInfo.mScrollContainers.add(this); 7845 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 7846 } 7847 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 7848 } else { 7849 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 7850 mAttachInfo.mScrollContainers.remove(this); 7851 } 7852 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 7853 } 7854 } 7855 7856 /** 7857 * Returns the quality of the drawing cache. 7858 * 7859 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 7860 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 7861 * 7862 * @see #setDrawingCacheQuality(int) 7863 * @see #setDrawingCacheEnabled(boolean) 7864 * @see #isDrawingCacheEnabled() 7865 * 7866 * @attr ref android.R.styleable#View_drawingCacheQuality 7867 */ 7868 @DrawingCacheQuality 7869 public int getDrawingCacheQuality() { 7870 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 7871 } 7872 7873 /** 7874 * Set the drawing cache quality of this view. This value is used only when the 7875 * drawing cache is enabled 7876 * 7877 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 7878 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 7879 * 7880 * @see #getDrawingCacheQuality() 7881 * @see #setDrawingCacheEnabled(boolean) 7882 * @see #isDrawingCacheEnabled() 7883 * 7884 * @attr ref android.R.styleable#View_drawingCacheQuality 7885 */ 7886 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 7887 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 7888 } 7889 7890 /** 7891 * Returns whether the screen should remain on, corresponding to the current 7892 * value of {@link #KEEP_SCREEN_ON}. 7893 * 7894 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 7895 * 7896 * @see #setKeepScreenOn(boolean) 7897 * 7898 * @attr ref android.R.styleable#View_keepScreenOn 7899 */ 7900 public boolean getKeepScreenOn() { 7901 return (mViewFlags & KEEP_SCREEN_ON) != 0; 7902 } 7903 7904 /** 7905 * Controls whether the screen should remain on, modifying the 7906 * value of {@link #KEEP_SCREEN_ON}. 7907 * 7908 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 7909 * 7910 * @see #getKeepScreenOn() 7911 * 7912 * @attr ref android.R.styleable#View_keepScreenOn 7913 */ 7914 public void setKeepScreenOn(boolean keepScreenOn) { 7915 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 7916 } 7917 7918 /** 7919 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 7920 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7921 * 7922 * @attr ref android.R.styleable#View_nextFocusLeft 7923 */ 7924 public int getNextFocusLeftId() { 7925 return mNextFocusLeftId; 7926 } 7927 7928 /** 7929 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 7930 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 7931 * decide automatically. 7932 * 7933 * @attr ref android.R.styleable#View_nextFocusLeft 7934 */ 7935 public void setNextFocusLeftId(int nextFocusLeftId) { 7936 mNextFocusLeftId = nextFocusLeftId; 7937 } 7938 7939 /** 7940 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 7941 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7942 * 7943 * @attr ref android.R.styleable#View_nextFocusRight 7944 */ 7945 public int getNextFocusRightId() { 7946 return mNextFocusRightId; 7947 } 7948 7949 /** 7950 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 7951 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 7952 * decide automatically. 7953 * 7954 * @attr ref android.R.styleable#View_nextFocusRight 7955 */ 7956 public void setNextFocusRightId(int nextFocusRightId) { 7957 mNextFocusRightId = nextFocusRightId; 7958 } 7959 7960 /** 7961 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 7962 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7963 * 7964 * @attr ref android.R.styleable#View_nextFocusUp 7965 */ 7966 public int getNextFocusUpId() { 7967 return mNextFocusUpId; 7968 } 7969 7970 /** 7971 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 7972 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 7973 * decide automatically. 7974 * 7975 * @attr ref android.R.styleable#View_nextFocusUp 7976 */ 7977 public void setNextFocusUpId(int nextFocusUpId) { 7978 mNextFocusUpId = nextFocusUpId; 7979 } 7980 7981 /** 7982 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 7983 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7984 * 7985 * @attr ref android.R.styleable#View_nextFocusDown 7986 */ 7987 public int getNextFocusDownId() { 7988 return mNextFocusDownId; 7989 } 7990 7991 /** 7992 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 7993 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 7994 * decide automatically. 7995 * 7996 * @attr ref android.R.styleable#View_nextFocusDown 7997 */ 7998 public void setNextFocusDownId(int nextFocusDownId) { 7999 mNextFocusDownId = nextFocusDownId; 8000 } 8001 8002 /** 8003 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8004 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8005 * 8006 * @attr ref android.R.styleable#View_nextFocusForward 8007 */ 8008 public int getNextFocusForwardId() { 8009 return mNextFocusForwardId; 8010 } 8011 8012 /** 8013 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8014 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 8015 * decide automatically. 8016 * 8017 * @attr ref android.R.styleable#View_nextFocusForward 8018 */ 8019 public void setNextFocusForwardId(int nextFocusForwardId) { 8020 mNextFocusForwardId = nextFocusForwardId; 8021 } 8022 8023 /** 8024 * Gets the id of the root of the next keyboard navigation cluster. 8025 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 8026 * decide automatically. 8027 * 8028 * @attr ref android.R.styleable#View_nextClusterForward 8029 */ 8030 public int getNextClusterForwardId() { 8031 return mNextClusterForwardId; 8032 } 8033 8034 /** 8035 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 8036 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 8037 * decide automatically. 8038 * 8039 * @attr ref android.R.styleable#View_nextClusterForward 8040 */ 8041 public void setNextClusterForwardId(int nextClusterForwardId) { 8042 mNextClusterForwardId = nextClusterForwardId; 8043 } 8044 8045 /** 8046 * Returns the visibility of this view and all of its ancestors 8047 * 8048 * @return True if this view and all of its ancestors are {@link #VISIBLE} 8049 */ 8050 public boolean isShown() { 8051 View current = this; 8052 //noinspection ConstantConditions 8053 do { 8054 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 8055 return false; 8056 } 8057 ViewParent parent = current.mParent; 8058 if (parent == null) { 8059 return false; // We are not attached to the view root 8060 } 8061 if (!(parent instanceof View)) { 8062 return true; 8063 } 8064 current = (View) parent; 8065 } while (current != null); 8066 8067 return false; 8068 } 8069 8070 /** 8071 * Called by the view hierarchy when the content insets for a window have 8072 * changed, to allow it to adjust its content to fit within those windows. 8073 * The content insets tell you the space that the status bar, input method, 8074 * and other system windows infringe on the application's window. 8075 * 8076 * <p>You do not normally need to deal with this function, since the default 8077 * window decoration given to applications takes care of applying it to the 8078 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 8079 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 8080 * and your content can be placed under those system elements. You can then 8081 * use this method within your view hierarchy if you have parts of your UI 8082 * which you would like to ensure are not being covered. 8083 * 8084 * <p>The default implementation of this method simply applies the content 8085 * insets to the view's padding, consuming that content (modifying the 8086 * insets to be 0), and returning true. This behavior is off by default, but can 8087 * be enabled through {@link #setFitsSystemWindows(boolean)}. 8088 * 8089 * <p>This function's traversal down the hierarchy is depth-first. The same content 8090 * insets object is propagated down the hierarchy, so any changes made to it will 8091 * be seen by all following views (including potentially ones above in 8092 * the hierarchy since this is a depth-first traversal). The first view 8093 * that returns true will abort the entire traversal. 8094 * 8095 * <p>The default implementation works well for a situation where it is 8096 * used with a container that covers the entire window, allowing it to 8097 * apply the appropriate insets to its content on all edges. If you need 8098 * a more complicated layout (such as two different views fitting system 8099 * windows, one on the top of the window, and one on the bottom), 8100 * you can override the method and handle the insets however you would like. 8101 * Note that the insets provided by the framework are always relative to the 8102 * far edges of the window, not accounting for the location of the called view 8103 * within that window. (In fact when this method is called you do not yet know 8104 * where the layout will place the view, as it is done before layout happens.) 8105 * 8106 * <p>Note: unlike many View methods, there is no dispatch phase to this 8107 * call. If you are overriding it in a ViewGroup and want to allow the 8108 * call to continue to your children, you must be sure to call the super 8109 * implementation. 8110 * 8111 * <p>Here is a sample layout that makes use of fitting system windows 8112 * to have controls for a video view placed inside of the window decorations 8113 * that it hides and shows. This can be used with code like the second 8114 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 8115 * 8116 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 8117 * 8118 * @param insets Current content insets of the window. Prior to 8119 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 8120 * the insets or else you and Android will be unhappy. 8121 * 8122 * @return {@code true} if this view applied the insets and it should not 8123 * continue propagating further down the hierarchy, {@code false} otherwise. 8124 * @see #getFitsSystemWindows() 8125 * @see #setFitsSystemWindows(boolean) 8126 * @see #setSystemUiVisibility(int) 8127 * 8128 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 8129 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 8130 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 8131 * to implement handling their own insets. 8132 */ 8133 @Deprecated 8134 protected boolean fitSystemWindows(Rect insets) { 8135 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 8136 if (insets == null) { 8137 // Null insets by definition have already been consumed. 8138 // This call cannot apply insets since there are none to apply, 8139 // so return false. 8140 return false; 8141 } 8142 // If we're not in the process of dispatching the newer apply insets call, 8143 // that means we're not in the compatibility path. Dispatch into the newer 8144 // apply insets path and take things from there. 8145 try { 8146 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 8147 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 8148 } finally { 8149 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 8150 } 8151 } else { 8152 // We're being called from the newer apply insets path. 8153 // Perform the standard fallback behavior. 8154 return fitSystemWindowsInt(insets); 8155 } 8156 } 8157 8158 private boolean fitSystemWindowsInt(Rect insets) { 8159 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 8160 mUserPaddingStart = UNDEFINED_PADDING; 8161 mUserPaddingEnd = UNDEFINED_PADDING; 8162 Rect localInsets = sThreadLocal.get(); 8163 if (localInsets == null) { 8164 localInsets = new Rect(); 8165 sThreadLocal.set(localInsets); 8166 } 8167 boolean res = computeFitSystemWindows(insets, localInsets); 8168 mUserPaddingLeftInitial = localInsets.left; 8169 mUserPaddingRightInitial = localInsets.right; 8170 internalSetPadding(localInsets.left, localInsets.top, 8171 localInsets.right, localInsets.bottom); 8172 return res; 8173 } 8174 return false; 8175 } 8176 8177 /** 8178 * Called when the view should apply {@link WindowInsets} according to its internal policy. 8179 * 8180 * <p>This method should be overridden by views that wish to apply a policy different from or 8181 * in addition to the default behavior. Clients that wish to force a view subtree 8182 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 8183 * 8184 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 8185 * it will be called during dispatch instead of this method. The listener may optionally 8186 * call this method from its own implementation if it wishes to apply the view's default 8187 * insets policy in addition to its own.</p> 8188 * 8189 * <p>Implementations of this method should either return the insets parameter unchanged 8190 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 8191 * that this view applied itself. This allows new inset types added in future platform 8192 * versions to pass through existing implementations unchanged without being erroneously 8193 * consumed.</p> 8194 * 8195 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 8196 * property is set then the view will consume the system window insets and apply them 8197 * as padding for the view.</p> 8198 * 8199 * @param insets Insets to apply 8200 * @return The supplied insets with any applied insets consumed 8201 */ 8202 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 8203 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 8204 // We weren't called from within a direct call to fitSystemWindows, 8205 // call into it as a fallback in case we're in a class that overrides it 8206 // and has logic to perform. 8207 if (fitSystemWindows(insets.getSystemWindowInsets())) { 8208 return insets.consumeSystemWindowInsets(); 8209 } 8210 } else { 8211 // We were called from within a direct call to fitSystemWindows. 8212 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 8213 return insets.consumeSystemWindowInsets(); 8214 } 8215 } 8216 return insets; 8217 } 8218 8219 /** 8220 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 8221 * window insets to this view. The listener's 8222 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 8223 * method will be called instead of the view's 8224 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 8225 * 8226 * @param listener Listener to set 8227 * 8228 * @see #onApplyWindowInsets(WindowInsets) 8229 */ 8230 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 8231 getListenerInfo().mOnApplyWindowInsetsListener = listener; 8232 } 8233 8234 /** 8235 * Request to apply the given window insets to this view or another view in its subtree. 8236 * 8237 * <p>This method should be called by clients wishing to apply insets corresponding to areas 8238 * obscured by window decorations or overlays. This can include the status and navigation bars, 8239 * action bars, input methods and more. New inset categories may be added in the future. 8240 * The method returns the insets provided minus any that were applied by this view or its 8241 * children.</p> 8242 * 8243 * <p>Clients wishing to provide custom behavior should override the 8244 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 8245 * {@link OnApplyWindowInsetsListener} via the 8246 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 8247 * method.</p> 8248 * 8249 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 8250 * </p> 8251 * 8252 * @param insets Insets to apply 8253 * @return The provided insets minus the insets that were consumed 8254 */ 8255 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 8256 try { 8257 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 8258 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 8259 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 8260 } else { 8261 return onApplyWindowInsets(insets); 8262 } 8263 } finally { 8264 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 8265 } 8266 } 8267 8268 /** 8269 * Compute the view's coordinate within the surface. 8270 * 8271 * <p>Computes the coordinates of this view in its surface. The argument 8272 * must be an array of two integers. After the method returns, the array 8273 * contains the x and y location in that order.</p> 8274 * @hide 8275 * @param location an array of two integers in which to hold the coordinates 8276 */ 8277 public void getLocationInSurface(@Size(2) int[] location) { 8278 getLocationInWindow(location); 8279 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 8280 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 8281 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 8282 } 8283 } 8284 8285 /** 8286 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 8287 * only available if the view is attached. 8288 * 8289 * @return WindowInsets from the top of the view hierarchy or null if View is detached 8290 */ 8291 public WindowInsets getRootWindowInsets() { 8292 if (mAttachInfo != null) { 8293 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 8294 } 8295 return null; 8296 } 8297 8298 /** 8299 * @hide Compute the insets that should be consumed by this view and the ones 8300 * that should propagate to those under it. 8301 */ 8302 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 8303 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8304 || mAttachInfo == null 8305 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 8306 && !mAttachInfo.mOverscanRequested)) { 8307 outLocalInsets.set(inoutInsets); 8308 inoutInsets.set(0, 0, 0, 0); 8309 return true; 8310 } else { 8311 // The application wants to take care of fitting system window for 8312 // the content... however we still need to take care of any overscan here. 8313 final Rect overscan = mAttachInfo.mOverscanInsets; 8314 outLocalInsets.set(overscan); 8315 inoutInsets.left -= overscan.left; 8316 inoutInsets.top -= overscan.top; 8317 inoutInsets.right -= overscan.right; 8318 inoutInsets.bottom -= overscan.bottom; 8319 return false; 8320 } 8321 } 8322 8323 /** 8324 * Compute insets that should be consumed by this view and the ones that should propagate 8325 * to those under it. 8326 * 8327 * @param in Insets currently being processed by this View, likely received as a parameter 8328 * to {@link #onApplyWindowInsets(WindowInsets)}. 8329 * @param outLocalInsets A Rect that will receive the insets that should be consumed 8330 * by this view 8331 * @return Insets that should be passed along to views under this one 8332 */ 8333 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 8334 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8335 || mAttachInfo == null 8336 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 8337 outLocalInsets.set(in.getSystemWindowInsets()); 8338 return in.consumeSystemWindowInsets(); 8339 } else { 8340 outLocalInsets.set(0, 0, 0, 0); 8341 return in; 8342 } 8343 } 8344 8345 /** 8346 * Sets whether or not this view should account for system screen decorations 8347 * such as the status bar and inset its content; that is, controlling whether 8348 * the default implementation of {@link #fitSystemWindows(Rect)} will be 8349 * executed. See that method for more details. 8350 * 8351 * <p>Note that if you are providing your own implementation of 8352 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 8353 * flag to true -- your implementation will be overriding the default 8354 * implementation that checks this flag. 8355 * 8356 * @param fitSystemWindows If true, then the default implementation of 8357 * {@link #fitSystemWindows(Rect)} will be executed. 8358 * 8359 * @attr ref android.R.styleable#View_fitsSystemWindows 8360 * @see #getFitsSystemWindows() 8361 * @see #fitSystemWindows(Rect) 8362 * @see #setSystemUiVisibility(int) 8363 */ 8364 public void setFitsSystemWindows(boolean fitSystemWindows) { 8365 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 8366 } 8367 8368 /** 8369 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 8370 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 8371 * will be executed. 8372 * 8373 * @return {@code true} if the default implementation of 8374 * {@link #fitSystemWindows(Rect)} will be executed. 8375 * 8376 * @attr ref android.R.styleable#View_fitsSystemWindows 8377 * @see #setFitsSystemWindows(boolean) 8378 * @see #fitSystemWindows(Rect) 8379 * @see #setSystemUiVisibility(int) 8380 */ 8381 @ViewDebug.ExportedProperty 8382 public boolean getFitsSystemWindows() { 8383 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 8384 } 8385 8386 /** @hide */ 8387 public boolean fitsSystemWindows() { 8388 return getFitsSystemWindows(); 8389 } 8390 8391 /** 8392 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 8393 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 8394 */ 8395 @Deprecated 8396 public void requestFitSystemWindows() { 8397 if (mParent != null) { 8398 mParent.requestFitSystemWindows(); 8399 } 8400 } 8401 8402 /** 8403 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 8404 */ 8405 public void requestApplyInsets() { 8406 requestFitSystemWindows(); 8407 } 8408 8409 /** 8410 * For use by PhoneWindow to make its own system window fitting optional. 8411 * @hide 8412 */ 8413 public void makeOptionalFitsSystemWindows() { 8414 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 8415 } 8416 8417 /** 8418 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 8419 * treat them as such. 8420 * @hide 8421 */ 8422 public void getOutsets(Rect outOutsetRect) { 8423 if (mAttachInfo != null) { 8424 outOutsetRect.set(mAttachInfo.mOutsets); 8425 } else { 8426 outOutsetRect.setEmpty(); 8427 } 8428 } 8429 8430 /** 8431 * Returns the visibility status for this view. 8432 * 8433 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8434 * @attr ref android.R.styleable#View_visibility 8435 */ 8436 @ViewDebug.ExportedProperty(mapping = { 8437 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 8438 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 8439 @ViewDebug.IntToString(from = GONE, to = "GONE") 8440 }) 8441 @Visibility 8442 public int getVisibility() { 8443 return mViewFlags & VISIBILITY_MASK; 8444 } 8445 8446 /** 8447 * Set the visibility state of this view. 8448 * 8449 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8450 * @attr ref android.R.styleable#View_visibility 8451 */ 8452 @RemotableViewMethod 8453 public void setVisibility(@Visibility int visibility) { 8454 setFlags(visibility, VISIBILITY_MASK); 8455 } 8456 8457 /** 8458 * Returns the enabled status for this view. The interpretation of the 8459 * enabled state varies by subclass. 8460 * 8461 * @return True if this view is enabled, false otherwise. 8462 */ 8463 @ViewDebug.ExportedProperty 8464 public boolean isEnabled() { 8465 return (mViewFlags & ENABLED_MASK) == ENABLED; 8466 } 8467 8468 /** 8469 * Set the enabled state of this view. The interpretation of the enabled 8470 * state varies by subclass. 8471 * 8472 * @param enabled True if this view is enabled, false otherwise. 8473 */ 8474 @RemotableViewMethod 8475 public void setEnabled(boolean enabled) { 8476 if (enabled == isEnabled()) return; 8477 8478 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 8479 8480 /* 8481 * The View most likely has to change its appearance, so refresh 8482 * the drawable state. 8483 */ 8484 refreshDrawableState(); 8485 8486 // Invalidate too, since the default behavior for views is to be 8487 // be drawn at 50% alpha rather than to change the drawable. 8488 invalidate(true); 8489 8490 if (!enabled) { 8491 cancelPendingInputEvents(); 8492 } 8493 } 8494 8495 /** 8496 * Set whether this view can receive the focus. 8497 * <p> 8498 * Setting this to false will also ensure that this view is not focusable 8499 * in touch mode. 8500 * 8501 * @param focusable If true, this view can receive the focus. 8502 * 8503 * @see #setFocusableInTouchMode(boolean) 8504 * @see #setFocusable(int) 8505 * @attr ref android.R.styleable#View_focusable 8506 */ 8507 public void setFocusable(boolean focusable) { 8508 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 8509 } 8510 8511 /** 8512 * Sets whether this view can receive focus. 8513 * <p> 8514 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 8515 * automatically based on the view's interactivity. This is the default. 8516 * <p> 8517 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 8518 * in touch mode. 8519 * 8520 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 8521 * or {@link #FOCUSABLE_AUTO}. 8522 * @see #setFocusableInTouchMode(boolean) 8523 * @attr ref android.R.styleable#View_focusable 8524 */ 8525 public void setFocusable(@Focusable int focusable) { 8526 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 8527 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 8528 } 8529 setFlags(focusable, FOCUSABLE_MASK); 8530 } 8531 8532 /** 8533 * Set whether this view can receive focus while in touch mode. 8534 * 8535 * Setting this to true will also ensure that this view is focusable. 8536 * 8537 * @param focusableInTouchMode If true, this view can receive the focus while 8538 * in touch mode. 8539 * 8540 * @see #setFocusable(boolean) 8541 * @attr ref android.R.styleable#View_focusableInTouchMode 8542 */ 8543 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 8544 // Focusable in touch mode should always be set before the focusable flag 8545 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 8546 // which, in touch mode, will not successfully request focus on this view 8547 // because the focusable in touch mode flag is not set 8548 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 8549 if (focusableInTouchMode) { 8550 setFlags(FOCUSABLE, FOCUSABLE_MASK); 8551 } 8552 } 8553 8554 /** 8555 * Set whether this view should have sound effects enabled for events such as 8556 * clicking and touching. 8557 * 8558 * <p>You may wish to disable sound effects for a view if you already play sounds, 8559 * for instance, a dial key that plays dtmf tones. 8560 * 8561 * @param soundEffectsEnabled whether sound effects are enabled for this view. 8562 * @see #isSoundEffectsEnabled() 8563 * @see #playSoundEffect(int) 8564 * @attr ref android.R.styleable#View_soundEffectsEnabled 8565 */ 8566 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 8567 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 8568 } 8569 8570 /** 8571 * @return whether this view should have sound effects enabled for events such as 8572 * clicking and touching. 8573 * 8574 * @see #setSoundEffectsEnabled(boolean) 8575 * @see #playSoundEffect(int) 8576 * @attr ref android.R.styleable#View_soundEffectsEnabled 8577 */ 8578 @ViewDebug.ExportedProperty 8579 public boolean isSoundEffectsEnabled() { 8580 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 8581 } 8582 8583 /** 8584 * Set whether this view should have haptic feedback for events such as 8585 * long presses. 8586 * 8587 * <p>You may wish to disable haptic feedback if your view already controls 8588 * its own haptic feedback. 8589 * 8590 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 8591 * @see #isHapticFeedbackEnabled() 8592 * @see #performHapticFeedback(int) 8593 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8594 */ 8595 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 8596 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 8597 } 8598 8599 /** 8600 * @return whether this view should have haptic feedback enabled for events 8601 * long presses. 8602 * 8603 * @see #setHapticFeedbackEnabled(boolean) 8604 * @see #performHapticFeedback(int) 8605 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8606 */ 8607 @ViewDebug.ExportedProperty 8608 public boolean isHapticFeedbackEnabled() { 8609 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 8610 } 8611 8612 /** 8613 * Returns the layout direction for this view. 8614 * 8615 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 8616 * {@link #LAYOUT_DIRECTION_RTL}, 8617 * {@link #LAYOUT_DIRECTION_INHERIT} or 8618 * {@link #LAYOUT_DIRECTION_LOCALE}. 8619 * 8620 * @attr ref android.R.styleable#View_layoutDirection 8621 * 8622 * @hide 8623 */ 8624 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8625 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 8626 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 8627 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 8628 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 8629 }) 8630 @LayoutDir 8631 public int getRawLayoutDirection() { 8632 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 8633 } 8634 8635 /** 8636 * Set the layout direction for this view. This will propagate a reset of layout direction 8637 * resolution to the view's children and resolve layout direction for this view. 8638 * 8639 * @param layoutDirection the layout direction to set. Should be one of: 8640 * 8641 * {@link #LAYOUT_DIRECTION_LTR}, 8642 * {@link #LAYOUT_DIRECTION_RTL}, 8643 * {@link #LAYOUT_DIRECTION_INHERIT}, 8644 * {@link #LAYOUT_DIRECTION_LOCALE}. 8645 * 8646 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 8647 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 8648 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 8649 * 8650 * @attr ref android.R.styleable#View_layoutDirection 8651 */ 8652 @RemotableViewMethod 8653 public void setLayoutDirection(@LayoutDir int layoutDirection) { 8654 if (getRawLayoutDirection() != layoutDirection) { 8655 // Reset the current layout direction and the resolved one 8656 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 8657 resetRtlProperties(); 8658 // Set the new layout direction (filtered) 8659 mPrivateFlags2 |= 8660 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 8661 // We need to resolve all RTL properties as they all depend on layout direction 8662 resolveRtlPropertiesIfNeeded(); 8663 requestLayout(); 8664 invalidate(true); 8665 } 8666 } 8667 8668 /** 8669 * Returns the resolved layout direction for this view. 8670 * 8671 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 8672 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 8673 * 8674 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 8675 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 8676 * 8677 * @attr ref android.R.styleable#View_layoutDirection 8678 */ 8679 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8680 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 8681 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 8682 }) 8683 @ResolvedLayoutDir 8684 public int getLayoutDirection() { 8685 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 8686 if (targetSdkVersion < JELLY_BEAN_MR1) { 8687 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 8688 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 8689 } 8690 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 8691 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 8692 } 8693 8694 /** 8695 * Indicates whether or not this view's layout is right-to-left. This is resolved from 8696 * layout attribute and/or the inherited value from the parent 8697 * 8698 * @return true if the layout is right-to-left. 8699 * 8700 * @hide 8701 */ 8702 @ViewDebug.ExportedProperty(category = "layout") 8703 public boolean isLayoutRtl() { 8704 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 8705 } 8706 8707 /** 8708 * Indicates whether the view is currently tracking transient state that the 8709 * app should not need to concern itself with saving and restoring, but that 8710 * the framework should take special note to preserve when possible. 8711 * 8712 * <p>A view with transient state cannot be trivially rebound from an external 8713 * data source, such as an adapter binding item views in a list. This may be 8714 * because the view is performing an animation, tracking user selection 8715 * of content, or similar.</p> 8716 * 8717 * @return true if the view has transient state 8718 */ 8719 @ViewDebug.ExportedProperty(category = "layout") 8720 public boolean hasTransientState() { 8721 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 8722 } 8723 8724 /** 8725 * Set whether this view is currently tracking transient state that the 8726 * framework should attempt to preserve when possible. This flag is reference counted, 8727 * so every call to setHasTransientState(true) should be paired with a later call 8728 * to setHasTransientState(false). 8729 * 8730 * <p>A view with transient state cannot be trivially rebound from an external 8731 * data source, such as an adapter binding item views in a list. This may be 8732 * because the view is performing an animation, tracking user selection 8733 * of content, or similar.</p> 8734 * 8735 * @param hasTransientState true if this view has transient state 8736 */ 8737 public void setHasTransientState(boolean hasTransientState) { 8738 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 8739 mTransientStateCount - 1; 8740 if (mTransientStateCount < 0) { 8741 mTransientStateCount = 0; 8742 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 8743 "unmatched pair of setHasTransientState calls"); 8744 } else if ((hasTransientState && mTransientStateCount == 1) || 8745 (!hasTransientState && mTransientStateCount == 0)) { 8746 // update flag if we've just incremented up from 0 or decremented down to 0 8747 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 8748 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 8749 if (mParent != null) { 8750 try { 8751 mParent.childHasTransientStateChanged(this, hasTransientState); 8752 } catch (AbstractMethodError e) { 8753 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 8754 " does not fully implement ViewParent", e); 8755 } 8756 } 8757 } 8758 } 8759 8760 /** 8761 * Returns true if this view is currently attached to a window. 8762 */ 8763 public boolean isAttachedToWindow() { 8764 return mAttachInfo != null; 8765 } 8766 8767 /** 8768 * Returns true if this view has been through at least one layout since it 8769 * was last attached to or detached from a window. 8770 */ 8771 public boolean isLaidOut() { 8772 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 8773 } 8774 8775 /** 8776 * If this view doesn't do any drawing on its own, set this flag to 8777 * allow further optimizations. By default, this flag is not set on 8778 * View, but could be set on some View subclasses such as ViewGroup. 8779 * 8780 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 8781 * you should clear this flag. 8782 * 8783 * @param willNotDraw whether or not this View draw on its own 8784 */ 8785 public void setWillNotDraw(boolean willNotDraw) { 8786 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 8787 } 8788 8789 /** 8790 * Returns whether or not this View draws on its own. 8791 * 8792 * @return true if this view has nothing to draw, false otherwise 8793 */ 8794 @ViewDebug.ExportedProperty(category = "drawing") 8795 public boolean willNotDraw() { 8796 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 8797 } 8798 8799 /** 8800 * When a View's drawing cache is enabled, drawing is redirected to an 8801 * offscreen bitmap. Some views, like an ImageView, must be able to 8802 * bypass this mechanism if they already draw a single bitmap, to avoid 8803 * unnecessary usage of the memory. 8804 * 8805 * @param willNotCacheDrawing true if this view does not cache its 8806 * drawing, false otherwise 8807 */ 8808 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 8809 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 8810 } 8811 8812 /** 8813 * Returns whether or not this View can cache its drawing or not. 8814 * 8815 * @return true if this view does not cache its drawing, false otherwise 8816 */ 8817 @ViewDebug.ExportedProperty(category = "drawing") 8818 public boolean willNotCacheDrawing() { 8819 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 8820 } 8821 8822 /** 8823 * Indicates whether this view reacts to click events or not. 8824 * 8825 * @return true if the view is clickable, false otherwise 8826 * 8827 * @see #setClickable(boolean) 8828 * @attr ref android.R.styleable#View_clickable 8829 */ 8830 @ViewDebug.ExportedProperty 8831 public boolean isClickable() { 8832 return (mViewFlags & CLICKABLE) == CLICKABLE; 8833 } 8834 8835 /** 8836 * Enables or disables click events for this view. When a view 8837 * is clickable it will change its state to "pressed" on every click. 8838 * Subclasses should set the view clickable to visually react to 8839 * user's clicks. 8840 * 8841 * @param clickable true to make the view clickable, false otherwise 8842 * 8843 * @see #isClickable() 8844 * @attr ref android.R.styleable#View_clickable 8845 */ 8846 public void setClickable(boolean clickable) { 8847 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 8848 } 8849 8850 /** 8851 * Indicates whether this view reacts to long click events or not. 8852 * 8853 * @return true if the view is long clickable, false otherwise 8854 * 8855 * @see #setLongClickable(boolean) 8856 * @attr ref android.R.styleable#View_longClickable 8857 */ 8858 public boolean isLongClickable() { 8859 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 8860 } 8861 8862 /** 8863 * Enables or disables long click events for this view. When a view is long 8864 * clickable it reacts to the user holding down the button for a longer 8865 * duration than a tap. This event can either launch the listener or a 8866 * context menu. 8867 * 8868 * @param longClickable true to make the view long clickable, false otherwise 8869 * @see #isLongClickable() 8870 * @attr ref android.R.styleable#View_longClickable 8871 */ 8872 public void setLongClickable(boolean longClickable) { 8873 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 8874 } 8875 8876 /** 8877 * Indicates whether this view reacts to context clicks or not. 8878 * 8879 * @return true if the view is context clickable, false otherwise 8880 * @see #setContextClickable(boolean) 8881 * @attr ref android.R.styleable#View_contextClickable 8882 */ 8883 public boolean isContextClickable() { 8884 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 8885 } 8886 8887 /** 8888 * Enables or disables context clicking for this view. This event can launch the listener. 8889 * 8890 * @param contextClickable true to make the view react to a context click, false otherwise 8891 * @see #isContextClickable() 8892 * @attr ref android.R.styleable#View_contextClickable 8893 */ 8894 public void setContextClickable(boolean contextClickable) { 8895 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 8896 } 8897 8898 /** 8899 * Sets the pressed state for this view and provides a touch coordinate for 8900 * animation hinting. 8901 * 8902 * @param pressed Pass true to set the View's internal state to "pressed", 8903 * or false to reverts the View's internal state from a 8904 * previously set "pressed" state. 8905 * @param x The x coordinate of the touch that caused the press 8906 * @param y The y coordinate of the touch that caused the press 8907 */ 8908 private void setPressed(boolean pressed, float x, float y) { 8909 if (pressed) { 8910 drawableHotspotChanged(x, y); 8911 } 8912 8913 setPressed(pressed); 8914 } 8915 8916 /** 8917 * Sets the pressed state for this view. 8918 * 8919 * @see #isClickable() 8920 * @see #setClickable(boolean) 8921 * 8922 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 8923 * the View's internal state from a previously set "pressed" state. 8924 */ 8925 public void setPressed(boolean pressed) { 8926 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 8927 8928 if (pressed) { 8929 mPrivateFlags |= PFLAG_PRESSED; 8930 } else { 8931 mPrivateFlags &= ~PFLAG_PRESSED; 8932 } 8933 8934 if (needsRefresh) { 8935 refreshDrawableState(); 8936 } 8937 dispatchSetPressed(pressed); 8938 } 8939 8940 /** 8941 * Dispatch setPressed to all of this View's children. 8942 * 8943 * @see #setPressed(boolean) 8944 * 8945 * @param pressed The new pressed state 8946 */ 8947 protected void dispatchSetPressed(boolean pressed) { 8948 } 8949 8950 /** 8951 * Indicates whether the view is currently in pressed state. Unless 8952 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 8953 * the pressed state. 8954 * 8955 * @see #setPressed(boolean) 8956 * @see #isClickable() 8957 * @see #setClickable(boolean) 8958 * 8959 * @return true if the view is currently pressed, false otherwise 8960 */ 8961 @ViewDebug.ExportedProperty 8962 public boolean isPressed() { 8963 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 8964 } 8965 8966 /** 8967 * @hide 8968 * Indicates whether this view will participate in data collection through 8969 * {@link ViewStructure}. If true, it will not provide any data 8970 * for itself or its children. If false, the normal data collection will be allowed. 8971 * 8972 * @return Returns false if assist data collection is not blocked, else true. 8973 * 8974 * @see #setAssistBlocked(boolean) 8975 * @attr ref android.R.styleable#View_assistBlocked 8976 */ 8977 public boolean isAssistBlocked() { 8978 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 8979 } 8980 8981 /** 8982 * @hide 8983 * Indicates whether this view will participate in data collection through 8984 * {@link ViewStructure} for auto-fill purposes. 8985 * 8986 * <p>If {@code true}, it will not provide any data for itself or its children. 8987 * <p>If {@code false}, the normal data collection will be allowed. 8988 * 8989 * @return Returns {@code false} if assist data collection for auto-fill is not blocked, 8990 * else {@code true}. 8991 * 8992 * TODO(b/33197203): update / remove javadoc tags below 8993 * @see #setAssistBlocked(boolean) 8994 * @attr ref android.R.styleable#View_assistBlocked 8995 */ 8996 public boolean isAutoFillBlocked() { 8997 return false; // TODO(b/33197203): properly implement it 8998 } 8999 9000 /** 9001 * @hide 9002 * Controls whether assist data collection from this view and its children is enabled 9003 * (that is, whether {@link #onProvideStructure} and 9004 * {@link #onProvideVirtualStructure} will be called). The default value is false, 9005 * allowing normal assist collection. Setting this to false will disable assist collection. 9006 * 9007 * @param enabled Set to true to <em>disable</em> assist data collection, or false 9008 * (the default) to allow it. 9009 * 9010 * @see #isAssistBlocked() 9011 * @see #onProvideStructure 9012 * @see #onProvideVirtualStructure 9013 * @attr ref android.R.styleable#View_assistBlocked 9014 */ 9015 public void setAssistBlocked(boolean enabled) { 9016 if (enabled) { 9017 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 9018 } else { 9019 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 9020 } 9021 } 9022 9023 /** 9024 * Indicates whether this view will save its state (that is, 9025 * whether its {@link #onSaveInstanceState} method will be called). 9026 * 9027 * @return Returns true if the view state saving is enabled, else false. 9028 * 9029 * @see #setSaveEnabled(boolean) 9030 * @attr ref android.R.styleable#View_saveEnabled 9031 */ 9032 public boolean isSaveEnabled() { 9033 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 9034 } 9035 9036 /** 9037 * Controls whether the saving of this view's state is 9038 * enabled (that is, whether its {@link #onSaveInstanceState} method 9039 * will be called). Note that even if freezing is enabled, the 9040 * view still must have an id assigned to it (via {@link #setId(int)}) 9041 * for its state to be saved. This flag can only disable the 9042 * saving of this view; any child views may still have their state saved. 9043 * 9044 * @param enabled Set to false to <em>disable</em> state saving, or true 9045 * (the default) to allow it. 9046 * 9047 * @see #isSaveEnabled() 9048 * @see #setId(int) 9049 * @see #onSaveInstanceState() 9050 * @attr ref android.R.styleable#View_saveEnabled 9051 */ 9052 public void setSaveEnabled(boolean enabled) { 9053 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 9054 } 9055 9056 /** 9057 * Gets whether the framework should discard touches when the view's 9058 * window is obscured by another visible window. 9059 * Refer to the {@link View} security documentation for more details. 9060 * 9061 * @return True if touch filtering is enabled. 9062 * 9063 * @see #setFilterTouchesWhenObscured(boolean) 9064 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9065 */ 9066 @ViewDebug.ExportedProperty 9067 public boolean getFilterTouchesWhenObscured() { 9068 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 9069 } 9070 9071 /** 9072 * Sets whether the framework should discard touches when the view's 9073 * window is obscured by another visible window. 9074 * Refer to the {@link View} security documentation for more details. 9075 * 9076 * @param enabled True if touch filtering should be enabled. 9077 * 9078 * @see #getFilterTouchesWhenObscured 9079 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9080 */ 9081 public void setFilterTouchesWhenObscured(boolean enabled) { 9082 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 9083 FILTER_TOUCHES_WHEN_OBSCURED); 9084 } 9085 9086 /** 9087 * Indicates whether the entire hierarchy under this view will save its 9088 * state when a state saving traversal occurs from its parent. The default 9089 * is true; if false, these views will not be saved unless 9090 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9091 * 9092 * @return Returns true if the view state saving from parent is enabled, else false. 9093 * 9094 * @see #setSaveFromParentEnabled(boolean) 9095 */ 9096 public boolean isSaveFromParentEnabled() { 9097 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 9098 } 9099 9100 /** 9101 * Controls whether the entire hierarchy under this view will save its 9102 * state when a state saving traversal occurs from its parent. The default 9103 * is true; if false, these views will not be saved unless 9104 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9105 * 9106 * @param enabled Set to false to <em>disable</em> state saving, or true 9107 * (the default) to allow it. 9108 * 9109 * @see #isSaveFromParentEnabled() 9110 * @see #setId(int) 9111 * @see #onSaveInstanceState() 9112 */ 9113 public void setSaveFromParentEnabled(boolean enabled) { 9114 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 9115 } 9116 9117 9118 /** 9119 * Returns whether this View is currently able to take focus. 9120 * 9121 * @return True if this view can take focus, or false otherwise. 9122 */ 9123 @ViewDebug.ExportedProperty(category = "focus") 9124 public final boolean isFocusable() { 9125 return FOCUSABLE == (mViewFlags & FOCUSABLE); 9126 } 9127 9128 /** 9129 * Returns the focusable setting for this view. 9130 * 9131 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 9132 * @attr ref android.R.styleable#View_focusable 9133 */ 9134 @ViewDebug.ExportedProperty(mapping = { 9135 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 9136 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 9137 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 9138 }) 9139 @Focusable 9140 public int getFocusable() { 9141 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 9142 } 9143 9144 /** 9145 * When a view is focusable, it may not want to take focus when in touch mode. 9146 * For example, a button would like focus when the user is navigating via a D-pad 9147 * so that the user can click on it, but once the user starts touching the screen, 9148 * the button shouldn't take focus 9149 * @return Whether the view is focusable in touch mode. 9150 * @attr ref android.R.styleable#View_focusableInTouchMode 9151 */ 9152 @ViewDebug.ExportedProperty 9153 public final boolean isFocusableInTouchMode() { 9154 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 9155 } 9156 9157 /** 9158 * Find the nearest view in the specified direction that can take focus. 9159 * This does not actually give focus to that view. 9160 * 9161 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9162 * 9163 * @return The nearest focusable in the specified direction, or null if none 9164 * can be found. 9165 */ 9166 public View focusSearch(@FocusRealDirection int direction) { 9167 if (mParent != null) { 9168 return mParent.focusSearch(this, direction); 9169 } else { 9170 return null; 9171 } 9172 } 9173 9174 /** 9175 * Returns whether this View is a root of a keyboard navigation cluster. 9176 * 9177 * @return True if this view is a root of a cluster, or false otherwise. 9178 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9179 */ 9180 @ViewDebug.ExportedProperty(category = "keyboardNavigationCluster") 9181 public final boolean isKeyboardNavigationCluster() { 9182 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 9183 } 9184 9185 /** 9186 * Set whether this view is a root of a keyboard navigation cluster. 9187 * 9188 * @param isCluster If true, this view is a root of a cluster. 9189 * 9190 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9191 */ 9192 public void setKeyboardNavigationCluster(boolean isCluster) { 9193 if (isCluster) { 9194 mPrivateFlags3 |= PFLAG3_CLUSTER; 9195 } else { 9196 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 9197 } 9198 } 9199 9200 /** 9201 * Returns whether this View should receive focus when the focus is restored for the view 9202 * hierarchy containing this view. 9203 * <p> 9204 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 9205 * window or serves as a target of cluster navigation. 9206 * 9207 * @see #restoreDefaultFocus(int) 9208 * 9209 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 9210 * @attr ref android.R.styleable#View_focusedByDefault 9211 */ 9212 @ViewDebug.ExportedProperty(category = "focusedByDefault") 9213 public final boolean isFocusedByDefault() { 9214 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 9215 } 9216 9217 /** 9218 * Sets whether this View should receive focus when the focus is restored for the view 9219 * hierarchy containing this view. 9220 * <p> 9221 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 9222 * window or serves as a target of cluster navigation. 9223 * 9224 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 9225 * {@code false} otherwise. 9226 * 9227 * @see #restoreDefaultFocus(int) 9228 * 9229 * @attr ref android.R.styleable#View_focusedByDefault 9230 */ 9231 public void setFocusedByDefault(boolean isFocusedByDefault) { 9232 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 9233 return; 9234 } 9235 9236 if (isFocusedByDefault) { 9237 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 9238 } else { 9239 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 9240 } 9241 9242 if (mParent instanceof ViewGroup) { 9243 if (isFocusedByDefault) { 9244 ((ViewGroup) mParent).setDefaultFocus(this); 9245 } else { 9246 ((ViewGroup) mParent).cleanDefaultFocus(this); 9247 } 9248 } 9249 } 9250 9251 /** 9252 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 9253 * 9254 * @return {@code true} if this view has default focus, {@code false} otherwise 9255 */ 9256 boolean hasDefaultFocus() { 9257 return isFocusedByDefault(); 9258 } 9259 9260 /** 9261 * Find the nearest keyboard navigation cluster in the specified direction. 9262 * This does not actually give focus to that cluster. 9263 * 9264 * @param currentCluster The starting point of the search. Null means the current cluster is not 9265 * found yet 9266 * @param direction Direction to look 9267 * 9268 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 9269 * can be found 9270 */ 9271 public View keyboardNavigationClusterSearch(View currentCluster, int direction) { 9272 if (isKeyboardNavigationCluster()) { 9273 currentCluster = this; 9274 } 9275 if (isRootNamespace()) { 9276 // Root namespace means we should consider ourselves the top of the 9277 // tree for group searching; otherwise we could be group searching 9278 // into other tabs. see LocalActivityManager and TabHost for more info. 9279 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 9280 this, currentCluster, direction); 9281 } else if (mParent != null) { 9282 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 9283 } 9284 return null; 9285 } 9286 9287 /** 9288 * This method is the last chance for the focused view and its ancestors to 9289 * respond to an arrow key. This is called when the focused view did not 9290 * consume the key internally, nor could the view system find a new view in 9291 * the requested direction to give focus to. 9292 * 9293 * @param focused The currently focused view. 9294 * @param direction The direction focus wants to move. One of FOCUS_UP, 9295 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 9296 * @return True if the this view consumed this unhandled move. 9297 */ 9298 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 9299 return false; 9300 } 9301 9302 /** 9303 * If a user manually specified the next view id for a particular direction, 9304 * use the root to look up the view. 9305 * @param root The root view of the hierarchy containing this view. 9306 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 9307 * or FOCUS_BACKWARD. 9308 * @return The user specified next view, or null if there is none. 9309 */ 9310 View findUserSetNextFocus(View root, @FocusDirection int direction) { 9311 switch (direction) { 9312 case FOCUS_LEFT: 9313 if (mNextFocusLeftId == View.NO_ID) return null; 9314 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 9315 case FOCUS_RIGHT: 9316 if (mNextFocusRightId == View.NO_ID) return null; 9317 return findViewInsideOutShouldExist(root, mNextFocusRightId); 9318 case FOCUS_UP: 9319 if (mNextFocusUpId == View.NO_ID) return null; 9320 return findViewInsideOutShouldExist(root, mNextFocusUpId); 9321 case FOCUS_DOWN: 9322 if (mNextFocusDownId == View.NO_ID) return null; 9323 return findViewInsideOutShouldExist(root, mNextFocusDownId); 9324 case FOCUS_FORWARD: 9325 if (mNextFocusForwardId == View.NO_ID) return null; 9326 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 9327 case FOCUS_BACKWARD: { 9328 if (mID == View.NO_ID) return null; 9329 final int id = mID; 9330 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 9331 @Override 9332 public boolean apply(View t) { 9333 return t.mNextFocusForwardId == id; 9334 } 9335 }); 9336 } 9337 } 9338 return null; 9339 } 9340 9341 private View findViewInsideOutShouldExist(View root, int id) { 9342 if (mMatchIdPredicate == null) { 9343 mMatchIdPredicate = new MatchIdPredicate(); 9344 } 9345 mMatchIdPredicate.mId = id; 9346 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 9347 if (result == null) { 9348 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 9349 } 9350 return result; 9351 } 9352 9353 /** 9354 * Find and return all focusable views that are descendants of this view, 9355 * possibly including this view if it is focusable itself. 9356 * 9357 * @param direction The direction of the focus 9358 * @return A list of focusable views 9359 */ 9360 public ArrayList<View> getFocusables(@FocusDirection int direction) { 9361 ArrayList<View> result = new ArrayList<View>(24); 9362 addFocusables(result, direction); 9363 return result; 9364 } 9365 9366 /** 9367 * Add any focusable views that are descendants of this view (possibly 9368 * including this view if it is focusable itself) to views. If we are in touch mode, 9369 * only add views that are also focusable in touch mode. 9370 * 9371 * @param views Focusable views found so far 9372 * @param direction The direction of the focus 9373 */ 9374 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 9375 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 9376 } 9377 9378 /** 9379 * Adds any focusable views that are descendants of this view (possibly 9380 * including this view if it is focusable itself) to views. This method 9381 * adds all focusable views regardless if we are in touch mode or 9382 * only views focusable in touch mode if we are in touch mode or 9383 * only views that can take accessibility focus if accessibility is enabled 9384 * depending on the focusable mode parameter. 9385 * 9386 * @param views Focusable views found so far or null if all we are interested is 9387 * the number of focusables. 9388 * @param direction The direction of the focus. 9389 * @param focusableMode The type of focusables to be added. 9390 * 9391 * @see #FOCUSABLES_ALL 9392 * @see #FOCUSABLES_TOUCH_MODE 9393 */ 9394 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 9395 @FocusableMode int focusableMode) { 9396 if (views == null) { 9397 return; 9398 } 9399 if (!isFocusable()) { 9400 return; 9401 } 9402 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 9403 && !isFocusableInTouchMode()) { 9404 return; 9405 } 9406 views.add(this); 9407 } 9408 9409 /** 9410 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 9411 * including this view if it is a cluster root itself) to views. 9412 * 9413 * @param views Keyboard navigation cluster roots found so far 9414 * @param direction Direction to look 9415 */ 9416 public void addKeyboardNavigationClusters( 9417 @NonNull Collection<View> views, 9418 int direction) { 9419 if (!(isKeyboardNavigationCluster())) { 9420 return; 9421 } 9422 views.add(this); 9423 } 9424 9425 /** 9426 * Finds the Views that contain given text. The containment is case insensitive. 9427 * The search is performed by either the text that the View renders or the content 9428 * description that describes the view for accessibility purposes and the view does 9429 * not render or both. Clients can specify how the search is to be performed via 9430 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 9431 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 9432 * 9433 * @param outViews The output list of matching Views. 9434 * @param searched The text to match against. 9435 * 9436 * @see #FIND_VIEWS_WITH_TEXT 9437 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 9438 * @see #setContentDescription(CharSequence) 9439 */ 9440 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 9441 @FindViewFlags int flags) { 9442 if (getAccessibilityNodeProvider() != null) { 9443 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 9444 outViews.add(this); 9445 } 9446 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 9447 && (searched != null && searched.length() > 0) 9448 && (mContentDescription != null && mContentDescription.length() > 0)) { 9449 String searchedLowerCase = searched.toString().toLowerCase(); 9450 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 9451 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 9452 outViews.add(this); 9453 } 9454 } 9455 } 9456 9457 /** 9458 * Find and return all touchable views that are descendants of this view, 9459 * possibly including this view if it is touchable itself. 9460 * 9461 * @return A list of touchable views 9462 */ 9463 public ArrayList<View> getTouchables() { 9464 ArrayList<View> result = new ArrayList<View>(); 9465 addTouchables(result); 9466 return result; 9467 } 9468 9469 /** 9470 * Add any touchable views that are descendants of this view (possibly 9471 * including this view if it is touchable itself) to views. 9472 * 9473 * @param views Touchable views found so far 9474 */ 9475 public void addTouchables(ArrayList<View> views) { 9476 final int viewFlags = mViewFlags; 9477 9478 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 9479 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 9480 && (viewFlags & ENABLED_MASK) == ENABLED) { 9481 views.add(this); 9482 } 9483 } 9484 9485 /** 9486 * Returns whether this View is accessibility focused. 9487 * 9488 * @return True if this View is accessibility focused. 9489 */ 9490 public boolean isAccessibilityFocused() { 9491 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 9492 } 9493 9494 /** 9495 * Call this to try to give accessibility focus to this view. 9496 * 9497 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 9498 * returns false or the view is no visible or the view already has accessibility 9499 * focus. 9500 * 9501 * See also {@link #focusSearch(int)}, which is what you call to say that you 9502 * have focus, and you want your parent to look for the next one. 9503 * 9504 * @return Whether this view actually took accessibility focus. 9505 * 9506 * @hide 9507 */ 9508 public boolean requestAccessibilityFocus() { 9509 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 9510 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 9511 return false; 9512 } 9513 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9514 return false; 9515 } 9516 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 9517 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 9518 ViewRootImpl viewRootImpl = getViewRootImpl(); 9519 if (viewRootImpl != null) { 9520 viewRootImpl.setAccessibilityFocus(this, null); 9521 } 9522 invalidate(); 9523 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 9524 return true; 9525 } 9526 return false; 9527 } 9528 9529 /** 9530 * Call this to try to clear accessibility focus of this view. 9531 * 9532 * See also {@link #focusSearch(int)}, which is what you call to say that you 9533 * have focus, and you want your parent to look for the next one. 9534 * 9535 * @hide 9536 */ 9537 public void clearAccessibilityFocus() { 9538 clearAccessibilityFocusNoCallbacks(0); 9539 9540 // Clear the global reference of accessibility focus if this view or 9541 // any of its descendants had accessibility focus. This will NOT send 9542 // an event or update internal state if focus is cleared from a 9543 // descendant view, which may leave views in inconsistent states. 9544 final ViewRootImpl viewRootImpl = getViewRootImpl(); 9545 if (viewRootImpl != null) { 9546 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 9547 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 9548 viewRootImpl.setAccessibilityFocus(null, null); 9549 } 9550 } 9551 } 9552 9553 private void sendAccessibilityHoverEvent(int eventType) { 9554 // Since we are not delivering to a client accessibility events from not 9555 // important views (unless the clinet request that) we need to fire the 9556 // event from the deepest view exposed to the client. As a consequence if 9557 // the user crosses a not exposed view the client will see enter and exit 9558 // of the exposed predecessor followed by and enter and exit of that same 9559 // predecessor when entering and exiting the not exposed descendant. This 9560 // is fine since the client has a clear idea which view is hovered at the 9561 // price of a couple more events being sent. This is a simple and 9562 // working solution. 9563 View source = this; 9564 while (true) { 9565 if (source.includeForAccessibility()) { 9566 source.sendAccessibilityEvent(eventType); 9567 return; 9568 } 9569 ViewParent parent = source.getParent(); 9570 if (parent instanceof View) { 9571 source = (View) parent; 9572 } else { 9573 return; 9574 } 9575 } 9576 } 9577 9578 /** 9579 * Clears accessibility focus without calling any callback methods 9580 * normally invoked in {@link #clearAccessibilityFocus()}. This method 9581 * is used separately from that one for clearing accessibility focus when 9582 * giving this focus to another view. 9583 * 9584 * @param action The action, if any, that led to focus being cleared. Set to 9585 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 9586 * the window. 9587 */ 9588 void clearAccessibilityFocusNoCallbacks(int action) { 9589 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 9590 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 9591 invalidate(); 9592 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 9593 AccessibilityEvent event = AccessibilityEvent.obtain( 9594 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 9595 event.setAction(action); 9596 if (mAccessibilityDelegate != null) { 9597 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 9598 } else { 9599 sendAccessibilityEventUnchecked(event); 9600 } 9601 } 9602 } 9603 } 9604 9605 /** 9606 * Call this to try to give focus to a specific view or to one of its 9607 * descendants. 9608 * 9609 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9610 * false), or if it is focusable and it is not focusable in touch mode 9611 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9612 * 9613 * See also {@link #focusSearch(int)}, which is what you call to say that you 9614 * have focus, and you want your parent to look for the next one. 9615 * 9616 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 9617 * {@link #FOCUS_DOWN} and <code>null</code>. 9618 * 9619 * @return Whether this view or one of its descendants actually took focus. 9620 */ 9621 public final boolean requestFocus() { 9622 return requestFocus(View.FOCUS_DOWN); 9623 } 9624 9625 /** 9626 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 9627 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 9628 * Nested keyboard navigation clusters are excluded from the hierarchy. 9629 * 9630 * @param direction The direction of the focus 9631 * @return Whether this view or one of its descendants actually took focus 9632 */ 9633 public boolean restoreDefaultFocus(@FocusDirection int direction) { 9634 return requestFocus(direction); 9635 } 9636 9637 /** 9638 * Call this to try to give focus to a specific view or to one of its 9639 * descendants and give it a hint about what direction focus is heading. 9640 * 9641 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9642 * false), or if it is focusable and it is not focusable in touch mode 9643 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9644 * 9645 * See also {@link #focusSearch(int)}, which is what you call to say that you 9646 * have focus, and you want your parent to look for the next one. 9647 * 9648 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 9649 * <code>null</code> set for the previously focused rectangle. 9650 * 9651 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9652 * @return Whether this view or one of its descendants actually took focus. 9653 */ 9654 public final boolean requestFocus(int direction) { 9655 return requestFocus(direction, null); 9656 } 9657 9658 /** 9659 * Call this to try to give focus to a specific view or to one of its descendants 9660 * and give it hints about the direction and a specific rectangle that the focus 9661 * is coming from. The rectangle can help give larger views a finer grained hint 9662 * about where focus is coming from, and therefore, where to show selection, or 9663 * forward focus change internally. 9664 * 9665 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9666 * false), or if it is focusable and it is not focusable in touch mode 9667 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9668 * 9669 * A View will not take focus if it is not visible. 9670 * 9671 * A View will not take focus if one of its parents has 9672 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 9673 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 9674 * 9675 * See also {@link #focusSearch(int)}, which is what you call to say that you 9676 * have focus, and you want your parent to look for the next one. 9677 * 9678 * You may wish to override this method if your custom {@link View} has an internal 9679 * {@link View} that it wishes to forward the request to. 9680 * 9681 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9682 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 9683 * to give a finer grained hint about where focus is coming from. May be null 9684 * if there is no hint. 9685 * @return Whether this view or one of its descendants actually took focus. 9686 */ 9687 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 9688 return requestFocusNoSearch(direction, previouslyFocusedRect); 9689 } 9690 9691 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 9692 // need to be focusable 9693 if ((mViewFlags & FOCUSABLE) != FOCUSABLE 9694 || (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9695 return false; 9696 } 9697 9698 // need to be focusable in touch mode if in touch mode 9699 if (isInTouchMode() && 9700 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 9701 return false; 9702 } 9703 9704 // need to not have any parents blocking us 9705 if (hasAncestorThatBlocksDescendantFocus()) { 9706 return false; 9707 } 9708 9709 handleFocusGainInternal(direction, previouslyFocusedRect); 9710 return true; 9711 } 9712 9713 /** 9714 * Call this to try to give focus to a specific view or to one of its descendants. This is a 9715 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 9716 * touch mode to request focus when they are touched. 9717 * 9718 * @return Whether this view or one of its descendants actually took focus. 9719 * 9720 * @see #isInTouchMode() 9721 * 9722 */ 9723 public final boolean requestFocusFromTouch() { 9724 // Leave touch mode if we need to 9725 if (isInTouchMode()) { 9726 ViewRootImpl viewRoot = getViewRootImpl(); 9727 if (viewRoot != null) { 9728 viewRoot.ensureTouchMode(false); 9729 } 9730 } 9731 return requestFocus(View.FOCUS_DOWN); 9732 } 9733 9734 /** 9735 * @return Whether any ancestor of this view blocks descendant focus. 9736 */ 9737 private boolean hasAncestorThatBlocksDescendantFocus() { 9738 final boolean focusableInTouchMode = isFocusableInTouchMode(); 9739 ViewParent ancestor = mParent; 9740 while (ancestor instanceof ViewGroup) { 9741 final ViewGroup vgAncestor = (ViewGroup) ancestor; 9742 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 9743 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 9744 return true; 9745 } else { 9746 ancestor = vgAncestor.getParent(); 9747 } 9748 } 9749 return false; 9750 } 9751 9752 /** 9753 * Gets the mode for determining whether this View is important for accessibility. 9754 * A view is important for accessibility if it fires accessibility events and if it 9755 * is reported to accessibility services that query the screen. 9756 * 9757 * @return The mode for determining whether a view is important for accessibility, one 9758 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 9759 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 9760 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 9761 * 9762 * @attr ref android.R.styleable#View_importantForAccessibility 9763 * 9764 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9765 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9766 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9767 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9768 */ 9769 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 9770 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 9771 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 9772 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 9773 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 9774 to = "noHideDescendants") 9775 }) 9776 public int getImportantForAccessibility() { 9777 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9778 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9779 } 9780 9781 /** 9782 * Sets the live region mode for this view. This indicates to accessibility 9783 * services whether they should automatically notify the user about changes 9784 * to the view's content description or text, or to the content descriptions 9785 * or text of the view's children (where applicable). 9786 * <p> 9787 * For example, in a login screen with a TextView that displays an "incorrect 9788 * password" notification, that view should be marked as a live region with 9789 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9790 * <p> 9791 * To disable change notifications for this view, use 9792 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 9793 * mode for most views. 9794 * <p> 9795 * To indicate that the user should be notified of changes, use 9796 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9797 * <p> 9798 * If the view's changes should interrupt ongoing speech and notify the user 9799 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 9800 * 9801 * @param mode The live region mode for this view, one of: 9802 * <ul> 9803 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 9804 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 9805 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 9806 * </ul> 9807 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9808 */ 9809 public void setAccessibilityLiveRegion(int mode) { 9810 if (mode != getAccessibilityLiveRegion()) { 9811 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9812 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 9813 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9814 notifyViewAccessibilityStateChangedIfNeeded( 9815 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9816 } 9817 } 9818 9819 /** 9820 * Gets the live region mode for this View. 9821 * 9822 * @return The live region mode for the view. 9823 * 9824 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9825 * 9826 * @see #setAccessibilityLiveRegion(int) 9827 */ 9828 public int getAccessibilityLiveRegion() { 9829 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 9830 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 9831 } 9832 9833 /** 9834 * Sets how to determine whether this view is important for accessibility 9835 * which is if it fires accessibility events and if it is reported to 9836 * accessibility services that query the screen. 9837 * 9838 * @param mode How to determine whether this view is important for accessibility. 9839 * 9840 * @attr ref android.R.styleable#View_importantForAccessibility 9841 * 9842 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9843 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9844 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9845 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9846 */ 9847 public void setImportantForAccessibility(int mode) { 9848 final int oldMode = getImportantForAccessibility(); 9849 if (mode != oldMode) { 9850 final boolean hideDescendants = 9851 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 9852 9853 // If this node or its descendants are no longer important, try to 9854 // clear accessibility focus. 9855 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 9856 final View focusHost = findAccessibilityFocusHost(hideDescendants); 9857 if (focusHost != null) { 9858 focusHost.clearAccessibilityFocus(); 9859 } 9860 } 9861 9862 // If we're moving between AUTO and another state, we might not need 9863 // to send a subtree changed notification. We'll store the computed 9864 // importance, since we'll need to check it later to make sure. 9865 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 9866 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 9867 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 9868 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9869 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 9870 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9871 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 9872 notifySubtreeAccessibilityStateChangedIfNeeded(); 9873 } else { 9874 notifyViewAccessibilityStateChangedIfNeeded( 9875 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9876 } 9877 } 9878 } 9879 9880 /** 9881 * Returns the view within this view's hierarchy that is hosting 9882 * accessibility focus. 9883 * 9884 * @param searchDescendants whether to search for focus in descendant views 9885 * @return the view hosting accessibility focus, or {@code null} 9886 */ 9887 private View findAccessibilityFocusHost(boolean searchDescendants) { 9888 if (isAccessibilityFocusedViewOrHost()) { 9889 return this; 9890 } 9891 9892 if (searchDescendants) { 9893 final ViewRootImpl viewRoot = getViewRootImpl(); 9894 if (viewRoot != null) { 9895 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 9896 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 9897 return focusHost; 9898 } 9899 } 9900 } 9901 9902 return null; 9903 } 9904 9905 /** 9906 * Computes whether this view should be exposed for accessibility. In 9907 * general, views that are interactive or provide information are exposed 9908 * while views that serve only as containers are hidden. 9909 * <p> 9910 * If an ancestor of this view has importance 9911 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 9912 * returns <code>false</code>. 9913 * <p> 9914 * Otherwise, the value is computed according to the view's 9915 * {@link #getImportantForAccessibility()} value: 9916 * <ol> 9917 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 9918 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 9919 * </code> 9920 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 9921 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 9922 * view satisfies any of the following: 9923 * <ul> 9924 * <li>Is actionable, e.g. {@link #isClickable()}, 9925 * {@link #isLongClickable()}, or {@link #isFocusable()} 9926 * <li>Has an {@link AccessibilityDelegate} 9927 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 9928 * {@link OnKeyListener}, etc. 9929 * <li>Is an accessibility live region, e.g. 9930 * {@link #getAccessibilityLiveRegion()} is not 9931 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 9932 * </ul> 9933 * </ol> 9934 * 9935 * @return Whether the view is exposed for accessibility. 9936 * @see #setImportantForAccessibility(int) 9937 * @see #getImportantForAccessibility() 9938 */ 9939 public boolean isImportantForAccessibility() { 9940 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9941 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9942 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 9943 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 9944 return false; 9945 } 9946 9947 // Check parent mode to ensure we're not hidden. 9948 ViewParent parent = mParent; 9949 while (parent instanceof View) { 9950 if (((View) parent).getImportantForAccessibility() 9951 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 9952 return false; 9953 } 9954 parent = parent.getParent(); 9955 } 9956 9957 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 9958 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 9959 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 9960 } 9961 9962 /** 9963 * Gets the parent for accessibility purposes. Note that the parent for 9964 * accessibility is not necessary the immediate parent. It is the first 9965 * predecessor that is important for accessibility. 9966 * 9967 * @return The parent for accessibility purposes. 9968 */ 9969 public ViewParent getParentForAccessibility() { 9970 if (mParent instanceof View) { 9971 View parentView = (View) mParent; 9972 if (parentView.includeForAccessibility()) { 9973 return mParent; 9974 } else { 9975 return mParent.getParentForAccessibility(); 9976 } 9977 } 9978 return null; 9979 } 9980 9981 /** 9982 * Adds the children of this View relevant for accessibility to the given list 9983 * as output. Since some Views are not important for accessibility the added 9984 * child views are not necessarily direct children of this view, rather they are 9985 * the first level of descendants important for accessibility. 9986 * 9987 * @param outChildren The output list that will receive children for accessibility. 9988 */ 9989 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 9990 9991 } 9992 9993 /** 9994 * Whether to regard this view for accessibility. A view is regarded for 9995 * accessibility if it is important for accessibility or the querying 9996 * accessibility service has explicitly requested that view not 9997 * important for accessibility are regarded. 9998 * 9999 * @return Whether to regard the view for accessibility. 10000 * 10001 * @hide 10002 */ 10003 public boolean includeForAccessibility() { 10004 if (mAttachInfo != null) { 10005 return (mAttachInfo.mAccessibilityFetchFlags 10006 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 10007 || isImportantForAccessibility(); 10008 } 10009 return false; 10010 } 10011 10012 /** 10013 * Returns whether the View is considered actionable from 10014 * accessibility perspective. Such view are important for 10015 * accessibility. 10016 * 10017 * @return True if the view is actionable for accessibility. 10018 * 10019 * @hide 10020 */ 10021 public boolean isActionableForAccessibility() { 10022 return (isClickable() || isLongClickable() || isFocusable()); 10023 } 10024 10025 /** 10026 * Returns whether the View has registered callbacks which makes it 10027 * important for accessibility. 10028 * 10029 * @return True if the view is actionable for accessibility. 10030 */ 10031 private boolean hasListenersForAccessibility() { 10032 ListenerInfo info = getListenerInfo(); 10033 return mTouchDelegate != null || info.mOnKeyListener != null 10034 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 10035 || info.mOnHoverListener != null || info.mOnDragListener != null; 10036 } 10037 10038 /** 10039 * Notifies that the accessibility state of this view changed. The change 10040 * is local to this view and does not represent structural changes such 10041 * as children and parent. For example, the view became focusable. The 10042 * notification is at at most once every 10043 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 10044 * to avoid unnecessary load to the system. Also once a view has a pending 10045 * notification this method is a NOP until the notification has been sent. 10046 * 10047 * @hide 10048 */ 10049 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 10050 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 10051 return; 10052 } 10053 if (mSendViewStateChangedAccessibilityEvent == null) { 10054 mSendViewStateChangedAccessibilityEvent = 10055 new SendViewStateChangedAccessibilityEvent(); 10056 } 10057 mSendViewStateChangedAccessibilityEvent.runOrPost(changeType); 10058 } 10059 10060 /** 10061 * Notifies that the accessibility state of this view changed. The change 10062 * is *not* local to this view and does represent structural changes such 10063 * as children and parent. For example, the view size changed. The 10064 * notification is at at most once every 10065 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 10066 * to avoid unnecessary load to the system. Also once a view has a pending 10067 * notification this method is a NOP until the notification has been sent. 10068 * 10069 * @hide 10070 */ 10071 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 10072 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 10073 return; 10074 } 10075 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 10076 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 10077 if (mParent != null) { 10078 try { 10079 mParent.notifySubtreeAccessibilityStateChanged( 10080 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 10081 } catch (AbstractMethodError e) { 10082 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 10083 " does not fully implement ViewParent", e); 10084 } 10085 } 10086 } 10087 } 10088 10089 /** 10090 * Change the visibility of the View without triggering any other changes. This is 10091 * important for transitions, where visibility changes should not adjust focus or 10092 * trigger a new layout. This is only used when the visibility has already been changed 10093 * and we need a transient value during an animation. When the animation completes, 10094 * the original visibility value is always restored. 10095 * 10096 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 10097 * @hide 10098 */ 10099 public void setTransitionVisibility(@Visibility int visibility) { 10100 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 10101 } 10102 10103 /** 10104 * Reset the flag indicating the accessibility state of the subtree rooted 10105 * at this view changed. 10106 */ 10107 void resetSubtreeAccessibilityStateChanged() { 10108 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 10109 } 10110 10111 /** 10112 * Report an accessibility action to this view's parents for delegated processing. 10113 * 10114 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 10115 * call this method to delegate an accessibility action to a supporting parent. If the parent 10116 * returns true from its 10117 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 10118 * method this method will return true to signify that the action was consumed.</p> 10119 * 10120 * <p>This method is useful for implementing nested scrolling child views. If 10121 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 10122 * a custom view implementation may invoke this method to allow a parent to consume the 10123 * scroll first. If this method returns true the custom view should skip its own scrolling 10124 * behavior.</p> 10125 * 10126 * @param action Accessibility action to delegate 10127 * @param arguments Optional action arguments 10128 * @return true if the action was consumed by a parent 10129 */ 10130 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 10131 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 10132 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 10133 return true; 10134 } 10135 } 10136 return false; 10137 } 10138 10139 /** 10140 * Performs the specified accessibility action on the view. For 10141 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 10142 * <p> 10143 * If an {@link AccessibilityDelegate} has been specified via calling 10144 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10145 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 10146 * is responsible for handling this call. 10147 * </p> 10148 * 10149 * <p>The default implementation will delegate 10150 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 10151 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 10152 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 10153 * 10154 * @param action The action to perform. 10155 * @param arguments Optional action arguments. 10156 * @return Whether the action was performed. 10157 */ 10158 public boolean performAccessibilityAction(int action, Bundle arguments) { 10159 if (mAccessibilityDelegate != null) { 10160 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 10161 } else { 10162 return performAccessibilityActionInternal(action, arguments); 10163 } 10164 } 10165 10166 /** 10167 * @see #performAccessibilityAction(int, Bundle) 10168 * 10169 * Note: Called from the default {@link AccessibilityDelegate}. 10170 * 10171 * @hide 10172 */ 10173 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 10174 if (isNestedScrollingEnabled() 10175 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 10176 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 10177 || action == R.id.accessibilityActionScrollUp 10178 || action == R.id.accessibilityActionScrollLeft 10179 || action == R.id.accessibilityActionScrollDown 10180 || action == R.id.accessibilityActionScrollRight)) { 10181 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 10182 return true; 10183 } 10184 } 10185 10186 switch (action) { 10187 case AccessibilityNodeInfo.ACTION_CLICK: { 10188 if (isClickable()) { 10189 performClick(); 10190 return true; 10191 } 10192 } break; 10193 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 10194 if (isLongClickable()) { 10195 performLongClick(); 10196 return true; 10197 } 10198 } break; 10199 case AccessibilityNodeInfo.ACTION_FOCUS: { 10200 if (!hasFocus()) { 10201 // Get out of touch mode since accessibility 10202 // wants to move focus around. 10203 getViewRootImpl().ensureTouchMode(false); 10204 return requestFocus(); 10205 } 10206 } break; 10207 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 10208 if (hasFocus()) { 10209 clearFocus(); 10210 return !isFocused(); 10211 } 10212 } break; 10213 case AccessibilityNodeInfo.ACTION_SELECT: { 10214 if (!isSelected()) { 10215 setSelected(true); 10216 return isSelected(); 10217 } 10218 } break; 10219 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 10220 if (isSelected()) { 10221 setSelected(false); 10222 return !isSelected(); 10223 } 10224 } break; 10225 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 10226 if (!isAccessibilityFocused()) { 10227 return requestAccessibilityFocus(); 10228 } 10229 } break; 10230 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 10231 if (isAccessibilityFocused()) { 10232 clearAccessibilityFocus(); 10233 return true; 10234 } 10235 } break; 10236 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 10237 if (arguments != null) { 10238 final int granularity = arguments.getInt( 10239 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10240 final boolean extendSelection = arguments.getBoolean( 10241 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10242 return traverseAtGranularity(granularity, true, extendSelection); 10243 } 10244 } break; 10245 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 10246 if (arguments != null) { 10247 final int granularity = arguments.getInt( 10248 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10249 final boolean extendSelection = arguments.getBoolean( 10250 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10251 return traverseAtGranularity(granularity, false, extendSelection); 10252 } 10253 } break; 10254 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 10255 CharSequence text = getIterableTextForAccessibility(); 10256 if (text == null) { 10257 return false; 10258 } 10259 final int start = (arguments != null) ? arguments.getInt( 10260 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 10261 final int end = (arguments != null) ? arguments.getInt( 10262 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 10263 // Only cursor position can be specified (selection length == 0) 10264 if ((getAccessibilitySelectionStart() != start 10265 || getAccessibilitySelectionEnd() != end) 10266 && (start == end)) { 10267 setAccessibilitySelection(start, end); 10268 notifyViewAccessibilityStateChangedIfNeeded( 10269 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10270 return true; 10271 } 10272 } break; 10273 case R.id.accessibilityActionShowOnScreen: { 10274 if (mAttachInfo != null) { 10275 final Rect r = mAttachInfo.mTmpInvalRect; 10276 getDrawingRect(r); 10277 return requestRectangleOnScreen(r, true); 10278 } 10279 } break; 10280 case R.id.accessibilityActionContextClick: { 10281 if (isContextClickable()) { 10282 performContextClick(); 10283 return true; 10284 } 10285 } break; 10286 } 10287 return false; 10288 } 10289 10290 private boolean traverseAtGranularity(int granularity, boolean forward, 10291 boolean extendSelection) { 10292 CharSequence text = getIterableTextForAccessibility(); 10293 if (text == null || text.length() == 0) { 10294 return false; 10295 } 10296 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 10297 if (iterator == null) { 10298 return false; 10299 } 10300 int current = getAccessibilitySelectionEnd(); 10301 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10302 current = forward ? 0 : text.length(); 10303 } 10304 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 10305 if (range == null) { 10306 return false; 10307 } 10308 final int segmentStart = range[0]; 10309 final int segmentEnd = range[1]; 10310 int selectionStart; 10311 int selectionEnd; 10312 if (extendSelection && isAccessibilitySelectionExtendable()) { 10313 selectionStart = getAccessibilitySelectionStart(); 10314 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10315 selectionStart = forward ? segmentStart : segmentEnd; 10316 } 10317 selectionEnd = forward ? segmentEnd : segmentStart; 10318 } else { 10319 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 10320 } 10321 setAccessibilitySelection(selectionStart, selectionEnd); 10322 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 10323 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 10324 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 10325 return true; 10326 } 10327 10328 /** 10329 * Gets the text reported for accessibility purposes. 10330 * 10331 * @return The accessibility text. 10332 * 10333 * @hide 10334 */ 10335 public CharSequence getIterableTextForAccessibility() { 10336 return getContentDescription(); 10337 } 10338 10339 /** 10340 * Gets whether accessibility selection can be extended. 10341 * 10342 * @return If selection is extensible. 10343 * 10344 * @hide 10345 */ 10346 public boolean isAccessibilitySelectionExtendable() { 10347 return false; 10348 } 10349 10350 /** 10351 * @hide 10352 */ 10353 public int getAccessibilitySelectionStart() { 10354 return mAccessibilityCursorPosition; 10355 } 10356 10357 /** 10358 * @hide 10359 */ 10360 public int getAccessibilitySelectionEnd() { 10361 return getAccessibilitySelectionStart(); 10362 } 10363 10364 /** 10365 * @hide 10366 */ 10367 public void setAccessibilitySelection(int start, int end) { 10368 if (start == end && end == mAccessibilityCursorPosition) { 10369 return; 10370 } 10371 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 10372 mAccessibilityCursorPosition = start; 10373 } else { 10374 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 10375 } 10376 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 10377 } 10378 10379 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 10380 int fromIndex, int toIndex) { 10381 if (mParent == null) { 10382 return; 10383 } 10384 AccessibilityEvent event = AccessibilityEvent.obtain( 10385 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 10386 onInitializeAccessibilityEvent(event); 10387 onPopulateAccessibilityEvent(event); 10388 event.setFromIndex(fromIndex); 10389 event.setToIndex(toIndex); 10390 event.setAction(action); 10391 event.setMovementGranularity(granularity); 10392 mParent.requestSendAccessibilityEvent(this, event); 10393 } 10394 10395 /** 10396 * @hide 10397 */ 10398 public TextSegmentIterator getIteratorForGranularity(int granularity) { 10399 switch (granularity) { 10400 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 10401 CharSequence text = getIterableTextForAccessibility(); 10402 if (text != null && text.length() > 0) { 10403 CharacterTextSegmentIterator iterator = 10404 CharacterTextSegmentIterator.getInstance( 10405 mContext.getResources().getConfiguration().locale); 10406 iterator.initialize(text.toString()); 10407 return iterator; 10408 } 10409 } break; 10410 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 10411 CharSequence text = getIterableTextForAccessibility(); 10412 if (text != null && text.length() > 0) { 10413 WordTextSegmentIterator iterator = 10414 WordTextSegmentIterator.getInstance( 10415 mContext.getResources().getConfiguration().locale); 10416 iterator.initialize(text.toString()); 10417 return iterator; 10418 } 10419 } break; 10420 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 10421 CharSequence text = getIterableTextForAccessibility(); 10422 if (text != null && text.length() > 0) { 10423 ParagraphTextSegmentIterator iterator = 10424 ParagraphTextSegmentIterator.getInstance(); 10425 iterator.initialize(text.toString()); 10426 return iterator; 10427 } 10428 } break; 10429 } 10430 return null; 10431 } 10432 10433 /** 10434 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 10435 * and {@link #onFinishTemporaryDetach()}. 10436 * 10437 * <p>This method always returns {@code true} when called directly or indirectly from 10438 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 10439 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 10440 * <ul> 10441 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 10442 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 10443 * </ul> 10444 * </p> 10445 * 10446 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 10447 * and {@link #onFinishTemporaryDetach()}. 10448 */ 10449 public final boolean isTemporarilyDetached() { 10450 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 10451 } 10452 10453 /** 10454 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 10455 * a container View. 10456 */ 10457 @CallSuper 10458 public void dispatchStartTemporaryDetach() { 10459 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 10460 onStartTemporaryDetach(); 10461 } 10462 10463 /** 10464 * This is called when a container is going to temporarily detach a child, with 10465 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 10466 * It will either be followed by {@link #onFinishTemporaryDetach()} or 10467 * {@link #onDetachedFromWindow()} when the container is done. 10468 */ 10469 public void onStartTemporaryDetach() { 10470 removeUnsetPressCallback(); 10471 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 10472 } 10473 10474 /** 10475 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 10476 * a container View. 10477 */ 10478 @CallSuper 10479 public void dispatchFinishTemporaryDetach() { 10480 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 10481 onFinishTemporaryDetach(); 10482 if (hasWindowFocus() && hasFocus()) { 10483 InputMethodManager.getInstance().focusIn(this); 10484 } 10485 } 10486 10487 /** 10488 * Called after {@link #onStartTemporaryDetach} when the container is done 10489 * changing the view. 10490 */ 10491 public void onFinishTemporaryDetach() { 10492 } 10493 10494 /** 10495 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 10496 * for this view's window. Returns null if the view is not currently attached 10497 * to the window. Normally you will not need to use this directly, but 10498 * just use the standard high-level event callbacks like 10499 * {@link #onKeyDown(int, KeyEvent)}. 10500 */ 10501 public KeyEvent.DispatcherState getKeyDispatcherState() { 10502 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 10503 } 10504 10505 /** 10506 * Dispatch a key event before it is processed by any input method 10507 * associated with the view hierarchy. This can be used to intercept 10508 * key events in special situations before the IME consumes them; a 10509 * typical example would be handling the BACK key to update the application's 10510 * UI instead of allowing the IME to see it and close itself. 10511 * 10512 * @param event The key event to be dispatched. 10513 * @return True if the event was handled, false otherwise. 10514 */ 10515 public boolean dispatchKeyEventPreIme(KeyEvent event) { 10516 return onKeyPreIme(event.getKeyCode(), event); 10517 } 10518 10519 /** 10520 * Dispatch a key event to the next view on the focus path. This path runs 10521 * from the top of the view tree down to the currently focused view. If this 10522 * view has focus, it will dispatch to itself. Otherwise it will dispatch 10523 * the next node down the focus path. This method also fires any key 10524 * listeners. 10525 * 10526 * @param event The key event to be dispatched. 10527 * @return True if the event was handled, false otherwise. 10528 */ 10529 public boolean dispatchKeyEvent(KeyEvent event) { 10530 if (mInputEventConsistencyVerifier != null) { 10531 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 10532 } 10533 10534 // Give any attached key listener a first crack at the event. 10535 //noinspection SimplifiableIfStatement 10536 ListenerInfo li = mListenerInfo; 10537 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 10538 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 10539 return true; 10540 } 10541 10542 if (event.dispatch(this, mAttachInfo != null 10543 ? mAttachInfo.mKeyDispatchState : null, this)) { 10544 return true; 10545 } 10546 10547 if (mInputEventConsistencyVerifier != null) { 10548 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10549 } 10550 return false; 10551 } 10552 10553 /** 10554 * Dispatches a key shortcut event. 10555 * 10556 * @param event The key event to be dispatched. 10557 * @return True if the event was handled by the view, false otherwise. 10558 */ 10559 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 10560 return onKeyShortcut(event.getKeyCode(), event); 10561 } 10562 10563 /** 10564 * Pass the touch screen motion event down to the target view, or this 10565 * view if it is the target. 10566 * 10567 * @param event The motion event to be dispatched. 10568 * @return True if the event was handled by the view, false otherwise. 10569 */ 10570 public boolean dispatchTouchEvent(MotionEvent event) { 10571 // If the event should be handled by accessibility focus first. 10572 if (event.isTargetAccessibilityFocus()) { 10573 // We don't have focus or no virtual descendant has it, do not handle the event. 10574 if (!isAccessibilityFocusedViewOrHost()) { 10575 return false; 10576 } 10577 // We have focus and got the event, then use normal event dispatch. 10578 event.setTargetAccessibilityFocus(false); 10579 } 10580 10581 boolean result = false; 10582 10583 if (mInputEventConsistencyVerifier != null) { 10584 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 10585 } 10586 10587 final int actionMasked = event.getActionMasked(); 10588 if (actionMasked == MotionEvent.ACTION_DOWN) { 10589 // Defensive cleanup for new gesture 10590 stopNestedScroll(); 10591 } 10592 10593 if (onFilterTouchEventForSecurity(event)) { 10594 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 10595 result = true; 10596 } 10597 //noinspection SimplifiableIfStatement 10598 ListenerInfo li = mListenerInfo; 10599 if (li != null && li.mOnTouchListener != null 10600 && (mViewFlags & ENABLED_MASK) == ENABLED 10601 && li.mOnTouchListener.onTouch(this, event)) { 10602 result = true; 10603 } 10604 10605 if (!result && onTouchEvent(event)) { 10606 result = true; 10607 } 10608 } 10609 10610 if (!result && mInputEventConsistencyVerifier != null) { 10611 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10612 } 10613 10614 // Clean up after nested scrolls if this is the end of a gesture; 10615 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 10616 // of the gesture. 10617 if (actionMasked == MotionEvent.ACTION_UP || 10618 actionMasked == MotionEvent.ACTION_CANCEL || 10619 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 10620 stopNestedScroll(); 10621 } 10622 10623 return result; 10624 } 10625 10626 boolean isAccessibilityFocusedViewOrHost() { 10627 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 10628 .getAccessibilityFocusedHost() == this); 10629 } 10630 10631 /** 10632 * Filter the touch event to apply security policies. 10633 * 10634 * @param event The motion event to be filtered. 10635 * @return True if the event should be dispatched, false if the event should be dropped. 10636 * 10637 * @see #getFilterTouchesWhenObscured 10638 */ 10639 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 10640 //noinspection RedundantIfStatement 10641 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 10642 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 10643 // Window is obscured, drop this touch. 10644 return false; 10645 } 10646 return true; 10647 } 10648 10649 /** 10650 * Pass a trackball motion event down to the focused view. 10651 * 10652 * @param event The motion event to be dispatched. 10653 * @return True if the event was handled by the view, false otherwise. 10654 */ 10655 public boolean dispatchTrackballEvent(MotionEvent event) { 10656 if (mInputEventConsistencyVerifier != null) { 10657 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 10658 } 10659 10660 return onTrackballEvent(event); 10661 } 10662 10663 /** 10664 * Dispatch a generic motion event. 10665 * <p> 10666 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 10667 * are delivered to the view under the pointer. All other generic motion events are 10668 * delivered to the focused view. Hover events are handled specially and are delivered 10669 * to {@link #onHoverEvent(MotionEvent)}. 10670 * </p> 10671 * 10672 * @param event The motion event to be dispatched. 10673 * @return True if the event was handled by the view, false otherwise. 10674 */ 10675 public boolean dispatchGenericMotionEvent(MotionEvent event) { 10676 if (mInputEventConsistencyVerifier != null) { 10677 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 10678 } 10679 10680 final int source = event.getSource(); 10681 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 10682 final int action = event.getAction(); 10683 if (action == MotionEvent.ACTION_HOVER_ENTER 10684 || action == MotionEvent.ACTION_HOVER_MOVE 10685 || action == MotionEvent.ACTION_HOVER_EXIT) { 10686 if (dispatchHoverEvent(event)) { 10687 return true; 10688 } 10689 } else if (dispatchGenericPointerEvent(event)) { 10690 return true; 10691 } 10692 } else if (dispatchGenericFocusedEvent(event)) { 10693 return true; 10694 } 10695 10696 if (dispatchGenericMotionEventInternal(event)) { 10697 return true; 10698 } 10699 10700 if (mInputEventConsistencyVerifier != null) { 10701 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10702 } 10703 return false; 10704 } 10705 10706 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 10707 //noinspection SimplifiableIfStatement 10708 ListenerInfo li = mListenerInfo; 10709 if (li != null && li.mOnGenericMotionListener != null 10710 && (mViewFlags & ENABLED_MASK) == ENABLED 10711 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 10712 return true; 10713 } 10714 10715 if (onGenericMotionEvent(event)) { 10716 return true; 10717 } 10718 10719 final int actionButton = event.getActionButton(); 10720 switch (event.getActionMasked()) { 10721 case MotionEvent.ACTION_BUTTON_PRESS: 10722 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 10723 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10724 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10725 if (performContextClick(event.getX(), event.getY())) { 10726 mInContextButtonPress = true; 10727 setPressed(true, event.getX(), event.getY()); 10728 removeTapCallback(); 10729 removeLongPressCallback(); 10730 return true; 10731 } 10732 } 10733 break; 10734 10735 case MotionEvent.ACTION_BUTTON_RELEASE: 10736 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10737 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10738 mInContextButtonPress = false; 10739 mIgnoreNextUpEvent = true; 10740 } 10741 break; 10742 } 10743 10744 if (mInputEventConsistencyVerifier != null) { 10745 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10746 } 10747 return false; 10748 } 10749 10750 /** 10751 * Dispatch a hover event. 10752 * <p> 10753 * Do not call this method directly. 10754 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10755 * </p> 10756 * 10757 * @param event The motion event to be dispatched. 10758 * @return True if the event was handled by the view, false otherwise. 10759 */ 10760 protected boolean dispatchHoverEvent(MotionEvent event) { 10761 ListenerInfo li = mListenerInfo; 10762 //noinspection SimplifiableIfStatement 10763 if (li != null && li.mOnHoverListener != null 10764 && (mViewFlags & ENABLED_MASK) == ENABLED 10765 && li.mOnHoverListener.onHover(this, event)) { 10766 return true; 10767 } 10768 10769 return onHoverEvent(event); 10770 } 10771 10772 /** 10773 * Returns true if the view has a child to which it has recently sent 10774 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 10775 * it does not have a hovered child, then it must be the innermost hovered view. 10776 * @hide 10777 */ 10778 protected boolean hasHoveredChild() { 10779 return false; 10780 } 10781 10782 /** 10783 * Dispatch a generic motion event to the view under the first pointer. 10784 * <p> 10785 * Do not call this method directly. 10786 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10787 * </p> 10788 * 10789 * @param event The motion event to be dispatched. 10790 * @return True if the event was handled by the view, false otherwise. 10791 */ 10792 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 10793 return false; 10794 } 10795 10796 /** 10797 * Dispatch a generic motion event to the currently focused view. 10798 * <p> 10799 * Do not call this method directly. 10800 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10801 * </p> 10802 * 10803 * @param event The motion event to be dispatched. 10804 * @return True if the event was handled by the view, false otherwise. 10805 */ 10806 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 10807 return false; 10808 } 10809 10810 /** 10811 * Dispatch a pointer event. 10812 * <p> 10813 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 10814 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 10815 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 10816 * and should not be expected to handle other pointing device features. 10817 * </p> 10818 * 10819 * @param event The motion event to be dispatched. 10820 * @return True if the event was handled by the view, false otherwise. 10821 * @hide 10822 */ 10823 public final boolean dispatchPointerEvent(MotionEvent event) { 10824 if (event.isTouchEvent()) { 10825 return dispatchTouchEvent(event); 10826 } else { 10827 return dispatchGenericMotionEvent(event); 10828 } 10829 } 10830 10831 /** 10832 * Called when the window containing this view gains or loses window focus. 10833 * ViewGroups should override to route to their children. 10834 * 10835 * @param hasFocus True if the window containing this view now has focus, 10836 * false otherwise. 10837 */ 10838 public void dispatchWindowFocusChanged(boolean hasFocus) { 10839 onWindowFocusChanged(hasFocus); 10840 } 10841 10842 /** 10843 * Called when the window containing this view gains or loses focus. Note 10844 * that this is separate from view focus: to receive key events, both 10845 * your view and its window must have focus. If a window is displayed 10846 * on top of yours that takes input focus, then your own window will lose 10847 * focus but the view focus will remain unchanged. 10848 * 10849 * @param hasWindowFocus True if the window containing this view now has 10850 * focus, false otherwise. 10851 */ 10852 public void onWindowFocusChanged(boolean hasWindowFocus) { 10853 InputMethodManager imm = InputMethodManager.peekInstance(); 10854 if (!hasWindowFocus) { 10855 if (isPressed()) { 10856 setPressed(false); 10857 } 10858 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 10859 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10860 imm.focusOut(this); 10861 } 10862 removeLongPressCallback(); 10863 removeTapCallback(); 10864 onFocusLost(); 10865 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10866 imm.focusIn(this); 10867 } 10868 refreshDrawableState(); 10869 } 10870 10871 /** 10872 * Returns true if this view is in a window that currently has window focus. 10873 * Note that this is not the same as the view itself having focus. 10874 * 10875 * @return True if this view is in a window that currently has window focus. 10876 */ 10877 public boolean hasWindowFocus() { 10878 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 10879 } 10880 10881 /** 10882 * Dispatch a view visibility change down the view hierarchy. 10883 * ViewGroups should override to route to their children. 10884 * @param changedView The view whose visibility changed. Could be 'this' or 10885 * an ancestor view. 10886 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 10887 * {@link #INVISIBLE} or {@link #GONE}. 10888 */ 10889 protected void dispatchVisibilityChanged(@NonNull View changedView, 10890 @Visibility int visibility) { 10891 onVisibilityChanged(changedView, visibility); 10892 } 10893 10894 /** 10895 * Called when the visibility of the view or an ancestor of the view has 10896 * changed. 10897 * 10898 * @param changedView The view whose visibility changed. May be 10899 * {@code this} or an ancestor view. 10900 * @param visibility The new visibility, one of {@link #VISIBLE}, 10901 * {@link #INVISIBLE} or {@link #GONE}. 10902 */ 10903 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 10904 } 10905 10906 /** 10907 * Dispatch a hint about whether this view is displayed. For instance, when 10908 * a View moves out of the screen, it might receives a display hint indicating 10909 * the view is not displayed. Applications should not <em>rely</em> on this hint 10910 * as there is no guarantee that they will receive one. 10911 * 10912 * @param hint A hint about whether or not this view is displayed: 10913 * {@link #VISIBLE} or {@link #INVISIBLE}. 10914 */ 10915 public void dispatchDisplayHint(@Visibility int hint) { 10916 onDisplayHint(hint); 10917 } 10918 10919 /** 10920 * Gives this view a hint about whether is displayed or not. For instance, when 10921 * a View moves out of the screen, it might receives a display hint indicating 10922 * the view is not displayed. Applications should not <em>rely</em> on this hint 10923 * as there is no guarantee that they will receive one. 10924 * 10925 * @param hint A hint about whether or not this view is displayed: 10926 * {@link #VISIBLE} or {@link #INVISIBLE}. 10927 */ 10928 protected void onDisplayHint(@Visibility int hint) { 10929 } 10930 10931 /** 10932 * Dispatch a window visibility change down the view hierarchy. 10933 * ViewGroups should override to route to their children. 10934 * 10935 * @param visibility The new visibility of the window. 10936 * 10937 * @see #onWindowVisibilityChanged(int) 10938 */ 10939 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 10940 onWindowVisibilityChanged(visibility); 10941 } 10942 10943 /** 10944 * Called when the window containing has change its visibility 10945 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 10946 * that this tells you whether or not your window is being made visible 10947 * to the window manager; this does <em>not</em> tell you whether or not 10948 * your window is obscured by other windows on the screen, even if it 10949 * is itself visible. 10950 * 10951 * @param visibility The new visibility of the window. 10952 */ 10953 protected void onWindowVisibilityChanged(@Visibility int visibility) { 10954 if (visibility == VISIBLE) { 10955 initialAwakenScrollBars(); 10956 } 10957 } 10958 10959 /** 10960 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 10961 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 10962 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 10963 * 10964 * @param isVisible true if this view's visibility to the user is uninterrupted by its 10965 * ancestors or by window visibility 10966 * @return true if this view is visible to the user, not counting clipping or overlapping 10967 */ 10968 boolean dispatchVisibilityAggregated(boolean isVisible) { 10969 final boolean thisVisible = getVisibility() == VISIBLE; 10970 // If we're not visible but something is telling us we are, ignore it. 10971 if (thisVisible || !isVisible) { 10972 onVisibilityAggregated(isVisible); 10973 } 10974 return thisVisible && isVisible; 10975 } 10976 10977 /** 10978 * Called when the user-visibility of this View is potentially affected by a change 10979 * to this view itself, an ancestor view or the window this view is attached to. 10980 * 10981 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 10982 * and this view's window is also visible 10983 */ 10984 @CallSuper 10985 public void onVisibilityAggregated(boolean isVisible) { 10986 if (isVisible && mAttachInfo != null) { 10987 initialAwakenScrollBars(); 10988 } 10989 10990 final Drawable dr = mBackground; 10991 if (dr != null && isVisible != dr.isVisible()) { 10992 dr.setVisible(isVisible, false); 10993 } 10994 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 10995 if (fg != null && isVisible != fg.isVisible()) { 10996 fg.setVisible(isVisible, false); 10997 } 10998 } 10999 11000 /** 11001 * Returns the current visibility of the window this view is attached to 11002 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 11003 * 11004 * @return Returns the current visibility of the view's window. 11005 */ 11006 @Visibility 11007 public int getWindowVisibility() { 11008 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 11009 } 11010 11011 /** 11012 * Retrieve the overall visible display size in which the window this view is 11013 * attached to has been positioned in. This takes into account screen 11014 * decorations above the window, for both cases where the window itself 11015 * is being position inside of them or the window is being placed under 11016 * then and covered insets are used for the window to position its content 11017 * inside. In effect, this tells you the available area where content can 11018 * be placed and remain visible to users. 11019 * 11020 * <p>This function requires an IPC back to the window manager to retrieve 11021 * the requested information, so should not be used in performance critical 11022 * code like drawing. 11023 * 11024 * @param outRect Filled in with the visible display frame. If the view 11025 * is not attached to a window, this is simply the raw display size. 11026 */ 11027 public void getWindowVisibleDisplayFrame(Rect outRect) { 11028 if (mAttachInfo != null) { 11029 try { 11030 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 11031 } catch (RemoteException e) { 11032 return; 11033 } 11034 // XXX This is really broken, and probably all needs to be done 11035 // in the window manager, and we need to know more about whether 11036 // we want the area behind or in front of the IME. 11037 final Rect insets = mAttachInfo.mVisibleInsets; 11038 outRect.left += insets.left; 11039 outRect.top += insets.top; 11040 outRect.right -= insets.right; 11041 outRect.bottom -= insets.bottom; 11042 return; 11043 } 11044 // The view is not attached to a display so we don't have a context. 11045 // Make a best guess about the display size. 11046 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 11047 d.getRectSize(outRect); 11048 } 11049 11050 /** 11051 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 11052 * is currently in without any insets. 11053 * 11054 * @hide 11055 */ 11056 public void getWindowDisplayFrame(Rect outRect) { 11057 if (mAttachInfo != null) { 11058 try { 11059 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 11060 } catch (RemoteException e) { 11061 return; 11062 } 11063 return; 11064 } 11065 // The view is not attached to a display so we don't have a context. 11066 // Make a best guess about the display size. 11067 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 11068 d.getRectSize(outRect); 11069 } 11070 11071 /** 11072 * Dispatch a notification about a resource configuration change down 11073 * the view hierarchy. 11074 * ViewGroups should override to route to their children. 11075 * 11076 * @param newConfig The new resource configuration. 11077 * 11078 * @see #onConfigurationChanged(android.content.res.Configuration) 11079 */ 11080 public void dispatchConfigurationChanged(Configuration newConfig) { 11081 onConfigurationChanged(newConfig); 11082 } 11083 11084 /** 11085 * Called when the current configuration of the resources being used 11086 * by the application have changed. You can use this to decide when 11087 * to reload resources that can changed based on orientation and other 11088 * configuration characteristics. You only need to use this if you are 11089 * not relying on the normal {@link android.app.Activity} mechanism of 11090 * recreating the activity instance upon a configuration change. 11091 * 11092 * @param newConfig The new resource configuration. 11093 */ 11094 protected void onConfigurationChanged(Configuration newConfig) { 11095 } 11096 11097 /** 11098 * Private function to aggregate all per-view attributes in to the view 11099 * root. 11100 */ 11101 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 11102 performCollectViewAttributes(attachInfo, visibility); 11103 } 11104 11105 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 11106 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 11107 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 11108 attachInfo.mKeepScreenOn = true; 11109 } 11110 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 11111 ListenerInfo li = mListenerInfo; 11112 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 11113 attachInfo.mHasSystemUiListeners = true; 11114 } 11115 } 11116 } 11117 11118 void needGlobalAttributesUpdate(boolean force) { 11119 final AttachInfo ai = mAttachInfo; 11120 if (ai != null && !ai.mRecomputeGlobalAttributes) { 11121 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 11122 || ai.mHasSystemUiListeners) { 11123 ai.mRecomputeGlobalAttributes = true; 11124 } 11125 } 11126 } 11127 11128 /** 11129 * Returns whether the device is currently in touch mode. Touch mode is entered 11130 * once the user begins interacting with the device by touch, and affects various 11131 * things like whether focus is always visible to the user. 11132 * 11133 * @return Whether the device is in touch mode. 11134 */ 11135 @ViewDebug.ExportedProperty 11136 public boolean isInTouchMode() { 11137 if (mAttachInfo != null) { 11138 return mAttachInfo.mInTouchMode; 11139 } else { 11140 return ViewRootImpl.isInTouchMode(); 11141 } 11142 } 11143 11144 /** 11145 * Returns the context the view is running in, through which it can 11146 * access the current theme, resources, etc. 11147 * 11148 * @return The view's Context. 11149 */ 11150 @ViewDebug.CapturedViewProperty 11151 public final Context getContext() { 11152 return mContext; 11153 } 11154 11155 /** 11156 * Handle a key event before it is processed by any input method 11157 * associated with the view hierarchy. This can be used to intercept 11158 * key events in special situations before the IME consumes them; a 11159 * typical example would be handling the BACK key to update the application's 11160 * UI instead of allowing the IME to see it and close itself. 11161 * 11162 * @param keyCode The value in event.getKeyCode(). 11163 * @param event Description of the key event. 11164 * @return If you handled the event, return true. If you want to allow the 11165 * event to be handled by the next receiver, return false. 11166 */ 11167 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 11168 return false; 11169 } 11170 11171 /** 11172 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 11173 * KeyEvent.Callback.onKeyDown()}: perform press of the view 11174 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 11175 * is released, if the view is enabled and clickable. 11176 * <p> 11177 * Key presses in software keyboards will generally NOT trigger this 11178 * listener, although some may elect to do so in some situations. Do not 11179 * rely on this to catch software key presses. 11180 * 11181 * @param keyCode a key code that represents the button pressed, from 11182 * {@link android.view.KeyEvent} 11183 * @param event the KeyEvent object that defines the button action 11184 */ 11185 public boolean onKeyDown(int keyCode, KeyEvent event) { 11186 if (KeyEvent.isConfirmKey(keyCode)) { 11187 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11188 return true; 11189 } 11190 11191 if (event.getRepeatCount() == 0) { 11192 // Long clickable items don't necessarily have to be clickable. 11193 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 11194 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 11195 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 11196 // For the purposes of menu anchoring and drawable hotspots, 11197 // key events are considered to be at the center of the view. 11198 final float x = getWidth() / 2f; 11199 final float y = getHeight() / 2f; 11200 if (clickable) { 11201 setPressed(true, x, y); 11202 } 11203 checkForLongClick(0, x, y); 11204 return true; 11205 } 11206 } 11207 } 11208 11209 return false; 11210 } 11211 11212 /** 11213 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 11214 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 11215 * the event). 11216 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11217 * although some may elect to do so in some situations. Do not rely on this to 11218 * catch software key presses. 11219 */ 11220 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 11221 return false; 11222 } 11223 11224 /** 11225 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 11226 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 11227 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 11228 * or {@link KeyEvent#KEYCODE_SPACE} is released. 11229 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11230 * although some may elect to do so in some situations. Do not rely on this to 11231 * catch software key presses. 11232 * 11233 * @param keyCode A key code that represents the button pressed, from 11234 * {@link android.view.KeyEvent}. 11235 * @param event The KeyEvent object that defines the button action. 11236 */ 11237 public boolean onKeyUp(int keyCode, KeyEvent event) { 11238 if (KeyEvent.isConfirmKey(keyCode)) { 11239 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11240 return true; 11241 } 11242 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 11243 setPressed(false); 11244 11245 if (!mHasPerformedLongPress) { 11246 // This is a tap, so remove the longpress check 11247 removeLongPressCallback(); 11248 return performClick(); 11249 } 11250 } 11251 } 11252 return false; 11253 } 11254 11255 /** 11256 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 11257 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 11258 * the event). 11259 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11260 * although some may elect to do so in some situations. Do not rely on this to 11261 * catch software key presses. 11262 * 11263 * @param keyCode A key code that represents the button pressed, from 11264 * {@link android.view.KeyEvent}. 11265 * @param repeatCount The number of times the action was made. 11266 * @param event The KeyEvent object that defines the button action. 11267 */ 11268 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 11269 return false; 11270 } 11271 11272 /** 11273 * Called on the focused view when a key shortcut event is not handled. 11274 * Override this method to implement local key shortcuts for the View. 11275 * Key shortcuts can also be implemented by setting the 11276 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 11277 * 11278 * @param keyCode The value in event.getKeyCode(). 11279 * @param event Description of the key event. 11280 * @return If you handled the event, return true. If you want to allow the 11281 * event to be handled by the next receiver, return false. 11282 */ 11283 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 11284 return false; 11285 } 11286 11287 /** 11288 * Check whether the called view is a text editor, in which case it 11289 * would make sense to automatically display a soft input window for 11290 * it. Subclasses should override this if they implement 11291 * {@link #onCreateInputConnection(EditorInfo)} to return true if 11292 * a call on that method would return a non-null InputConnection, and 11293 * they are really a first-class editor that the user would normally 11294 * start typing on when the go into a window containing your view. 11295 * 11296 * <p>The default implementation always returns false. This does 11297 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 11298 * will not be called or the user can not otherwise perform edits on your 11299 * view; it is just a hint to the system that this is not the primary 11300 * purpose of this view. 11301 * 11302 * @return Returns true if this view is a text editor, else false. 11303 */ 11304 public boolean onCheckIsTextEditor() { 11305 return false; 11306 } 11307 11308 /** 11309 * Create a new InputConnection for an InputMethod to interact 11310 * with the view. The default implementation returns null, since it doesn't 11311 * support input methods. You can override this to implement such support. 11312 * This is only needed for views that take focus and text input. 11313 * 11314 * <p>When implementing this, you probably also want to implement 11315 * {@link #onCheckIsTextEditor()} to indicate you will return a 11316 * non-null InputConnection.</p> 11317 * 11318 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 11319 * object correctly and in its entirety, so that the connected IME can rely 11320 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 11321 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 11322 * must be filled in with the correct cursor position for IMEs to work correctly 11323 * with your application.</p> 11324 * 11325 * @param outAttrs Fill in with attribute information about the connection. 11326 */ 11327 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 11328 return null; 11329 } 11330 11331 /** 11332 * Called by the {@link android.view.inputmethod.InputMethodManager} 11333 * when a view who is not the current 11334 * input connection target is trying to make a call on the manager. The 11335 * default implementation returns false; you can override this to return 11336 * true for certain views if you are performing InputConnection proxying 11337 * to them. 11338 * @param view The View that is making the InputMethodManager call. 11339 * @return Return true to allow the call, false to reject. 11340 */ 11341 public boolean checkInputConnectionProxy(View view) { 11342 return false; 11343 } 11344 11345 /** 11346 * Show the context menu for this view. It is not safe to hold on to the 11347 * menu after returning from this method. 11348 * 11349 * You should normally not overload this method. Overload 11350 * {@link #onCreateContextMenu(ContextMenu)} or define an 11351 * {@link OnCreateContextMenuListener} to add items to the context menu. 11352 * 11353 * @param menu The context menu to populate 11354 */ 11355 public void createContextMenu(ContextMenu menu) { 11356 ContextMenuInfo menuInfo = getContextMenuInfo(); 11357 11358 // Sets the current menu info so all items added to menu will have 11359 // my extra info set. 11360 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 11361 11362 onCreateContextMenu(menu); 11363 ListenerInfo li = mListenerInfo; 11364 if (li != null && li.mOnCreateContextMenuListener != null) { 11365 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 11366 } 11367 11368 // Clear the extra information so subsequent items that aren't mine don't 11369 // have my extra info. 11370 ((MenuBuilder)menu).setCurrentMenuInfo(null); 11371 11372 if (mParent != null) { 11373 mParent.createContextMenu(menu); 11374 } 11375 } 11376 11377 /** 11378 * Views should implement this if they have extra information to associate 11379 * with the context menu. The return result is supplied as a parameter to 11380 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 11381 * callback. 11382 * 11383 * @return Extra information about the item for which the context menu 11384 * should be shown. This information will vary across different 11385 * subclasses of View. 11386 */ 11387 protected ContextMenuInfo getContextMenuInfo() { 11388 return null; 11389 } 11390 11391 /** 11392 * Views should implement this if the view itself is going to add items to 11393 * the context menu. 11394 * 11395 * @param menu the context menu to populate 11396 */ 11397 protected void onCreateContextMenu(ContextMenu menu) { 11398 } 11399 11400 /** 11401 * Implement this method to handle trackball motion events. The 11402 * <em>relative</em> movement of the trackball since the last event 11403 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 11404 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 11405 * that a movement of 1 corresponds to the user pressing one DPAD key (so 11406 * they will often be fractional values, representing the more fine-grained 11407 * movement information available from a trackball). 11408 * 11409 * @param event The motion event. 11410 * @return True if the event was handled, false otherwise. 11411 */ 11412 public boolean onTrackballEvent(MotionEvent event) { 11413 return false; 11414 } 11415 11416 /** 11417 * Implement this method to handle generic motion events. 11418 * <p> 11419 * Generic motion events describe joystick movements, mouse hovers, track pad 11420 * touches, scroll wheel movements and other input events. The 11421 * {@link MotionEvent#getSource() source} of the motion event specifies 11422 * the class of input that was received. Implementations of this method 11423 * must examine the bits in the source before processing the event. 11424 * The following code example shows how this is done. 11425 * </p><p> 11426 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11427 * are delivered to the view under the pointer. All other generic motion events are 11428 * delivered to the focused view. 11429 * </p> 11430 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 11431 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 11432 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 11433 * // process the joystick movement... 11434 * return true; 11435 * } 11436 * } 11437 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 11438 * switch (event.getAction()) { 11439 * case MotionEvent.ACTION_HOVER_MOVE: 11440 * // process the mouse hover movement... 11441 * return true; 11442 * case MotionEvent.ACTION_SCROLL: 11443 * // process the scroll wheel movement... 11444 * return true; 11445 * } 11446 * } 11447 * return super.onGenericMotionEvent(event); 11448 * }</pre> 11449 * 11450 * @param event The generic motion event being processed. 11451 * @return True if the event was handled, false otherwise. 11452 */ 11453 public boolean onGenericMotionEvent(MotionEvent event) { 11454 return false; 11455 } 11456 11457 /** 11458 * Implement this method to handle hover events. 11459 * <p> 11460 * This method is called whenever a pointer is hovering into, over, or out of the 11461 * bounds of a view and the view is not currently being touched. 11462 * Hover events are represented as pointer events with action 11463 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 11464 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 11465 * </p> 11466 * <ul> 11467 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 11468 * when the pointer enters the bounds of the view.</li> 11469 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 11470 * when the pointer has already entered the bounds of the view and has moved.</li> 11471 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 11472 * when the pointer has exited the bounds of the view or when the pointer is 11473 * about to go down due to a button click, tap, or similar user action that 11474 * causes the view to be touched.</li> 11475 * </ul> 11476 * <p> 11477 * The view should implement this method to return true to indicate that it is 11478 * handling the hover event, such as by changing its drawable state. 11479 * </p><p> 11480 * The default implementation calls {@link #setHovered} to update the hovered state 11481 * of the view when a hover enter or hover exit event is received, if the view 11482 * is enabled and is clickable. The default implementation also sends hover 11483 * accessibility events. 11484 * </p> 11485 * 11486 * @param event The motion event that describes the hover. 11487 * @return True if the view handled the hover event. 11488 * 11489 * @see #isHovered 11490 * @see #setHovered 11491 * @see #onHoverChanged 11492 */ 11493 public boolean onHoverEvent(MotionEvent event) { 11494 // The root view may receive hover (or touch) events that are outside the bounds of 11495 // the window. This code ensures that we only send accessibility events for 11496 // hovers that are actually within the bounds of the root view. 11497 final int action = event.getActionMasked(); 11498 if (!mSendingHoverAccessibilityEvents) { 11499 if ((action == MotionEvent.ACTION_HOVER_ENTER 11500 || action == MotionEvent.ACTION_HOVER_MOVE) 11501 && !hasHoveredChild() 11502 && pointInView(event.getX(), event.getY())) { 11503 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 11504 mSendingHoverAccessibilityEvents = true; 11505 } 11506 } else { 11507 if (action == MotionEvent.ACTION_HOVER_EXIT 11508 || (action == MotionEvent.ACTION_MOVE 11509 && !pointInView(event.getX(), event.getY()))) { 11510 mSendingHoverAccessibilityEvents = false; 11511 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 11512 } 11513 } 11514 11515 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 11516 && event.isFromSource(InputDevice.SOURCE_MOUSE) 11517 && isOnScrollbar(event.getX(), event.getY())) { 11518 awakenScrollBars(); 11519 } 11520 if (isHoverable()) { 11521 switch (action) { 11522 case MotionEvent.ACTION_HOVER_ENTER: 11523 setHovered(true); 11524 break; 11525 case MotionEvent.ACTION_HOVER_EXIT: 11526 setHovered(false); 11527 break; 11528 } 11529 11530 // Dispatch the event to onGenericMotionEvent before returning true. 11531 // This is to provide compatibility with existing applications that 11532 // handled HOVER_MOVE events in onGenericMotionEvent and that would 11533 // break because of the new default handling for hoverable views 11534 // in onHoverEvent. 11535 // Note that onGenericMotionEvent will be called by default when 11536 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 11537 dispatchGenericMotionEventInternal(event); 11538 // The event was already handled by calling setHovered(), so always 11539 // return true. 11540 return true; 11541 } 11542 11543 return false; 11544 } 11545 11546 /** 11547 * Returns true if the view should handle {@link #onHoverEvent} 11548 * by calling {@link #setHovered} to change its hovered state. 11549 * 11550 * @return True if the view is hoverable. 11551 */ 11552 private boolean isHoverable() { 11553 final int viewFlags = mViewFlags; 11554 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11555 return false; 11556 } 11557 11558 return (viewFlags & CLICKABLE) == CLICKABLE 11559 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 11560 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11561 } 11562 11563 /** 11564 * Returns true if the view is currently hovered. 11565 * 11566 * @return True if the view is currently hovered. 11567 * 11568 * @see #setHovered 11569 * @see #onHoverChanged 11570 */ 11571 @ViewDebug.ExportedProperty 11572 public boolean isHovered() { 11573 return (mPrivateFlags & PFLAG_HOVERED) != 0; 11574 } 11575 11576 /** 11577 * Sets whether the view is currently hovered. 11578 * <p> 11579 * Calling this method also changes the drawable state of the view. This 11580 * enables the view to react to hover by using different drawable resources 11581 * to change its appearance. 11582 * </p><p> 11583 * The {@link #onHoverChanged} method is called when the hovered state changes. 11584 * </p> 11585 * 11586 * @param hovered True if the view is hovered. 11587 * 11588 * @see #isHovered 11589 * @see #onHoverChanged 11590 */ 11591 public void setHovered(boolean hovered) { 11592 if (hovered) { 11593 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 11594 mPrivateFlags |= PFLAG_HOVERED; 11595 refreshDrawableState(); 11596 onHoverChanged(true); 11597 } 11598 } else { 11599 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 11600 mPrivateFlags &= ~PFLAG_HOVERED; 11601 refreshDrawableState(); 11602 onHoverChanged(false); 11603 } 11604 } 11605 } 11606 11607 /** 11608 * Implement this method to handle hover state changes. 11609 * <p> 11610 * This method is called whenever the hover state changes as a result of a 11611 * call to {@link #setHovered}. 11612 * </p> 11613 * 11614 * @param hovered The current hover state, as returned by {@link #isHovered}. 11615 * 11616 * @see #isHovered 11617 * @see #setHovered 11618 */ 11619 public void onHoverChanged(boolean hovered) { 11620 } 11621 11622 /** 11623 * Handles scroll bar dragging by mouse input. 11624 * 11625 * @hide 11626 * @param event The motion event. 11627 * 11628 * @return true if the event was handled as a scroll bar dragging, false otherwise. 11629 */ 11630 protected boolean handleScrollBarDragging(MotionEvent event) { 11631 if (mScrollCache == null) { 11632 return false; 11633 } 11634 final float x = event.getX(); 11635 final float y = event.getY(); 11636 final int action = event.getAction(); 11637 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 11638 && action != MotionEvent.ACTION_DOWN) 11639 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 11640 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 11641 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11642 return false; 11643 } 11644 11645 switch (action) { 11646 case MotionEvent.ACTION_MOVE: 11647 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 11648 return false; 11649 } 11650 if (mScrollCache.mScrollBarDraggingState 11651 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 11652 final Rect bounds = mScrollCache.mScrollBarBounds; 11653 getVerticalScrollBarBounds(bounds); 11654 final int range = computeVerticalScrollRange(); 11655 final int offset = computeVerticalScrollOffset(); 11656 final int extent = computeVerticalScrollExtent(); 11657 11658 final int thumbLength = ScrollBarUtils.getThumbLength( 11659 bounds.height(), bounds.width(), extent, range); 11660 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11661 bounds.height(), thumbLength, extent, range, offset); 11662 11663 final float diff = y - mScrollCache.mScrollBarDraggingPos; 11664 final float maxThumbOffset = bounds.height() - thumbLength; 11665 final float newThumbOffset = 11666 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11667 final int height = getHeight(); 11668 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11669 && height > 0 && extent > 0) { 11670 final int newY = Math.round((range - extent) 11671 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 11672 if (newY != getScrollY()) { 11673 mScrollCache.mScrollBarDraggingPos = y; 11674 setScrollY(newY); 11675 } 11676 } 11677 return true; 11678 } 11679 if (mScrollCache.mScrollBarDraggingState 11680 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 11681 final Rect bounds = mScrollCache.mScrollBarBounds; 11682 getHorizontalScrollBarBounds(bounds); 11683 final int range = computeHorizontalScrollRange(); 11684 final int offset = computeHorizontalScrollOffset(); 11685 final int extent = computeHorizontalScrollExtent(); 11686 11687 final int thumbLength = ScrollBarUtils.getThumbLength( 11688 bounds.width(), bounds.height(), extent, range); 11689 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11690 bounds.width(), thumbLength, extent, range, offset); 11691 11692 final float diff = x - mScrollCache.mScrollBarDraggingPos; 11693 final float maxThumbOffset = bounds.width() - thumbLength; 11694 final float newThumbOffset = 11695 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11696 final int width = getWidth(); 11697 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11698 && width > 0 && extent > 0) { 11699 final int newX = Math.round((range - extent) 11700 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 11701 if (newX != getScrollX()) { 11702 mScrollCache.mScrollBarDraggingPos = x; 11703 setScrollX(newX); 11704 } 11705 } 11706 return true; 11707 } 11708 case MotionEvent.ACTION_DOWN: 11709 if (mScrollCache.state == ScrollabilityCache.OFF) { 11710 return false; 11711 } 11712 if (isOnVerticalScrollbarThumb(x, y)) { 11713 mScrollCache.mScrollBarDraggingState = 11714 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 11715 mScrollCache.mScrollBarDraggingPos = y; 11716 return true; 11717 } 11718 if (isOnHorizontalScrollbarThumb(x, y)) { 11719 mScrollCache.mScrollBarDraggingState = 11720 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 11721 mScrollCache.mScrollBarDraggingPos = x; 11722 return true; 11723 } 11724 } 11725 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11726 return false; 11727 } 11728 11729 /** 11730 * Implement this method to handle touch screen motion events. 11731 * <p> 11732 * If this method is used to detect click actions, it is recommended that 11733 * the actions be performed by implementing and calling 11734 * {@link #performClick()}. This will ensure consistent system behavior, 11735 * including: 11736 * <ul> 11737 * <li>obeying click sound preferences 11738 * <li>dispatching OnClickListener calls 11739 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 11740 * accessibility features are enabled 11741 * </ul> 11742 * 11743 * @param event The motion event. 11744 * @return True if the event was handled, false otherwise. 11745 */ 11746 public boolean onTouchEvent(MotionEvent event) { 11747 final float x = event.getX(); 11748 final float y = event.getY(); 11749 final int viewFlags = mViewFlags; 11750 final int action = event.getAction(); 11751 11752 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 11753 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 11754 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11755 11756 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11757 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 11758 setPressed(false); 11759 } 11760 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11761 // A disabled view that is clickable still consumes the touch 11762 // events, it just doesn't respond to them. 11763 return clickable; 11764 } 11765 if (mTouchDelegate != null) { 11766 if (mTouchDelegate.onTouchEvent(event)) { 11767 return true; 11768 } 11769 } 11770 11771 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 11772 switch (action) { 11773 case MotionEvent.ACTION_UP: 11774 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11775 if ((viewFlags & TOOLTIP) == TOOLTIP) { 11776 handleTooltipUp(); 11777 } 11778 if (!clickable) { 11779 removeTapCallback(); 11780 removeLongPressCallback(); 11781 mInContextButtonPress = false; 11782 mHasPerformedLongPress = false; 11783 mIgnoreNextUpEvent = false; 11784 break; 11785 } 11786 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 11787 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 11788 // take focus if we don't have it already and we should in 11789 // touch mode. 11790 boolean focusTaken = false; 11791 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 11792 focusTaken = requestFocus(); 11793 } 11794 11795 if (prepressed) { 11796 // The button is being released before we actually 11797 // showed it as pressed. Make it show the pressed 11798 // state now (before scheduling the click) to ensure 11799 // the user sees it. 11800 setPressed(true, x, y); 11801 } 11802 11803 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 11804 // This is a tap, so remove the longpress check 11805 removeLongPressCallback(); 11806 11807 // Only perform take click actions if we were in the pressed state 11808 if (!focusTaken) { 11809 // Use a Runnable and post this rather than calling 11810 // performClick directly. This lets other visual state 11811 // of the view update before click actions start. 11812 if (mPerformClick == null) { 11813 mPerformClick = new PerformClick(); 11814 } 11815 if (!post(mPerformClick)) { 11816 performClick(); 11817 } 11818 } 11819 } 11820 11821 if (mUnsetPressedState == null) { 11822 mUnsetPressedState = new UnsetPressedState(); 11823 } 11824 11825 if (prepressed) { 11826 postDelayed(mUnsetPressedState, 11827 ViewConfiguration.getPressedStateDuration()); 11828 } else if (!post(mUnsetPressedState)) { 11829 // If the post failed, unpress right now 11830 mUnsetPressedState.run(); 11831 } 11832 11833 removeTapCallback(); 11834 } 11835 mIgnoreNextUpEvent = false; 11836 break; 11837 11838 case MotionEvent.ACTION_DOWN: 11839 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 11840 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 11841 } 11842 mHasPerformedLongPress = false; 11843 11844 if (!clickable) { 11845 checkForLongClick(0, x, y); 11846 break; 11847 } 11848 11849 if (performButtonActionOnTouchDown(event)) { 11850 break; 11851 } 11852 11853 // Walk up the hierarchy to determine if we're inside a scrolling container. 11854 boolean isInScrollingContainer = isInScrollingContainer(); 11855 11856 // For views inside a scrolling container, delay the pressed feedback for 11857 // a short period in case this is a scroll. 11858 if (isInScrollingContainer) { 11859 mPrivateFlags |= PFLAG_PREPRESSED; 11860 if (mPendingCheckForTap == null) { 11861 mPendingCheckForTap = new CheckForTap(); 11862 } 11863 mPendingCheckForTap.x = event.getX(); 11864 mPendingCheckForTap.y = event.getY(); 11865 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 11866 } else { 11867 // Not inside a scrolling container, so show the feedback right away 11868 setPressed(true, x, y); 11869 checkForLongClick(0, x, y); 11870 } 11871 break; 11872 11873 case MotionEvent.ACTION_CANCEL: 11874 if (clickable) { 11875 setPressed(false); 11876 } 11877 removeTapCallback(); 11878 removeLongPressCallback(); 11879 mInContextButtonPress = false; 11880 mHasPerformedLongPress = false; 11881 mIgnoreNextUpEvent = false; 11882 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11883 break; 11884 11885 case MotionEvent.ACTION_MOVE: 11886 if (clickable) { 11887 drawableHotspotChanged(x, y); 11888 } 11889 11890 // Be lenient about moving outside of buttons 11891 if (!pointInView(x, y, mTouchSlop)) { 11892 // Outside button 11893 // Remove any future long press/tap checks 11894 removeTapCallback(); 11895 removeLongPressCallback(); 11896 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 11897 setPressed(false); 11898 } 11899 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11900 } 11901 break; 11902 } 11903 11904 return true; 11905 } 11906 11907 return false; 11908 } 11909 11910 /** 11911 * @hide 11912 */ 11913 public boolean isInScrollingContainer() { 11914 ViewParent p = getParent(); 11915 while (p != null && p instanceof ViewGroup) { 11916 if (((ViewGroup) p).shouldDelayChildPressedState()) { 11917 return true; 11918 } 11919 p = p.getParent(); 11920 } 11921 return false; 11922 } 11923 11924 /** 11925 * Remove the longpress detection timer. 11926 */ 11927 private void removeLongPressCallback() { 11928 if (mPendingCheckForLongPress != null) { 11929 removeCallbacks(mPendingCheckForLongPress); 11930 } 11931 } 11932 11933 /** 11934 * Remove the pending click action 11935 */ 11936 private void removePerformClickCallback() { 11937 if (mPerformClick != null) { 11938 removeCallbacks(mPerformClick); 11939 } 11940 } 11941 11942 /** 11943 * Remove the prepress detection timer. 11944 */ 11945 private void removeUnsetPressCallback() { 11946 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 11947 setPressed(false); 11948 removeCallbacks(mUnsetPressedState); 11949 } 11950 } 11951 11952 /** 11953 * Remove the tap detection timer. 11954 */ 11955 private void removeTapCallback() { 11956 if (mPendingCheckForTap != null) { 11957 mPrivateFlags &= ~PFLAG_PREPRESSED; 11958 removeCallbacks(mPendingCheckForTap); 11959 } 11960 } 11961 11962 /** 11963 * Cancels a pending long press. Your subclass can use this if you 11964 * want the context menu to come up if the user presses and holds 11965 * at the same place, but you don't want it to come up if they press 11966 * and then move around enough to cause scrolling. 11967 */ 11968 public void cancelLongPress() { 11969 removeLongPressCallback(); 11970 11971 /* 11972 * The prepressed state handled by the tap callback is a display 11973 * construct, but the tap callback will post a long press callback 11974 * less its own timeout. Remove it here. 11975 */ 11976 removeTapCallback(); 11977 } 11978 11979 /** 11980 * Remove the pending callback for sending a 11981 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 11982 */ 11983 private void removeSendViewScrolledAccessibilityEventCallback() { 11984 if (mSendViewScrolledAccessibilityEvent != null) { 11985 removeCallbacks(mSendViewScrolledAccessibilityEvent); 11986 mSendViewScrolledAccessibilityEvent.mIsPending = false; 11987 } 11988 } 11989 11990 /** 11991 * Sets the TouchDelegate for this View. 11992 */ 11993 public void setTouchDelegate(TouchDelegate delegate) { 11994 mTouchDelegate = delegate; 11995 } 11996 11997 /** 11998 * Gets the TouchDelegate for this View. 11999 */ 12000 public TouchDelegate getTouchDelegate() { 12001 return mTouchDelegate; 12002 } 12003 12004 /** 12005 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 12006 * 12007 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 12008 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 12009 * available. This method should only be called for touch events. 12010 * 12011 * <p class="note">This api is not intended for most applications. Buffered dispatch 12012 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 12013 * streams will not improve your input latency. Side effects include: increased latency, 12014 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 12015 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 12016 * you.</p> 12017 */ 12018 public final void requestUnbufferedDispatch(MotionEvent event) { 12019 final int action = event.getAction(); 12020 if (mAttachInfo == null 12021 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 12022 || !event.isTouchEvent()) { 12023 return; 12024 } 12025 mAttachInfo.mUnbufferedDispatchRequested = true; 12026 } 12027 12028 /** 12029 * Set flags controlling behavior of this view. 12030 * 12031 * @param flags Constant indicating the value which should be set 12032 * @param mask Constant indicating the bit range that should be changed 12033 */ 12034 void setFlags(int flags, int mask) { 12035 final boolean accessibilityEnabled = 12036 AccessibilityManager.getInstance(mContext).isEnabled(); 12037 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 12038 12039 int old = mViewFlags; 12040 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 12041 12042 int changed = mViewFlags ^ old; 12043 if (changed == 0) { 12044 return; 12045 } 12046 int privateFlags = mPrivateFlags; 12047 12048 // If focusable is auto, update the FOCUSABLE bit. 12049 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 12050 && (changed & (FOCUSABLE_MASK | CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) { 12051 int newFocus = NOT_FOCUSABLE; 12052 if ((mViewFlags & (CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) { 12053 newFocus = FOCUSABLE; 12054 } else { 12055 mViewFlags = (mViewFlags & ~FOCUSABLE_IN_TOUCH_MODE); 12056 } 12057 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 12058 int focusChanged = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 12059 changed = (changed & ~FOCUSABLE) | focusChanged; 12060 } 12061 12062 /* Check if the FOCUSABLE bit has changed */ 12063 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 12064 if (((old & FOCUSABLE) == FOCUSABLE) 12065 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 12066 /* Give up focus if we are no longer focusable */ 12067 clearFocus(); 12068 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 12069 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 12070 /* 12071 * Tell the view system that we are now available to take focus 12072 * if no one else already has it. 12073 */ 12074 if (mParent != null) mParent.focusableViewAvailable(this); 12075 } 12076 } 12077 12078 final int newVisibility = flags & VISIBILITY_MASK; 12079 if (newVisibility == VISIBLE) { 12080 if ((changed & VISIBILITY_MASK) != 0) { 12081 /* 12082 * If this view is becoming visible, invalidate it in case it changed while 12083 * it was not visible. Marking it drawn ensures that the invalidation will 12084 * go through. 12085 */ 12086 mPrivateFlags |= PFLAG_DRAWN; 12087 invalidate(true); 12088 12089 needGlobalAttributesUpdate(true); 12090 12091 // a view becoming visible is worth notifying the parent 12092 // about in case nothing has focus. even if this specific view 12093 // isn't focusable, it may contain something that is, so let 12094 // the root view try to give this focus if nothing else does. 12095 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 12096 mParent.focusableViewAvailable(this); 12097 } 12098 } 12099 } 12100 12101 /* Check if the GONE bit has changed */ 12102 if ((changed & GONE) != 0) { 12103 needGlobalAttributesUpdate(false); 12104 requestLayout(); 12105 12106 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 12107 if (hasFocus()) clearFocus(); 12108 clearAccessibilityFocus(); 12109 destroyDrawingCache(); 12110 if (mParent instanceof View) { 12111 // GONE views noop invalidation, so invalidate the parent 12112 ((View) mParent).invalidate(true); 12113 } 12114 // Mark the view drawn to ensure that it gets invalidated properly the next 12115 // time it is visible and gets invalidated 12116 mPrivateFlags |= PFLAG_DRAWN; 12117 } 12118 if (mAttachInfo != null) { 12119 mAttachInfo.mViewVisibilityChanged = true; 12120 } 12121 } 12122 12123 /* Check if the VISIBLE bit has changed */ 12124 if ((changed & INVISIBLE) != 0) { 12125 needGlobalAttributesUpdate(false); 12126 /* 12127 * If this view is becoming invisible, set the DRAWN flag so that 12128 * the next invalidate() will not be skipped. 12129 */ 12130 mPrivateFlags |= PFLAG_DRAWN; 12131 12132 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 12133 // root view becoming invisible shouldn't clear focus and accessibility focus 12134 if (getRootView() != this) { 12135 if (hasFocus()) clearFocus(); 12136 clearAccessibilityFocus(); 12137 } 12138 } 12139 if (mAttachInfo != null) { 12140 mAttachInfo.mViewVisibilityChanged = true; 12141 } 12142 } 12143 12144 if ((changed & VISIBILITY_MASK) != 0) { 12145 // If the view is invisible, cleanup its display list to free up resources 12146 if (newVisibility != VISIBLE && mAttachInfo != null) { 12147 cleanupDraw(); 12148 } 12149 12150 if (mParent instanceof ViewGroup) { 12151 ((ViewGroup) mParent).onChildVisibilityChanged(this, 12152 (changed & VISIBILITY_MASK), newVisibility); 12153 ((View) mParent).invalidate(true); 12154 } else if (mParent != null) { 12155 mParent.invalidateChild(this, null); 12156 } 12157 12158 if (mAttachInfo != null) { 12159 dispatchVisibilityChanged(this, newVisibility); 12160 12161 // Aggregated visibility changes are dispatched to attached views 12162 // in visible windows where the parent is currently shown/drawn 12163 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 12164 // discounting clipping or overlapping. This makes it a good place 12165 // to change animation states. 12166 if (mParent != null && getWindowVisibility() == VISIBLE && 12167 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 12168 dispatchVisibilityAggregated(newVisibility == VISIBLE); 12169 } 12170 notifySubtreeAccessibilityStateChangedIfNeeded(); 12171 } 12172 } 12173 12174 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 12175 destroyDrawingCache(); 12176 } 12177 12178 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 12179 destroyDrawingCache(); 12180 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12181 invalidateParentCaches(); 12182 } 12183 12184 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 12185 destroyDrawingCache(); 12186 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12187 } 12188 12189 if ((changed & DRAW_MASK) != 0) { 12190 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 12191 if (mBackground != null 12192 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 12193 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12194 } else { 12195 mPrivateFlags |= PFLAG_SKIP_DRAW; 12196 } 12197 } else { 12198 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12199 } 12200 requestLayout(); 12201 invalidate(true); 12202 } 12203 12204 if ((changed & KEEP_SCREEN_ON) != 0) { 12205 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 12206 mParent.recomputeViewAttributes(this); 12207 } 12208 } 12209 12210 if (accessibilityEnabled) { 12211 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 12212 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 12213 || (changed & CONTEXT_CLICKABLE) != 0) { 12214 if (oldIncludeForAccessibility != includeForAccessibility()) { 12215 notifySubtreeAccessibilityStateChangedIfNeeded(); 12216 } else { 12217 notifyViewAccessibilityStateChangedIfNeeded( 12218 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12219 } 12220 } else if ((changed & ENABLED_MASK) != 0) { 12221 notifyViewAccessibilityStateChangedIfNeeded( 12222 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12223 } 12224 } 12225 } 12226 12227 /** 12228 * Change the view's z order in the tree, so it's on top of other sibling 12229 * views. This ordering change may affect layout, if the parent container 12230 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 12231 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 12232 * method should be followed by calls to {@link #requestLayout()} and 12233 * {@link View#invalidate()} on the view's parent to force the parent to redraw 12234 * with the new child ordering. 12235 * 12236 * @see ViewGroup#bringChildToFront(View) 12237 */ 12238 public void bringToFront() { 12239 if (mParent != null) { 12240 mParent.bringChildToFront(this); 12241 } 12242 } 12243 12244 /** 12245 * This is called in response to an internal scroll in this view (i.e., the 12246 * view scrolled its own contents). This is typically as a result of 12247 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 12248 * called. 12249 * 12250 * @param l Current horizontal scroll origin. 12251 * @param t Current vertical scroll origin. 12252 * @param oldl Previous horizontal scroll origin. 12253 * @param oldt Previous vertical scroll origin. 12254 */ 12255 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 12256 notifySubtreeAccessibilityStateChangedIfNeeded(); 12257 12258 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 12259 postSendViewScrolledAccessibilityEventCallback(); 12260 } 12261 12262 mBackgroundSizeChanged = true; 12263 if (mForegroundInfo != null) { 12264 mForegroundInfo.mBoundsChanged = true; 12265 } 12266 12267 final AttachInfo ai = mAttachInfo; 12268 if (ai != null) { 12269 ai.mViewScrollChanged = true; 12270 } 12271 12272 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 12273 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 12274 } 12275 } 12276 12277 /** 12278 * Interface definition for a callback to be invoked when the scroll 12279 * X or Y positions of a view change. 12280 * <p> 12281 * <b>Note:</b> Some views handle scrolling independently from View and may 12282 * have their own separate listeners for scroll-type events. For example, 12283 * {@link android.widget.ListView ListView} allows clients to register an 12284 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 12285 * to listen for changes in list scroll position. 12286 * 12287 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 12288 */ 12289 public interface OnScrollChangeListener { 12290 /** 12291 * Called when the scroll position of a view changes. 12292 * 12293 * @param v The view whose scroll position has changed. 12294 * @param scrollX Current horizontal scroll origin. 12295 * @param scrollY Current vertical scroll origin. 12296 * @param oldScrollX Previous horizontal scroll origin. 12297 * @param oldScrollY Previous vertical scroll origin. 12298 */ 12299 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 12300 } 12301 12302 /** 12303 * Interface definition for a callback to be invoked when the layout bounds of a view 12304 * changes due to layout processing. 12305 */ 12306 public interface OnLayoutChangeListener { 12307 /** 12308 * Called when the layout bounds of a view changes due to layout processing. 12309 * 12310 * @param v The view whose bounds have changed. 12311 * @param left The new value of the view's left property. 12312 * @param top The new value of the view's top property. 12313 * @param right The new value of the view's right property. 12314 * @param bottom The new value of the view's bottom property. 12315 * @param oldLeft The previous value of the view's left property. 12316 * @param oldTop The previous value of the view's top property. 12317 * @param oldRight The previous value of the view's right property. 12318 * @param oldBottom The previous value of the view's bottom property. 12319 */ 12320 void onLayoutChange(View v, int left, int top, int right, int bottom, 12321 int oldLeft, int oldTop, int oldRight, int oldBottom); 12322 } 12323 12324 /** 12325 * This is called during layout when the size of this view has changed. If 12326 * you were just added to the view hierarchy, you're called with the old 12327 * values of 0. 12328 * 12329 * @param w Current width of this view. 12330 * @param h Current height of this view. 12331 * @param oldw Old width of this view. 12332 * @param oldh Old height of this view. 12333 */ 12334 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 12335 } 12336 12337 /** 12338 * Called by draw to draw the child views. This may be overridden 12339 * by derived classes to gain control just before its children are drawn 12340 * (but after its own view has been drawn). 12341 * @param canvas the canvas on which to draw the view 12342 */ 12343 protected void dispatchDraw(Canvas canvas) { 12344 12345 } 12346 12347 /** 12348 * Gets the parent of this view. Note that the parent is a 12349 * ViewParent and not necessarily a View. 12350 * 12351 * @return Parent of this view. 12352 */ 12353 public final ViewParent getParent() { 12354 return mParent; 12355 } 12356 12357 /** 12358 * Set the horizontal scrolled position of your view. This will cause a call to 12359 * {@link #onScrollChanged(int, int, int, int)} and the view will be 12360 * invalidated. 12361 * @param value the x position to scroll to 12362 */ 12363 public void setScrollX(int value) { 12364 scrollTo(value, mScrollY); 12365 } 12366 12367 /** 12368 * Set the vertical scrolled position of your view. This will cause a call to 12369 * {@link #onScrollChanged(int, int, int, int)} and the view will be 12370 * invalidated. 12371 * @param value the y position to scroll to 12372 */ 12373 public void setScrollY(int value) { 12374 scrollTo(mScrollX, value); 12375 } 12376 12377 /** 12378 * Return the scrolled left position of this view. This is the left edge of 12379 * the displayed part of your view. You do not need to draw any pixels 12380 * farther left, since those are outside of the frame of your view on 12381 * screen. 12382 * 12383 * @return The left edge of the displayed part of your view, in pixels. 12384 */ 12385 public final int getScrollX() { 12386 return mScrollX; 12387 } 12388 12389 /** 12390 * Return the scrolled top position of this view. This is the top edge of 12391 * the displayed part of your view. You do not need to draw any pixels above 12392 * it, since those are outside of the frame of your view on screen. 12393 * 12394 * @return The top edge of the displayed part of your view, in pixels. 12395 */ 12396 public final int getScrollY() { 12397 return mScrollY; 12398 } 12399 12400 /** 12401 * Return the width of the your view. 12402 * 12403 * @return The width of your view, in pixels. 12404 */ 12405 @ViewDebug.ExportedProperty(category = "layout") 12406 public final int getWidth() { 12407 return mRight - mLeft; 12408 } 12409 12410 /** 12411 * Return the height of your view. 12412 * 12413 * @return The height of your view, in pixels. 12414 */ 12415 @ViewDebug.ExportedProperty(category = "layout") 12416 public final int getHeight() { 12417 return mBottom - mTop; 12418 } 12419 12420 /** 12421 * Return the visible drawing bounds of your view. Fills in the output 12422 * rectangle with the values from getScrollX(), getScrollY(), 12423 * getWidth(), and getHeight(). These bounds do not account for any 12424 * transformation properties currently set on the view, such as 12425 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 12426 * 12427 * @param outRect The (scrolled) drawing bounds of the view. 12428 */ 12429 public void getDrawingRect(Rect outRect) { 12430 outRect.left = mScrollX; 12431 outRect.top = mScrollY; 12432 outRect.right = mScrollX + (mRight - mLeft); 12433 outRect.bottom = mScrollY + (mBottom - mTop); 12434 } 12435 12436 /** 12437 * Like {@link #getMeasuredWidthAndState()}, but only returns the 12438 * raw width component (that is the result is masked by 12439 * {@link #MEASURED_SIZE_MASK}). 12440 * 12441 * @return The raw measured width of this view. 12442 */ 12443 public final int getMeasuredWidth() { 12444 return mMeasuredWidth & MEASURED_SIZE_MASK; 12445 } 12446 12447 /** 12448 * Return the full width measurement information for this view as computed 12449 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 12450 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 12451 * This should be used during measurement and layout calculations only. Use 12452 * {@link #getWidth()} to see how wide a view is after layout. 12453 * 12454 * @return The measured width of this view as a bit mask. 12455 */ 12456 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 12457 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 12458 name = "MEASURED_STATE_TOO_SMALL"), 12459 }) 12460 public final int getMeasuredWidthAndState() { 12461 return mMeasuredWidth; 12462 } 12463 12464 /** 12465 * Like {@link #getMeasuredHeightAndState()}, but only returns the 12466 * raw height component (that is the result is masked by 12467 * {@link #MEASURED_SIZE_MASK}). 12468 * 12469 * @return The raw measured height of this view. 12470 */ 12471 public final int getMeasuredHeight() { 12472 return mMeasuredHeight & MEASURED_SIZE_MASK; 12473 } 12474 12475 /** 12476 * Return the full height measurement information for this view as computed 12477 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 12478 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 12479 * This should be used during measurement and layout calculations only. Use 12480 * {@link #getHeight()} to see how wide a view is after layout. 12481 * 12482 * @return The measured height of this view as a bit mask. 12483 */ 12484 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 12485 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 12486 name = "MEASURED_STATE_TOO_SMALL"), 12487 }) 12488 public final int getMeasuredHeightAndState() { 12489 return mMeasuredHeight; 12490 } 12491 12492 /** 12493 * Return only the state bits of {@link #getMeasuredWidthAndState()} 12494 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 12495 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 12496 * and the height component is at the shifted bits 12497 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 12498 */ 12499 public final int getMeasuredState() { 12500 return (mMeasuredWidth&MEASURED_STATE_MASK) 12501 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 12502 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 12503 } 12504 12505 /** 12506 * The transform matrix of this view, which is calculated based on the current 12507 * rotation, scale, and pivot properties. 12508 * 12509 * @see #getRotation() 12510 * @see #getScaleX() 12511 * @see #getScaleY() 12512 * @see #getPivotX() 12513 * @see #getPivotY() 12514 * @return The current transform matrix for the view 12515 */ 12516 public Matrix getMatrix() { 12517 ensureTransformationInfo(); 12518 final Matrix matrix = mTransformationInfo.mMatrix; 12519 mRenderNode.getMatrix(matrix); 12520 return matrix; 12521 } 12522 12523 /** 12524 * Returns true if the transform matrix is the identity matrix. 12525 * Recomputes the matrix if necessary. 12526 * 12527 * @return True if the transform matrix is the identity matrix, false otherwise. 12528 */ 12529 final boolean hasIdentityMatrix() { 12530 return mRenderNode.hasIdentityMatrix(); 12531 } 12532 12533 void ensureTransformationInfo() { 12534 if (mTransformationInfo == null) { 12535 mTransformationInfo = new TransformationInfo(); 12536 } 12537 } 12538 12539 /** 12540 * Utility method to retrieve the inverse of the current mMatrix property. 12541 * We cache the matrix to avoid recalculating it when transform properties 12542 * have not changed. 12543 * 12544 * @return The inverse of the current matrix of this view. 12545 * @hide 12546 */ 12547 public final Matrix getInverseMatrix() { 12548 ensureTransformationInfo(); 12549 if (mTransformationInfo.mInverseMatrix == null) { 12550 mTransformationInfo.mInverseMatrix = new Matrix(); 12551 } 12552 final Matrix matrix = mTransformationInfo.mInverseMatrix; 12553 mRenderNode.getInverseMatrix(matrix); 12554 return matrix; 12555 } 12556 12557 /** 12558 * Gets the distance along the Z axis from the camera to this view. 12559 * 12560 * @see #setCameraDistance(float) 12561 * 12562 * @return The distance along the Z axis. 12563 */ 12564 public float getCameraDistance() { 12565 final float dpi = mResources.getDisplayMetrics().densityDpi; 12566 return -(mRenderNode.getCameraDistance() * dpi); 12567 } 12568 12569 /** 12570 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 12571 * views are drawn) from the camera to this view. The camera's distance 12572 * affects 3D transformations, for instance rotations around the X and Y 12573 * axis. If the rotationX or rotationY properties are changed and this view is 12574 * large (more than half the size of the screen), it is recommended to always 12575 * use a camera distance that's greater than the height (X axis rotation) or 12576 * the width (Y axis rotation) of this view.</p> 12577 * 12578 * <p>The distance of the camera from the view plane can have an affect on the 12579 * perspective distortion of the view when it is rotated around the x or y axis. 12580 * For example, a large distance will result in a large viewing angle, and there 12581 * will not be much perspective distortion of the view as it rotates. A short 12582 * distance may cause much more perspective distortion upon rotation, and can 12583 * also result in some drawing artifacts if the rotated view ends up partially 12584 * behind the camera (which is why the recommendation is to use a distance at 12585 * least as far as the size of the view, if the view is to be rotated.)</p> 12586 * 12587 * <p>The distance is expressed in "depth pixels." The default distance depends 12588 * on the screen density. For instance, on a medium density display, the 12589 * default distance is 1280. On a high density display, the default distance 12590 * is 1920.</p> 12591 * 12592 * <p>If you want to specify a distance that leads to visually consistent 12593 * results across various densities, use the following formula:</p> 12594 * <pre> 12595 * float scale = context.getResources().getDisplayMetrics().density; 12596 * view.setCameraDistance(distance * scale); 12597 * </pre> 12598 * 12599 * <p>The density scale factor of a high density display is 1.5, 12600 * and 1920 = 1280 * 1.5.</p> 12601 * 12602 * @param distance The distance in "depth pixels", if negative the opposite 12603 * value is used 12604 * 12605 * @see #setRotationX(float) 12606 * @see #setRotationY(float) 12607 */ 12608 public void setCameraDistance(float distance) { 12609 final float dpi = mResources.getDisplayMetrics().densityDpi; 12610 12611 invalidateViewProperty(true, false); 12612 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 12613 invalidateViewProperty(false, false); 12614 12615 invalidateParentIfNeededAndWasQuickRejected(); 12616 } 12617 12618 /** 12619 * The degrees that the view is rotated around the pivot point. 12620 * 12621 * @see #setRotation(float) 12622 * @see #getPivotX() 12623 * @see #getPivotY() 12624 * 12625 * @return The degrees of rotation. 12626 */ 12627 @ViewDebug.ExportedProperty(category = "drawing") 12628 public float getRotation() { 12629 return mRenderNode.getRotation(); 12630 } 12631 12632 /** 12633 * Sets the degrees that the view is rotated around the pivot point. Increasing values 12634 * result in clockwise rotation. 12635 * 12636 * @param rotation The degrees of rotation. 12637 * 12638 * @see #getRotation() 12639 * @see #getPivotX() 12640 * @see #getPivotY() 12641 * @see #setRotationX(float) 12642 * @see #setRotationY(float) 12643 * 12644 * @attr ref android.R.styleable#View_rotation 12645 */ 12646 public void setRotation(float rotation) { 12647 if (rotation != getRotation()) { 12648 // Double-invalidation is necessary to capture view's old and new areas 12649 invalidateViewProperty(true, false); 12650 mRenderNode.setRotation(rotation); 12651 invalidateViewProperty(false, true); 12652 12653 invalidateParentIfNeededAndWasQuickRejected(); 12654 notifySubtreeAccessibilityStateChangedIfNeeded(); 12655 } 12656 } 12657 12658 /** 12659 * The degrees that the view is rotated around the vertical axis through the pivot point. 12660 * 12661 * @see #getPivotX() 12662 * @see #getPivotY() 12663 * @see #setRotationY(float) 12664 * 12665 * @return The degrees of Y rotation. 12666 */ 12667 @ViewDebug.ExportedProperty(category = "drawing") 12668 public float getRotationY() { 12669 return mRenderNode.getRotationY(); 12670 } 12671 12672 /** 12673 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 12674 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 12675 * down the y axis. 12676 * 12677 * When rotating large views, it is recommended to adjust the camera distance 12678 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12679 * 12680 * @param rotationY The degrees of Y rotation. 12681 * 12682 * @see #getRotationY() 12683 * @see #getPivotX() 12684 * @see #getPivotY() 12685 * @see #setRotation(float) 12686 * @see #setRotationX(float) 12687 * @see #setCameraDistance(float) 12688 * 12689 * @attr ref android.R.styleable#View_rotationY 12690 */ 12691 public void setRotationY(float rotationY) { 12692 if (rotationY != getRotationY()) { 12693 invalidateViewProperty(true, false); 12694 mRenderNode.setRotationY(rotationY); 12695 invalidateViewProperty(false, true); 12696 12697 invalidateParentIfNeededAndWasQuickRejected(); 12698 notifySubtreeAccessibilityStateChangedIfNeeded(); 12699 } 12700 } 12701 12702 /** 12703 * The degrees that the view is rotated around the horizontal axis through the pivot point. 12704 * 12705 * @see #getPivotX() 12706 * @see #getPivotY() 12707 * @see #setRotationX(float) 12708 * 12709 * @return The degrees of X rotation. 12710 */ 12711 @ViewDebug.ExportedProperty(category = "drawing") 12712 public float getRotationX() { 12713 return mRenderNode.getRotationX(); 12714 } 12715 12716 /** 12717 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 12718 * Increasing values result in clockwise rotation from the viewpoint of looking down the 12719 * x axis. 12720 * 12721 * When rotating large views, it is recommended to adjust the camera distance 12722 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12723 * 12724 * @param rotationX The degrees of X rotation. 12725 * 12726 * @see #getRotationX() 12727 * @see #getPivotX() 12728 * @see #getPivotY() 12729 * @see #setRotation(float) 12730 * @see #setRotationY(float) 12731 * @see #setCameraDistance(float) 12732 * 12733 * @attr ref android.R.styleable#View_rotationX 12734 */ 12735 public void setRotationX(float rotationX) { 12736 if (rotationX != getRotationX()) { 12737 invalidateViewProperty(true, false); 12738 mRenderNode.setRotationX(rotationX); 12739 invalidateViewProperty(false, true); 12740 12741 invalidateParentIfNeededAndWasQuickRejected(); 12742 notifySubtreeAccessibilityStateChangedIfNeeded(); 12743 } 12744 } 12745 12746 /** 12747 * The amount that the view is scaled in x around the pivot point, as a proportion of 12748 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 12749 * 12750 * <p>By default, this is 1.0f. 12751 * 12752 * @see #getPivotX() 12753 * @see #getPivotY() 12754 * @return The scaling factor. 12755 */ 12756 @ViewDebug.ExportedProperty(category = "drawing") 12757 public float getScaleX() { 12758 return mRenderNode.getScaleX(); 12759 } 12760 12761 /** 12762 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 12763 * the view's unscaled width. A value of 1 means that no scaling is applied. 12764 * 12765 * @param scaleX The scaling factor. 12766 * @see #getPivotX() 12767 * @see #getPivotY() 12768 * 12769 * @attr ref android.R.styleable#View_scaleX 12770 */ 12771 public void setScaleX(float scaleX) { 12772 if (scaleX != getScaleX()) { 12773 invalidateViewProperty(true, false); 12774 mRenderNode.setScaleX(scaleX); 12775 invalidateViewProperty(false, true); 12776 12777 invalidateParentIfNeededAndWasQuickRejected(); 12778 notifySubtreeAccessibilityStateChangedIfNeeded(); 12779 } 12780 } 12781 12782 /** 12783 * The amount that the view is scaled in y around the pivot point, as a proportion of 12784 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 12785 * 12786 * <p>By default, this is 1.0f. 12787 * 12788 * @see #getPivotX() 12789 * @see #getPivotY() 12790 * @return The scaling factor. 12791 */ 12792 @ViewDebug.ExportedProperty(category = "drawing") 12793 public float getScaleY() { 12794 return mRenderNode.getScaleY(); 12795 } 12796 12797 /** 12798 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 12799 * the view's unscaled width. A value of 1 means that no scaling is applied. 12800 * 12801 * @param scaleY The scaling factor. 12802 * @see #getPivotX() 12803 * @see #getPivotY() 12804 * 12805 * @attr ref android.R.styleable#View_scaleY 12806 */ 12807 public void setScaleY(float scaleY) { 12808 if (scaleY != getScaleY()) { 12809 invalidateViewProperty(true, false); 12810 mRenderNode.setScaleY(scaleY); 12811 invalidateViewProperty(false, true); 12812 12813 invalidateParentIfNeededAndWasQuickRejected(); 12814 notifySubtreeAccessibilityStateChangedIfNeeded(); 12815 } 12816 } 12817 12818 /** 12819 * The x location of the point around which the view is {@link #setRotation(float) rotated} 12820 * and {@link #setScaleX(float) scaled}. 12821 * 12822 * @see #getRotation() 12823 * @see #getScaleX() 12824 * @see #getScaleY() 12825 * @see #getPivotY() 12826 * @return The x location of the pivot point. 12827 * 12828 * @attr ref android.R.styleable#View_transformPivotX 12829 */ 12830 @ViewDebug.ExportedProperty(category = "drawing") 12831 public float getPivotX() { 12832 return mRenderNode.getPivotX(); 12833 } 12834 12835 /** 12836 * Sets the x location of the point around which the view is 12837 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 12838 * By default, the pivot point is centered on the object. 12839 * Setting this property disables this behavior and causes the view to use only the 12840 * explicitly set pivotX and pivotY values. 12841 * 12842 * @param pivotX The x location of the pivot point. 12843 * @see #getRotation() 12844 * @see #getScaleX() 12845 * @see #getScaleY() 12846 * @see #getPivotY() 12847 * 12848 * @attr ref android.R.styleable#View_transformPivotX 12849 */ 12850 public void setPivotX(float pivotX) { 12851 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 12852 invalidateViewProperty(true, false); 12853 mRenderNode.setPivotX(pivotX); 12854 invalidateViewProperty(false, true); 12855 12856 invalidateParentIfNeededAndWasQuickRejected(); 12857 } 12858 } 12859 12860 /** 12861 * The y location of the point around which the view is {@link #setRotation(float) rotated} 12862 * and {@link #setScaleY(float) scaled}. 12863 * 12864 * @see #getRotation() 12865 * @see #getScaleX() 12866 * @see #getScaleY() 12867 * @see #getPivotY() 12868 * @return The y location of the pivot point. 12869 * 12870 * @attr ref android.R.styleable#View_transformPivotY 12871 */ 12872 @ViewDebug.ExportedProperty(category = "drawing") 12873 public float getPivotY() { 12874 return mRenderNode.getPivotY(); 12875 } 12876 12877 /** 12878 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 12879 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 12880 * Setting this property disables this behavior and causes the view to use only the 12881 * explicitly set pivotX and pivotY values. 12882 * 12883 * @param pivotY The y location of the pivot point. 12884 * @see #getRotation() 12885 * @see #getScaleX() 12886 * @see #getScaleY() 12887 * @see #getPivotY() 12888 * 12889 * @attr ref android.R.styleable#View_transformPivotY 12890 */ 12891 public void setPivotY(float pivotY) { 12892 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 12893 invalidateViewProperty(true, false); 12894 mRenderNode.setPivotY(pivotY); 12895 invalidateViewProperty(false, true); 12896 12897 invalidateParentIfNeededAndWasQuickRejected(); 12898 } 12899 } 12900 12901 /** 12902 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 12903 * completely transparent and 1 means the view is completely opaque. 12904 * 12905 * <p>By default this is 1.0f. 12906 * @return The opacity of the view. 12907 */ 12908 @ViewDebug.ExportedProperty(category = "drawing") 12909 public float getAlpha() { 12910 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 12911 } 12912 12913 /** 12914 * Sets the behavior for overlapping rendering for this view (see {@link 12915 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 12916 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 12917 * providing the value which is then used internally. That is, when {@link 12918 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 12919 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 12920 * instead. 12921 * 12922 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 12923 * instead of that returned by {@link #hasOverlappingRendering()}. 12924 * 12925 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 12926 */ 12927 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 12928 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 12929 if (hasOverlappingRendering) { 12930 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 12931 } else { 12932 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 12933 } 12934 } 12935 12936 /** 12937 * Returns the value for overlapping rendering that is used internally. This is either 12938 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 12939 * the return value of {@link #hasOverlappingRendering()}, otherwise. 12940 * 12941 * @return The value for overlapping rendering being used internally. 12942 */ 12943 public final boolean getHasOverlappingRendering() { 12944 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 12945 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 12946 hasOverlappingRendering(); 12947 } 12948 12949 /** 12950 * Returns whether this View has content which overlaps. 12951 * 12952 * <p>This function, intended to be overridden by specific View types, is an optimization when 12953 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 12954 * an offscreen buffer and then composited into place, which can be expensive. If the view has 12955 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 12956 * directly. An example of overlapping rendering is a TextView with a background image, such as 12957 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 12958 * ImageView with only the foreground image. The default implementation returns true; subclasses 12959 * should override if they have cases which can be optimized.</p> 12960 * 12961 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 12962 * necessitates that a View return true if it uses the methods internally without passing the 12963 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 12964 * 12965 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 12966 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 12967 * 12968 * @return true if the content in this view might overlap, false otherwise. 12969 */ 12970 @ViewDebug.ExportedProperty(category = "drawing") 12971 public boolean hasOverlappingRendering() { 12972 return true; 12973 } 12974 12975 /** 12976 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 12977 * completely transparent and 1 means the view is completely opaque. 12978 * 12979 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 12980 * can have significant performance implications, especially for large views. It is best to use 12981 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 12982 * 12983 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 12984 * strongly recommended for performance reasons to either override 12985 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 12986 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 12987 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 12988 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 12989 * of rendering cost, even for simple or small views. Starting with 12990 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 12991 * applied to the view at the rendering level.</p> 12992 * 12993 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 12994 * responsible for applying the opacity itself.</p> 12995 * 12996 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 12997 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 12998 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 12999 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 13000 * 13001 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 13002 * value will clip a View to its bounds, unless the View returns <code>false</code> from 13003 * {@link #hasOverlappingRendering}.</p> 13004 * 13005 * @param alpha The opacity of the view. 13006 * 13007 * @see #hasOverlappingRendering() 13008 * @see #setLayerType(int, android.graphics.Paint) 13009 * 13010 * @attr ref android.R.styleable#View_alpha 13011 */ 13012 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 13013 ensureTransformationInfo(); 13014 if (mTransformationInfo.mAlpha != alpha) { 13015 // Report visibility changes, which can affect children, to accessibility 13016 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 13017 notifySubtreeAccessibilityStateChangedIfNeeded(); 13018 } 13019 mTransformationInfo.mAlpha = alpha; 13020 if (onSetAlpha((int) (alpha * 255))) { 13021 mPrivateFlags |= PFLAG_ALPHA_SET; 13022 // subclass is handling alpha - don't optimize rendering cache invalidation 13023 invalidateParentCaches(); 13024 invalidate(true); 13025 } else { 13026 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13027 invalidateViewProperty(true, false); 13028 mRenderNode.setAlpha(getFinalAlpha()); 13029 } 13030 } 13031 } 13032 13033 /** 13034 * Faster version of setAlpha() which performs the same steps except there are 13035 * no calls to invalidate(). The caller of this function should perform proper invalidation 13036 * on the parent and this object. The return value indicates whether the subclass handles 13037 * alpha (the return value for onSetAlpha()). 13038 * 13039 * @param alpha The new value for the alpha property 13040 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 13041 * the new value for the alpha property is different from the old value 13042 */ 13043 boolean setAlphaNoInvalidation(float alpha) { 13044 ensureTransformationInfo(); 13045 if (mTransformationInfo.mAlpha != alpha) { 13046 mTransformationInfo.mAlpha = alpha; 13047 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 13048 if (subclassHandlesAlpha) { 13049 mPrivateFlags |= PFLAG_ALPHA_SET; 13050 return true; 13051 } else { 13052 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13053 mRenderNode.setAlpha(getFinalAlpha()); 13054 } 13055 } 13056 return false; 13057 } 13058 13059 /** 13060 * This property is hidden and intended only for use by the Fade transition, which 13061 * animates it to produce a visual translucency that does not side-effect (or get 13062 * affected by) the real alpha property. This value is composited with the other 13063 * alpha value (and the AlphaAnimation value, when that is present) to produce 13064 * a final visual translucency result, which is what is passed into the DisplayList. 13065 * 13066 * @hide 13067 */ 13068 public void setTransitionAlpha(float alpha) { 13069 ensureTransformationInfo(); 13070 if (mTransformationInfo.mTransitionAlpha != alpha) { 13071 mTransformationInfo.mTransitionAlpha = alpha; 13072 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13073 invalidateViewProperty(true, false); 13074 mRenderNode.setAlpha(getFinalAlpha()); 13075 } 13076 } 13077 13078 /** 13079 * Calculates the visual alpha of this view, which is a combination of the actual 13080 * alpha value and the transitionAlpha value (if set). 13081 */ 13082 private float getFinalAlpha() { 13083 if (mTransformationInfo != null) { 13084 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 13085 } 13086 return 1; 13087 } 13088 13089 /** 13090 * This property is hidden and intended only for use by the Fade transition, which 13091 * animates it to produce a visual translucency that does not side-effect (or get 13092 * affected by) the real alpha property. This value is composited with the other 13093 * alpha value (and the AlphaAnimation value, when that is present) to produce 13094 * a final visual translucency result, which is what is passed into the DisplayList. 13095 * 13096 * @hide 13097 */ 13098 @ViewDebug.ExportedProperty(category = "drawing") 13099 public float getTransitionAlpha() { 13100 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 13101 } 13102 13103 /** 13104 * Top position of this view relative to its parent. 13105 * 13106 * @return The top of this view, in pixels. 13107 */ 13108 @ViewDebug.CapturedViewProperty 13109 public final int getTop() { 13110 return mTop; 13111 } 13112 13113 /** 13114 * Sets the top position of this view relative to its parent. This method is meant to be called 13115 * by the layout system and should not generally be called otherwise, because the property 13116 * may be changed at any time by the layout. 13117 * 13118 * @param top The top of this view, in pixels. 13119 */ 13120 public final void setTop(int top) { 13121 if (top != mTop) { 13122 final boolean matrixIsIdentity = hasIdentityMatrix(); 13123 if (matrixIsIdentity) { 13124 if (mAttachInfo != null) { 13125 int minTop; 13126 int yLoc; 13127 if (top < mTop) { 13128 minTop = top; 13129 yLoc = top - mTop; 13130 } else { 13131 minTop = mTop; 13132 yLoc = 0; 13133 } 13134 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 13135 } 13136 } else { 13137 // Double-invalidation is necessary to capture view's old and new areas 13138 invalidate(true); 13139 } 13140 13141 int width = mRight - mLeft; 13142 int oldHeight = mBottom - mTop; 13143 13144 mTop = top; 13145 mRenderNode.setTop(mTop); 13146 13147 sizeChange(width, mBottom - mTop, width, oldHeight); 13148 13149 if (!matrixIsIdentity) { 13150 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13151 invalidate(true); 13152 } 13153 mBackgroundSizeChanged = true; 13154 if (mForegroundInfo != null) { 13155 mForegroundInfo.mBoundsChanged = true; 13156 } 13157 invalidateParentIfNeeded(); 13158 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13159 // View was rejected last time it was drawn by its parent; this may have changed 13160 invalidateParentIfNeeded(); 13161 } 13162 } 13163 } 13164 13165 /** 13166 * Bottom position of this view relative to its parent. 13167 * 13168 * @return The bottom of this view, in pixels. 13169 */ 13170 @ViewDebug.CapturedViewProperty 13171 public final int getBottom() { 13172 return mBottom; 13173 } 13174 13175 /** 13176 * True if this view has changed since the last time being drawn. 13177 * 13178 * @return The dirty state of this view. 13179 */ 13180 public boolean isDirty() { 13181 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 13182 } 13183 13184 /** 13185 * Sets the bottom position of this view relative to its parent. This method is meant to be 13186 * called by the layout system and should not generally be called otherwise, because the 13187 * property may be changed at any time by the layout. 13188 * 13189 * @param bottom The bottom of this view, in pixels. 13190 */ 13191 public final void setBottom(int bottom) { 13192 if (bottom != mBottom) { 13193 final boolean matrixIsIdentity = hasIdentityMatrix(); 13194 if (matrixIsIdentity) { 13195 if (mAttachInfo != null) { 13196 int maxBottom; 13197 if (bottom < mBottom) { 13198 maxBottom = mBottom; 13199 } else { 13200 maxBottom = bottom; 13201 } 13202 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 13203 } 13204 } else { 13205 // Double-invalidation is necessary to capture view's old and new areas 13206 invalidate(true); 13207 } 13208 13209 int width = mRight - mLeft; 13210 int oldHeight = mBottom - mTop; 13211 13212 mBottom = bottom; 13213 mRenderNode.setBottom(mBottom); 13214 13215 sizeChange(width, mBottom - mTop, width, oldHeight); 13216 13217 if (!matrixIsIdentity) { 13218 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13219 invalidate(true); 13220 } 13221 mBackgroundSizeChanged = true; 13222 if (mForegroundInfo != null) { 13223 mForegroundInfo.mBoundsChanged = true; 13224 } 13225 invalidateParentIfNeeded(); 13226 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13227 // View was rejected last time it was drawn by its parent; this may have changed 13228 invalidateParentIfNeeded(); 13229 } 13230 } 13231 } 13232 13233 /** 13234 * Left position of this view relative to its parent. 13235 * 13236 * @return The left edge of this view, in pixels. 13237 */ 13238 @ViewDebug.CapturedViewProperty 13239 public final int getLeft() { 13240 return mLeft; 13241 } 13242 13243 /** 13244 * Sets the left position of this view relative to its parent. This method is meant to be called 13245 * by the layout system and should not generally be called otherwise, because the property 13246 * may be changed at any time by the layout. 13247 * 13248 * @param left The left of this view, in pixels. 13249 */ 13250 public final void setLeft(int left) { 13251 if (left != mLeft) { 13252 final boolean matrixIsIdentity = hasIdentityMatrix(); 13253 if (matrixIsIdentity) { 13254 if (mAttachInfo != null) { 13255 int minLeft; 13256 int xLoc; 13257 if (left < mLeft) { 13258 minLeft = left; 13259 xLoc = left - mLeft; 13260 } else { 13261 minLeft = mLeft; 13262 xLoc = 0; 13263 } 13264 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 13265 } 13266 } else { 13267 // Double-invalidation is necessary to capture view's old and new areas 13268 invalidate(true); 13269 } 13270 13271 int oldWidth = mRight - mLeft; 13272 int height = mBottom - mTop; 13273 13274 mLeft = left; 13275 mRenderNode.setLeft(left); 13276 13277 sizeChange(mRight - mLeft, height, oldWidth, height); 13278 13279 if (!matrixIsIdentity) { 13280 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13281 invalidate(true); 13282 } 13283 mBackgroundSizeChanged = true; 13284 if (mForegroundInfo != null) { 13285 mForegroundInfo.mBoundsChanged = true; 13286 } 13287 invalidateParentIfNeeded(); 13288 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13289 // View was rejected last time it was drawn by its parent; this may have changed 13290 invalidateParentIfNeeded(); 13291 } 13292 } 13293 } 13294 13295 /** 13296 * Right position of this view relative to its parent. 13297 * 13298 * @return The right edge of this view, in pixels. 13299 */ 13300 @ViewDebug.CapturedViewProperty 13301 public final int getRight() { 13302 return mRight; 13303 } 13304 13305 /** 13306 * Sets the right position of this view relative to its parent. This method is meant to be called 13307 * by the layout system and should not generally be called otherwise, because the property 13308 * may be changed at any time by the layout. 13309 * 13310 * @param right The right of this view, in pixels. 13311 */ 13312 public final void setRight(int right) { 13313 if (right != mRight) { 13314 final boolean matrixIsIdentity = hasIdentityMatrix(); 13315 if (matrixIsIdentity) { 13316 if (mAttachInfo != null) { 13317 int maxRight; 13318 if (right < mRight) { 13319 maxRight = mRight; 13320 } else { 13321 maxRight = right; 13322 } 13323 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 13324 } 13325 } else { 13326 // Double-invalidation is necessary to capture view's old and new areas 13327 invalidate(true); 13328 } 13329 13330 int oldWidth = mRight - mLeft; 13331 int height = mBottom - mTop; 13332 13333 mRight = right; 13334 mRenderNode.setRight(mRight); 13335 13336 sizeChange(mRight - mLeft, height, oldWidth, height); 13337 13338 if (!matrixIsIdentity) { 13339 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13340 invalidate(true); 13341 } 13342 mBackgroundSizeChanged = true; 13343 if (mForegroundInfo != null) { 13344 mForegroundInfo.mBoundsChanged = true; 13345 } 13346 invalidateParentIfNeeded(); 13347 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13348 // View was rejected last time it was drawn by its parent; this may have changed 13349 invalidateParentIfNeeded(); 13350 } 13351 } 13352 } 13353 13354 /** 13355 * The visual x position of this view, in pixels. This is equivalent to the 13356 * {@link #setTranslationX(float) translationX} property plus the current 13357 * {@link #getLeft() left} property. 13358 * 13359 * @return The visual x position of this view, in pixels. 13360 */ 13361 @ViewDebug.ExportedProperty(category = "drawing") 13362 public float getX() { 13363 return mLeft + getTranslationX(); 13364 } 13365 13366 /** 13367 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 13368 * {@link #setTranslationX(float) translationX} property to be the difference between 13369 * the x value passed in and the current {@link #getLeft() left} property. 13370 * 13371 * @param x The visual x position of this view, in pixels. 13372 */ 13373 public void setX(float x) { 13374 setTranslationX(x - mLeft); 13375 } 13376 13377 /** 13378 * The visual y position of this view, in pixels. This is equivalent to the 13379 * {@link #setTranslationY(float) translationY} property plus the current 13380 * {@link #getTop() top} property. 13381 * 13382 * @return The visual y position of this view, in pixels. 13383 */ 13384 @ViewDebug.ExportedProperty(category = "drawing") 13385 public float getY() { 13386 return mTop + getTranslationY(); 13387 } 13388 13389 /** 13390 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 13391 * {@link #setTranslationY(float) translationY} property to be the difference between 13392 * the y value passed in and the current {@link #getTop() top} property. 13393 * 13394 * @param y The visual y position of this view, in pixels. 13395 */ 13396 public void setY(float y) { 13397 setTranslationY(y - mTop); 13398 } 13399 13400 /** 13401 * The visual z position of this view, in pixels. This is equivalent to the 13402 * {@link #setTranslationZ(float) translationZ} property plus the current 13403 * {@link #getElevation() elevation} property. 13404 * 13405 * @return The visual z position of this view, in pixels. 13406 */ 13407 @ViewDebug.ExportedProperty(category = "drawing") 13408 public float getZ() { 13409 return getElevation() + getTranslationZ(); 13410 } 13411 13412 /** 13413 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 13414 * {@link #setTranslationZ(float) translationZ} property to be the difference between 13415 * the x value passed in and the current {@link #getElevation() elevation} property. 13416 * 13417 * @param z The visual z position of this view, in pixels. 13418 */ 13419 public void setZ(float z) { 13420 setTranslationZ(z - getElevation()); 13421 } 13422 13423 /** 13424 * The base elevation of this view relative to its parent, in pixels. 13425 * 13426 * @return The base depth position of the view, in pixels. 13427 */ 13428 @ViewDebug.ExportedProperty(category = "drawing") 13429 public float getElevation() { 13430 return mRenderNode.getElevation(); 13431 } 13432 13433 /** 13434 * Sets the base elevation of this view, in pixels. 13435 * 13436 * @attr ref android.R.styleable#View_elevation 13437 */ 13438 public void setElevation(float elevation) { 13439 if (elevation != getElevation()) { 13440 invalidateViewProperty(true, false); 13441 mRenderNode.setElevation(elevation); 13442 invalidateViewProperty(false, true); 13443 13444 invalidateParentIfNeededAndWasQuickRejected(); 13445 } 13446 } 13447 13448 /** 13449 * The horizontal location of this view relative to its {@link #getLeft() left} position. 13450 * This position is post-layout, in addition to wherever the object's 13451 * layout placed it. 13452 * 13453 * @return The horizontal position of this view relative to its left position, in pixels. 13454 */ 13455 @ViewDebug.ExportedProperty(category = "drawing") 13456 public float getTranslationX() { 13457 return mRenderNode.getTranslationX(); 13458 } 13459 13460 /** 13461 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 13462 * This effectively positions the object post-layout, in addition to wherever the object's 13463 * layout placed it. 13464 * 13465 * @param translationX The horizontal position of this view relative to its left position, 13466 * in pixels. 13467 * 13468 * @attr ref android.R.styleable#View_translationX 13469 */ 13470 public void setTranslationX(float translationX) { 13471 if (translationX != getTranslationX()) { 13472 invalidateViewProperty(true, false); 13473 mRenderNode.setTranslationX(translationX); 13474 invalidateViewProperty(false, true); 13475 13476 invalidateParentIfNeededAndWasQuickRejected(); 13477 notifySubtreeAccessibilityStateChangedIfNeeded(); 13478 } 13479 } 13480 13481 /** 13482 * The vertical location of this view relative to its {@link #getTop() top} position. 13483 * This position is post-layout, in addition to wherever the object's 13484 * layout placed it. 13485 * 13486 * @return The vertical position of this view relative to its top position, 13487 * in pixels. 13488 */ 13489 @ViewDebug.ExportedProperty(category = "drawing") 13490 public float getTranslationY() { 13491 return mRenderNode.getTranslationY(); 13492 } 13493 13494 /** 13495 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 13496 * This effectively positions the object post-layout, in addition to wherever the object's 13497 * layout placed it. 13498 * 13499 * @param translationY The vertical position of this view relative to its top position, 13500 * in pixels. 13501 * 13502 * @attr ref android.R.styleable#View_translationY 13503 */ 13504 public void setTranslationY(float translationY) { 13505 if (translationY != getTranslationY()) { 13506 invalidateViewProperty(true, false); 13507 mRenderNode.setTranslationY(translationY); 13508 invalidateViewProperty(false, true); 13509 13510 invalidateParentIfNeededAndWasQuickRejected(); 13511 notifySubtreeAccessibilityStateChangedIfNeeded(); 13512 } 13513 } 13514 13515 /** 13516 * The depth location of this view relative to its {@link #getElevation() elevation}. 13517 * 13518 * @return The depth of this view relative to its elevation. 13519 */ 13520 @ViewDebug.ExportedProperty(category = "drawing") 13521 public float getTranslationZ() { 13522 return mRenderNode.getTranslationZ(); 13523 } 13524 13525 /** 13526 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 13527 * 13528 * @attr ref android.R.styleable#View_translationZ 13529 */ 13530 public void setTranslationZ(float translationZ) { 13531 if (translationZ != getTranslationZ()) { 13532 invalidateViewProperty(true, false); 13533 mRenderNode.setTranslationZ(translationZ); 13534 invalidateViewProperty(false, true); 13535 13536 invalidateParentIfNeededAndWasQuickRejected(); 13537 } 13538 } 13539 13540 /** @hide */ 13541 public void setAnimationMatrix(Matrix matrix) { 13542 invalidateViewProperty(true, false); 13543 mRenderNode.setAnimationMatrix(matrix); 13544 invalidateViewProperty(false, true); 13545 13546 invalidateParentIfNeededAndWasQuickRejected(); 13547 } 13548 13549 /** 13550 * Returns the current StateListAnimator if exists. 13551 * 13552 * @return StateListAnimator or null if it does not exists 13553 * @see #setStateListAnimator(android.animation.StateListAnimator) 13554 */ 13555 public StateListAnimator getStateListAnimator() { 13556 return mStateListAnimator; 13557 } 13558 13559 /** 13560 * Attaches the provided StateListAnimator to this View. 13561 * <p> 13562 * Any previously attached StateListAnimator will be detached. 13563 * 13564 * @param stateListAnimator The StateListAnimator to update the view 13565 * @see {@link android.animation.StateListAnimator} 13566 */ 13567 public void setStateListAnimator(StateListAnimator stateListAnimator) { 13568 if (mStateListAnimator == stateListAnimator) { 13569 return; 13570 } 13571 if (mStateListAnimator != null) { 13572 mStateListAnimator.setTarget(null); 13573 } 13574 mStateListAnimator = stateListAnimator; 13575 if (stateListAnimator != null) { 13576 stateListAnimator.setTarget(this); 13577 if (isAttachedToWindow()) { 13578 stateListAnimator.setState(getDrawableState()); 13579 } 13580 } 13581 } 13582 13583 /** 13584 * Returns whether the Outline should be used to clip the contents of the View. 13585 * <p> 13586 * Note that this flag will only be respected if the View's Outline returns true from 13587 * {@link Outline#canClip()}. 13588 * 13589 * @see #setOutlineProvider(ViewOutlineProvider) 13590 * @see #setClipToOutline(boolean) 13591 */ 13592 public final boolean getClipToOutline() { 13593 return mRenderNode.getClipToOutline(); 13594 } 13595 13596 /** 13597 * Sets whether the View's Outline should be used to clip the contents of the View. 13598 * <p> 13599 * Only a single non-rectangular clip can be applied on a View at any time. 13600 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 13601 * circular reveal} animation take priority over Outline clipping, and 13602 * child Outline clipping takes priority over Outline clipping done by a 13603 * parent. 13604 * <p> 13605 * Note that this flag will only be respected if the View's Outline returns true from 13606 * {@link Outline#canClip()}. 13607 * 13608 * @see #setOutlineProvider(ViewOutlineProvider) 13609 * @see #getClipToOutline() 13610 */ 13611 public void setClipToOutline(boolean clipToOutline) { 13612 damageInParent(); 13613 if (getClipToOutline() != clipToOutline) { 13614 mRenderNode.setClipToOutline(clipToOutline); 13615 } 13616 } 13617 13618 // correspond to the enum values of View_outlineProvider 13619 private static final int PROVIDER_BACKGROUND = 0; 13620 private static final int PROVIDER_NONE = 1; 13621 private static final int PROVIDER_BOUNDS = 2; 13622 private static final int PROVIDER_PADDED_BOUNDS = 3; 13623 private void setOutlineProviderFromAttribute(int providerInt) { 13624 switch (providerInt) { 13625 case PROVIDER_BACKGROUND: 13626 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 13627 break; 13628 case PROVIDER_NONE: 13629 setOutlineProvider(null); 13630 break; 13631 case PROVIDER_BOUNDS: 13632 setOutlineProvider(ViewOutlineProvider.BOUNDS); 13633 break; 13634 case PROVIDER_PADDED_BOUNDS: 13635 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 13636 break; 13637 } 13638 } 13639 13640 /** 13641 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 13642 * the shape of the shadow it casts, and enables outline clipping. 13643 * <p> 13644 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 13645 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 13646 * outline provider with this method allows this behavior to be overridden. 13647 * <p> 13648 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 13649 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 13650 * <p> 13651 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 13652 * 13653 * @see #setClipToOutline(boolean) 13654 * @see #getClipToOutline() 13655 * @see #getOutlineProvider() 13656 */ 13657 public void setOutlineProvider(ViewOutlineProvider provider) { 13658 mOutlineProvider = provider; 13659 invalidateOutline(); 13660 } 13661 13662 /** 13663 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 13664 * that defines the shape of the shadow it casts, and enables outline clipping. 13665 * 13666 * @see #setOutlineProvider(ViewOutlineProvider) 13667 */ 13668 public ViewOutlineProvider getOutlineProvider() { 13669 return mOutlineProvider; 13670 } 13671 13672 /** 13673 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 13674 * 13675 * @see #setOutlineProvider(ViewOutlineProvider) 13676 */ 13677 public void invalidateOutline() { 13678 rebuildOutline(); 13679 13680 notifySubtreeAccessibilityStateChangedIfNeeded(); 13681 invalidateViewProperty(false, false); 13682 } 13683 13684 /** 13685 * Internal version of {@link #invalidateOutline()} which invalidates the 13686 * outline without invalidating the view itself. This is intended to be called from 13687 * within methods in the View class itself which are the result of the view being 13688 * invalidated already. For example, when we are drawing the background of a View, 13689 * we invalidate the outline in case it changed in the meantime, but we do not 13690 * need to invalidate the view because we're already drawing the background as part 13691 * of drawing the view in response to an earlier invalidation of the view. 13692 */ 13693 private void rebuildOutline() { 13694 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 13695 if (mAttachInfo == null) return; 13696 13697 if (mOutlineProvider == null) { 13698 // no provider, remove outline 13699 mRenderNode.setOutline(null); 13700 } else { 13701 final Outline outline = mAttachInfo.mTmpOutline; 13702 outline.setEmpty(); 13703 outline.setAlpha(1.0f); 13704 13705 mOutlineProvider.getOutline(this, outline); 13706 mRenderNode.setOutline(outline); 13707 } 13708 } 13709 13710 /** 13711 * HierarchyViewer only 13712 * 13713 * @hide 13714 */ 13715 @ViewDebug.ExportedProperty(category = "drawing") 13716 public boolean hasShadow() { 13717 return mRenderNode.hasShadow(); 13718 } 13719 13720 13721 /** @hide */ 13722 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 13723 mRenderNode.setRevealClip(shouldClip, x, y, radius); 13724 invalidateViewProperty(false, false); 13725 } 13726 13727 /** 13728 * Hit rectangle in parent's coordinates 13729 * 13730 * @param outRect The hit rectangle of the view. 13731 */ 13732 public void getHitRect(Rect outRect) { 13733 if (hasIdentityMatrix() || mAttachInfo == null) { 13734 outRect.set(mLeft, mTop, mRight, mBottom); 13735 } else { 13736 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 13737 tmpRect.set(0, 0, getWidth(), getHeight()); 13738 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 13739 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 13740 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 13741 } 13742 } 13743 13744 /** 13745 * Determines whether the given point, in local coordinates is inside the view. 13746 */ 13747 /*package*/ final boolean pointInView(float localX, float localY) { 13748 return pointInView(localX, localY, 0); 13749 } 13750 13751 /** 13752 * Utility method to determine whether the given point, in local coordinates, 13753 * is inside the view, where the area of the view is expanded by the slop factor. 13754 * This method is called while processing touch-move events to determine if the event 13755 * is still within the view. 13756 * 13757 * @hide 13758 */ 13759 public boolean pointInView(float localX, float localY, float slop) { 13760 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 13761 localY < ((mBottom - mTop) + slop); 13762 } 13763 13764 /** 13765 * When a view has focus and the user navigates away from it, the next view is searched for 13766 * starting from the rectangle filled in by this method. 13767 * 13768 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 13769 * of the view. However, if your view maintains some idea of internal selection, 13770 * such as a cursor, or a selected row or column, you should override this method and 13771 * fill in a more specific rectangle. 13772 * 13773 * @param r The rectangle to fill in, in this view's coordinates. 13774 */ 13775 public void getFocusedRect(Rect r) { 13776 getDrawingRect(r); 13777 } 13778 13779 /** 13780 * If some part of this view is not clipped by any of its parents, then 13781 * return that area in r in global (root) coordinates. To convert r to local 13782 * coordinates (without taking possible View rotations into account), offset 13783 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 13784 * If the view is completely clipped or translated out, return false. 13785 * 13786 * @param r If true is returned, r holds the global coordinates of the 13787 * visible portion of this view. 13788 * @param globalOffset If true is returned, globalOffset holds the dx,dy 13789 * between this view and its root. globalOffet may be null. 13790 * @return true if r is non-empty (i.e. part of the view is visible at the 13791 * root level. 13792 */ 13793 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 13794 int width = mRight - mLeft; 13795 int height = mBottom - mTop; 13796 if (width > 0 && height > 0) { 13797 r.set(0, 0, width, height); 13798 if (globalOffset != null) { 13799 globalOffset.set(-mScrollX, -mScrollY); 13800 } 13801 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 13802 } 13803 return false; 13804 } 13805 13806 public final boolean getGlobalVisibleRect(Rect r) { 13807 return getGlobalVisibleRect(r, null); 13808 } 13809 13810 public final boolean getLocalVisibleRect(Rect r) { 13811 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 13812 if (getGlobalVisibleRect(r, offset)) { 13813 r.offset(-offset.x, -offset.y); // make r local 13814 return true; 13815 } 13816 return false; 13817 } 13818 13819 /** 13820 * Offset this view's vertical location by the specified number of pixels. 13821 * 13822 * @param offset the number of pixels to offset the view by 13823 */ 13824 public void offsetTopAndBottom(int offset) { 13825 if (offset != 0) { 13826 final boolean matrixIsIdentity = hasIdentityMatrix(); 13827 if (matrixIsIdentity) { 13828 if (isHardwareAccelerated()) { 13829 invalidateViewProperty(false, false); 13830 } else { 13831 final ViewParent p = mParent; 13832 if (p != null && mAttachInfo != null) { 13833 final Rect r = mAttachInfo.mTmpInvalRect; 13834 int minTop; 13835 int maxBottom; 13836 int yLoc; 13837 if (offset < 0) { 13838 minTop = mTop + offset; 13839 maxBottom = mBottom; 13840 yLoc = offset; 13841 } else { 13842 minTop = mTop; 13843 maxBottom = mBottom + offset; 13844 yLoc = 0; 13845 } 13846 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 13847 p.invalidateChild(this, r); 13848 } 13849 } 13850 } else { 13851 invalidateViewProperty(false, false); 13852 } 13853 13854 mTop += offset; 13855 mBottom += offset; 13856 mRenderNode.offsetTopAndBottom(offset); 13857 if (isHardwareAccelerated()) { 13858 invalidateViewProperty(false, false); 13859 invalidateParentIfNeededAndWasQuickRejected(); 13860 } else { 13861 if (!matrixIsIdentity) { 13862 invalidateViewProperty(false, true); 13863 } 13864 invalidateParentIfNeeded(); 13865 } 13866 notifySubtreeAccessibilityStateChangedIfNeeded(); 13867 } 13868 } 13869 13870 /** 13871 * Offset this view's horizontal location by the specified amount of pixels. 13872 * 13873 * @param offset the number of pixels to offset the view by 13874 */ 13875 public void offsetLeftAndRight(int offset) { 13876 if (offset != 0) { 13877 final boolean matrixIsIdentity = hasIdentityMatrix(); 13878 if (matrixIsIdentity) { 13879 if (isHardwareAccelerated()) { 13880 invalidateViewProperty(false, false); 13881 } else { 13882 final ViewParent p = mParent; 13883 if (p != null && mAttachInfo != null) { 13884 final Rect r = mAttachInfo.mTmpInvalRect; 13885 int minLeft; 13886 int maxRight; 13887 if (offset < 0) { 13888 minLeft = mLeft + offset; 13889 maxRight = mRight; 13890 } else { 13891 minLeft = mLeft; 13892 maxRight = mRight + offset; 13893 } 13894 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 13895 p.invalidateChild(this, r); 13896 } 13897 } 13898 } else { 13899 invalidateViewProperty(false, false); 13900 } 13901 13902 mLeft += offset; 13903 mRight += offset; 13904 mRenderNode.offsetLeftAndRight(offset); 13905 if (isHardwareAccelerated()) { 13906 invalidateViewProperty(false, false); 13907 invalidateParentIfNeededAndWasQuickRejected(); 13908 } else { 13909 if (!matrixIsIdentity) { 13910 invalidateViewProperty(false, true); 13911 } 13912 invalidateParentIfNeeded(); 13913 } 13914 notifySubtreeAccessibilityStateChangedIfNeeded(); 13915 } 13916 } 13917 13918 /** 13919 * Get the LayoutParams associated with this view. All views should have 13920 * layout parameters. These supply parameters to the <i>parent</i> of this 13921 * view specifying how it should be arranged. There are many subclasses of 13922 * ViewGroup.LayoutParams, and these correspond to the different subclasses 13923 * of ViewGroup that are responsible for arranging their children. 13924 * 13925 * This method may return null if this View is not attached to a parent 13926 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 13927 * was not invoked successfully. When a View is attached to a parent 13928 * ViewGroup, this method must not return null. 13929 * 13930 * @return The LayoutParams associated with this view, or null if no 13931 * parameters have been set yet 13932 */ 13933 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 13934 public ViewGroup.LayoutParams getLayoutParams() { 13935 return mLayoutParams; 13936 } 13937 13938 /** 13939 * Set the layout parameters associated with this view. These supply 13940 * parameters to the <i>parent</i> of this view specifying how it should be 13941 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 13942 * correspond to the different subclasses of ViewGroup that are responsible 13943 * for arranging their children. 13944 * 13945 * @param params The layout parameters for this view, cannot be null 13946 */ 13947 public void setLayoutParams(ViewGroup.LayoutParams params) { 13948 if (params == null) { 13949 throw new NullPointerException("Layout parameters cannot be null"); 13950 } 13951 mLayoutParams = params; 13952 resolveLayoutParams(); 13953 if (mParent instanceof ViewGroup) { 13954 ((ViewGroup) mParent).onSetLayoutParams(this, params); 13955 } 13956 requestLayout(); 13957 } 13958 13959 /** 13960 * Resolve the layout parameters depending on the resolved layout direction 13961 * 13962 * @hide 13963 */ 13964 public void resolveLayoutParams() { 13965 if (mLayoutParams != null) { 13966 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 13967 } 13968 } 13969 13970 /** 13971 * Set the scrolled position of your view. This will cause a call to 13972 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13973 * invalidated. 13974 * @param x the x position to scroll to 13975 * @param y the y position to scroll to 13976 */ 13977 public void scrollTo(int x, int y) { 13978 if (mScrollX != x || mScrollY != y) { 13979 int oldX = mScrollX; 13980 int oldY = mScrollY; 13981 mScrollX = x; 13982 mScrollY = y; 13983 invalidateParentCaches(); 13984 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 13985 if (!awakenScrollBars()) { 13986 postInvalidateOnAnimation(); 13987 } 13988 } 13989 } 13990 13991 /** 13992 * Move the scrolled position of your view. This will cause a call to 13993 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13994 * invalidated. 13995 * @param x the amount of pixels to scroll by horizontally 13996 * @param y the amount of pixels to scroll by vertically 13997 */ 13998 public void scrollBy(int x, int y) { 13999 scrollTo(mScrollX + x, mScrollY + y); 14000 } 14001 14002 /** 14003 * <p>Trigger the scrollbars to draw. When invoked this method starts an 14004 * animation to fade the scrollbars out after a default delay. If a subclass 14005 * provides animated scrolling, the start delay should equal the duration 14006 * of the scrolling animation.</p> 14007 * 14008 * <p>The animation starts only if at least one of the scrollbars is 14009 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 14010 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14011 * this method returns true, and false otherwise. If the animation is 14012 * started, this method calls {@link #invalidate()}; in that case the 14013 * caller should not call {@link #invalidate()}.</p> 14014 * 14015 * <p>This method should be invoked every time a subclass directly updates 14016 * the scroll parameters.</p> 14017 * 14018 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 14019 * and {@link #scrollTo(int, int)}.</p> 14020 * 14021 * @return true if the animation is played, false otherwise 14022 * 14023 * @see #awakenScrollBars(int) 14024 * @see #scrollBy(int, int) 14025 * @see #scrollTo(int, int) 14026 * @see #isHorizontalScrollBarEnabled() 14027 * @see #isVerticalScrollBarEnabled() 14028 * @see #setHorizontalScrollBarEnabled(boolean) 14029 * @see #setVerticalScrollBarEnabled(boolean) 14030 */ 14031 protected boolean awakenScrollBars() { 14032 return mScrollCache != null && 14033 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 14034 } 14035 14036 /** 14037 * Trigger the scrollbars to draw. 14038 * This method differs from awakenScrollBars() only in its default duration. 14039 * initialAwakenScrollBars() will show the scroll bars for longer than 14040 * usual to give the user more of a chance to notice them. 14041 * 14042 * @return true if the animation is played, false otherwise. 14043 */ 14044 private boolean initialAwakenScrollBars() { 14045 return mScrollCache != null && 14046 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 14047 } 14048 14049 /** 14050 * <p> 14051 * Trigger the scrollbars to draw. When invoked this method starts an 14052 * animation to fade the scrollbars out after a fixed delay. If a subclass 14053 * provides animated scrolling, the start delay should equal the duration of 14054 * the scrolling animation. 14055 * </p> 14056 * 14057 * <p> 14058 * The animation starts only if at least one of the scrollbars is enabled, 14059 * as specified by {@link #isHorizontalScrollBarEnabled()} and 14060 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14061 * this method returns true, and false otherwise. If the animation is 14062 * started, this method calls {@link #invalidate()}; in that case the caller 14063 * should not call {@link #invalidate()}. 14064 * </p> 14065 * 14066 * <p> 14067 * This method should be invoked every time a subclass directly updates the 14068 * scroll parameters. 14069 * </p> 14070 * 14071 * @param startDelay the delay, in milliseconds, after which the animation 14072 * should start; when the delay is 0, the animation starts 14073 * immediately 14074 * @return true if the animation is played, false otherwise 14075 * 14076 * @see #scrollBy(int, int) 14077 * @see #scrollTo(int, int) 14078 * @see #isHorizontalScrollBarEnabled() 14079 * @see #isVerticalScrollBarEnabled() 14080 * @see #setHorizontalScrollBarEnabled(boolean) 14081 * @see #setVerticalScrollBarEnabled(boolean) 14082 */ 14083 protected boolean awakenScrollBars(int startDelay) { 14084 return awakenScrollBars(startDelay, true); 14085 } 14086 14087 /** 14088 * <p> 14089 * Trigger the scrollbars to draw. When invoked this method starts an 14090 * animation to fade the scrollbars out after a fixed delay. If a subclass 14091 * provides animated scrolling, the start delay should equal the duration of 14092 * the scrolling animation. 14093 * </p> 14094 * 14095 * <p> 14096 * The animation starts only if at least one of the scrollbars is enabled, 14097 * as specified by {@link #isHorizontalScrollBarEnabled()} and 14098 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14099 * this method returns true, and false otherwise. If the animation is 14100 * started, this method calls {@link #invalidate()} if the invalidate parameter 14101 * is set to true; in that case the caller 14102 * should not call {@link #invalidate()}. 14103 * </p> 14104 * 14105 * <p> 14106 * This method should be invoked every time a subclass directly updates the 14107 * scroll parameters. 14108 * </p> 14109 * 14110 * @param startDelay the delay, in milliseconds, after which the animation 14111 * should start; when the delay is 0, the animation starts 14112 * immediately 14113 * 14114 * @param invalidate Whether this method should call invalidate 14115 * 14116 * @return true if the animation is played, false otherwise 14117 * 14118 * @see #scrollBy(int, int) 14119 * @see #scrollTo(int, int) 14120 * @see #isHorizontalScrollBarEnabled() 14121 * @see #isVerticalScrollBarEnabled() 14122 * @see #setHorizontalScrollBarEnabled(boolean) 14123 * @see #setVerticalScrollBarEnabled(boolean) 14124 */ 14125 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 14126 final ScrollabilityCache scrollCache = mScrollCache; 14127 14128 if (scrollCache == null || !scrollCache.fadeScrollBars) { 14129 return false; 14130 } 14131 14132 if (scrollCache.scrollBar == null) { 14133 scrollCache.scrollBar = new ScrollBarDrawable(); 14134 scrollCache.scrollBar.setState(getDrawableState()); 14135 scrollCache.scrollBar.setCallback(this); 14136 } 14137 14138 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 14139 14140 if (invalidate) { 14141 // Invalidate to show the scrollbars 14142 postInvalidateOnAnimation(); 14143 } 14144 14145 if (scrollCache.state == ScrollabilityCache.OFF) { 14146 // FIXME: this is copied from WindowManagerService. 14147 // We should get this value from the system when it 14148 // is possible to do so. 14149 final int KEY_REPEAT_FIRST_DELAY = 750; 14150 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 14151 } 14152 14153 // Tell mScrollCache when we should start fading. This may 14154 // extend the fade start time if one was already scheduled 14155 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 14156 scrollCache.fadeStartTime = fadeStartTime; 14157 scrollCache.state = ScrollabilityCache.ON; 14158 14159 // Schedule our fader to run, unscheduling any old ones first 14160 if (mAttachInfo != null) { 14161 mAttachInfo.mHandler.removeCallbacks(scrollCache); 14162 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 14163 } 14164 14165 return true; 14166 } 14167 14168 return false; 14169 } 14170 14171 /** 14172 * Do not invalidate views which are not visible and which are not running an animation. They 14173 * will not get drawn and they should not set dirty flags as if they will be drawn 14174 */ 14175 private boolean skipInvalidate() { 14176 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 14177 (!(mParent instanceof ViewGroup) || 14178 !((ViewGroup) mParent).isViewTransitioning(this)); 14179 } 14180 14181 /** 14182 * Mark the area defined by dirty as needing to be drawn. If the view is 14183 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14184 * point in the future. 14185 * <p> 14186 * This must be called from a UI thread. To call from a non-UI thread, call 14187 * {@link #postInvalidate()}. 14188 * <p> 14189 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 14190 * {@code dirty}. 14191 * 14192 * @param dirty the rectangle representing the bounds of the dirty region 14193 */ 14194 public void invalidate(Rect dirty) { 14195 final int scrollX = mScrollX; 14196 final int scrollY = mScrollY; 14197 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 14198 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 14199 } 14200 14201 /** 14202 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 14203 * coordinates of the dirty rect are relative to the view. If the view is 14204 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14205 * point in the future. 14206 * <p> 14207 * This must be called from a UI thread. To call from a non-UI thread, call 14208 * {@link #postInvalidate()}. 14209 * 14210 * @param l the left position of the dirty region 14211 * @param t the top position of the dirty region 14212 * @param r the right position of the dirty region 14213 * @param b the bottom position of the dirty region 14214 */ 14215 public void invalidate(int l, int t, int r, int b) { 14216 final int scrollX = mScrollX; 14217 final int scrollY = mScrollY; 14218 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 14219 } 14220 14221 /** 14222 * Invalidate the whole view. If the view is visible, 14223 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 14224 * the future. 14225 * <p> 14226 * This must be called from a UI thread. To call from a non-UI thread, call 14227 * {@link #postInvalidate()}. 14228 */ 14229 public void invalidate() { 14230 invalidate(true); 14231 } 14232 14233 /** 14234 * This is where the invalidate() work actually happens. A full invalidate() 14235 * causes the drawing cache to be invalidated, but this function can be 14236 * called with invalidateCache set to false to skip that invalidation step 14237 * for cases that do not need it (for example, a component that remains at 14238 * the same dimensions with the same content). 14239 * 14240 * @param invalidateCache Whether the drawing cache for this view should be 14241 * invalidated as well. This is usually true for a full 14242 * invalidate, but may be set to false if the View's contents or 14243 * dimensions have not changed. 14244 * @hide 14245 */ 14246 public void invalidate(boolean invalidateCache) { 14247 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 14248 } 14249 14250 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 14251 boolean fullInvalidate) { 14252 if (mGhostView != null) { 14253 mGhostView.invalidate(true); 14254 return; 14255 } 14256 14257 if (skipInvalidate()) { 14258 return; 14259 } 14260 14261 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 14262 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 14263 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 14264 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 14265 if (fullInvalidate) { 14266 mLastIsOpaque = isOpaque(); 14267 mPrivateFlags &= ~PFLAG_DRAWN; 14268 } 14269 14270 mPrivateFlags |= PFLAG_DIRTY; 14271 14272 if (invalidateCache) { 14273 mPrivateFlags |= PFLAG_INVALIDATED; 14274 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 14275 } 14276 14277 // Propagate the damage rectangle to the parent view. 14278 final AttachInfo ai = mAttachInfo; 14279 final ViewParent p = mParent; 14280 if (p != null && ai != null && l < r && t < b) { 14281 final Rect damage = ai.mTmpInvalRect; 14282 damage.set(l, t, r, b); 14283 p.invalidateChild(this, damage); 14284 } 14285 14286 // Damage the entire projection receiver, if necessary. 14287 if (mBackground != null && mBackground.isProjected()) { 14288 final View receiver = getProjectionReceiver(); 14289 if (receiver != null) { 14290 receiver.damageInParent(); 14291 } 14292 } 14293 } 14294 } 14295 14296 /** 14297 * @return this view's projection receiver, or {@code null} if none exists 14298 */ 14299 private View getProjectionReceiver() { 14300 ViewParent p = getParent(); 14301 while (p != null && p instanceof View) { 14302 final View v = (View) p; 14303 if (v.isProjectionReceiver()) { 14304 return v; 14305 } 14306 p = p.getParent(); 14307 } 14308 14309 return null; 14310 } 14311 14312 /** 14313 * @return whether the view is a projection receiver 14314 */ 14315 private boolean isProjectionReceiver() { 14316 return mBackground != null; 14317 } 14318 14319 /** 14320 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 14321 * set any flags or handle all of the cases handled by the default invalidation methods. 14322 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 14323 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 14324 * walk up the hierarchy, transforming the dirty rect as necessary. 14325 * 14326 * The method also handles normal invalidation logic if display list properties are not 14327 * being used in this view. The invalidateParent and forceRedraw flags are used by that 14328 * backup approach, to handle these cases used in the various property-setting methods. 14329 * 14330 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 14331 * are not being used in this view 14332 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 14333 * list properties are not being used in this view 14334 */ 14335 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 14336 if (!isHardwareAccelerated() 14337 || !mRenderNode.isValid() 14338 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 14339 if (invalidateParent) { 14340 invalidateParentCaches(); 14341 } 14342 if (forceRedraw) { 14343 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14344 } 14345 invalidate(false); 14346 } else { 14347 damageInParent(); 14348 } 14349 } 14350 14351 /** 14352 * Tells the parent view to damage this view's bounds. 14353 * 14354 * @hide 14355 */ 14356 protected void damageInParent() { 14357 final AttachInfo ai = mAttachInfo; 14358 final ViewParent p = mParent; 14359 if (p != null && ai != null) { 14360 final Rect r = ai.mTmpInvalRect; 14361 r.set(0, 0, mRight - mLeft, mBottom - mTop); 14362 if (mParent instanceof ViewGroup) { 14363 ((ViewGroup) mParent).damageChild(this, r); 14364 } else { 14365 mParent.invalidateChild(this, r); 14366 } 14367 } 14368 } 14369 14370 /** 14371 * Utility method to transform a given Rect by the current matrix of this view. 14372 */ 14373 void transformRect(final Rect rect) { 14374 if (!getMatrix().isIdentity()) { 14375 RectF boundingRect = mAttachInfo.mTmpTransformRect; 14376 boundingRect.set(rect); 14377 getMatrix().mapRect(boundingRect); 14378 rect.set((int) Math.floor(boundingRect.left), 14379 (int) Math.floor(boundingRect.top), 14380 (int) Math.ceil(boundingRect.right), 14381 (int) Math.ceil(boundingRect.bottom)); 14382 } 14383 } 14384 14385 /** 14386 * Used to indicate that the parent of this view should clear its caches. This functionality 14387 * is used to force the parent to rebuild its display list (when hardware-accelerated), 14388 * which is necessary when various parent-managed properties of the view change, such as 14389 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 14390 * clears the parent caches and does not causes an invalidate event. 14391 * 14392 * @hide 14393 */ 14394 protected void invalidateParentCaches() { 14395 if (mParent instanceof View) { 14396 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 14397 } 14398 } 14399 14400 /** 14401 * Used to indicate that the parent of this view should be invalidated. This functionality 14402 * is used to force the parent to rebuild its display list (when hardware-accelerated), 14403 * which is necessary when various parent-managed properties of the view change, such as 14404 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 14405 * an invalidation event to the parent. 14406 * 14407 * @hide 14408 */ 14409 protected void invalidateParentIfNeeded() { 14410 if (isHardwareAccelerated() && mParent instanceof View) { 14411 ((View) mParent).invalidate(true); 14412 } 14413 } 14414 14415 /** 14416 * @hide 14417 */ 14418 protected void invalidateParentIfNeededAndWasQuickRejected() { 14419 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 14420 // View was rejected last time it was drawn by its parent; this may have changed 14421 invalidateParentIfNeeded(); 14422 } 14423 } 14424 14425 /** 14426 * Indicates whether this View is opaque. An opaque View guarantees that it will 14427 * draw all the pixels overlapping its bounds using a fully opaque color. 14428 * 14429 * Subclasses of View should override this method whenever possible to indicate 14430 * whether an instance is opaque. Opaque Views are treated in a special way by 14431 * the View hierarchy, possibly allowing it to perform optimizations during 14432 * invalidate/draw passes. 14433 * 14434 * @return True if this View is guaranteed to be fully opaque, false otherwise. 14435 */ 14436 @ViewDebug.ExportedProperty(category = "drawing") 14437 public boolean isOpaque() { 14438 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 14439 getFinalAlpha() >= 1.0f; 14440 } 14441 14442 /** 14443 * @hide 14444 */ 14445 protected void computeOpaqueFlags() { 14446 // Opaque if: 14447 // - Has a background 14448 // - Background is opaque 14449 // - Doesn't have scrollbars or scrollbars overlay 14450 14451 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 14452 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 14453 } else { 14454 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 14455 } 14456 14457 final int flags = mViewFlags; 14458 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 14459 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 14460 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 14461 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 14462 } else { 14463 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 14464 } 14465 } 14466 14467 /** 14468 * @hide 14469 */ 14470 protected boolean hasOpaqueScrollbars() { 14471 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 14472 } 14473 14474 /** 14475 * @return A handler associated with the thread running the View. This 14476 * handler can be used to pump events in the UI events queue. 14477 */ 14478 public Handler getHandler() { 14479 final AttachInfo attachInfo = mAttachInfo; 14480 if (attachInfo != null) { 14481 return attachInfo.mHandler; 14482 } 14483 return null; 14484 } 14485 14486 /** 14487 * Returns the queue of runnable for this view. 14488 * 14489 * @return the queue of runnables for this view 14490 */ 14491 private HandlerActionQueue getRunQueue() { 14492 if (mRunQueue == null) { 14493 mRunQueue = new HandlerActionQueue(); 14494 } 14495 return mRunQueue; 14496 } 14497 14498 /** 14499 * Gets the view root associated with the View. 14500 * @return The view root, or null if none. 14501 * @hide 14502 */ 14503 public ViewRootImpl getViewRootImpl() { 14504 if (mAttachInfo != null) { 14505 return mAttachInfo.mViewRootImpl; 14506 } 14507 return null; 14508 } 14509 14510 /** 14511 * @hide 14512 */ 14513 public ThreadedRenderer getThreadedRenderer() { 14514 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 14515 } 14516 14517 /** 14518 * <p>Causes the Runnable to be added to the message queue. 14519 * The runnable will be run on the user interface thread.</p> 14520 * 14521 * @param action The Runnable that will be executed. 14522 * 14523 * @return Returns true if the Runnable was successfully placed in to the 14524 * message queue. Returns false on failure, usually because the 14525 * looper processing the message queue is exiting. 14526 * 14527 * @see #postDelayed 14528 * @see #removeCallbacks 14529 */ 14530 public boolean post(Runnable action) { 14531 final AttachInfo attachInfo = mAttachInfo; 14532 if (attachInfo != null) { 14533 return attachInfo.mHandler.post(action); 14534 } 14535 14536 // Postpone the runnable until we know on which thread it needs to run. 14537 // Assume that the runnable will be successfully placed after attach. 14538 getRunQueue().post(action); 14539 return true; 14540 } 14541 14542 /** 14543 * <p>Causes the Runnable to be added to the message queue, to be run 14544 * after the specified amount of time elapses. 14545 * The runnable will be run on the user interface thread.</p> 14546 * 14547 * @param action The Runnable that will be executed. 14548 * @param delayMillis The delay (in milliseconds) until the Runnable 14549 * will be executed. 14550 * 14551 * @return true if the Runnable was successfully placed in to the 14552 * message queue. Returns false on failure, usually because the 14553 * looper processing the message queue is exiting. Note that a 14554 * result of true does not mean the Runnable will be processed -- 14555 * if the looper is quit before the delivery time of the message 14556 * occurs then the message will be dropped. 14557 * 14558 * @see #post 14559 * @see #removeCallbacks 14560 */ 14561 public boolean postDelayed(Runnable action, long delayMillis) { 14562 final AttachInfo attachInfo = mAttachInfo; 14563 if (attachInfo != null) { 14564 return attachInfo.mHandler.postDelayed(action, delayMillis); 14565 } 14566 14567 // Postpone the runnable until we know on which thread it needs to run. 14568 // Assume that the runnable will be successfully placed after attach. 14569 getRunQueue().postDelayed(action, delayMillis); 14570 return true; 14571 } 14572 14573 /** 14574 * <p>Causes the Runnable to execute on the next animation time step. 14575 * The runnable will be run on the user interface thread.</p> 14576 * 14577 * @param action The Runnable that will be executed. 14578 * 14579 * @see #postOnAnimationDelayed 14580 * @see #removeCallbacks 14581 */ 14582 public void postOnAnimation(Runnable action) { 14583 final AttachInfo attachInfo = mAttachInfo; 14584 if (attachInfo != null) { 14585 attachInfo.mViewRootImpl.mChoreographer.postCallback( 14586 Choreographer.CALLBACK_ANIMATION, action, null); 14587 } else { 14588 // Postpone the runnable until we know 14589 // on which thread it needs to run. 14590 getRunQueue().post(action); 14591 } 14592 } 14593 14594 /** 14595 * <p>Causes the Runnable to execute on the next animation time step, 14596 * after the specified amount of time elapses. 14597 * The runnable will be run on the user interface thread.</p> 14598 * 14599 * @param action The Runnable that will be executed. 14600 * @param delayMillis The delay (in milliseconds) until the Runnable 14601 * will be executed. 14602 * 14603 * @see #postOnAnimation 14604 * @see #removeCallbacks 14605 */ 14606 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 14607 final AttachInfo attachInfo = mAttachInfo; 14608 if (attachInfo != null) { 14609 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 14610 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 14611 } else { 14612 // Postpone the runnable until we know 14613 // on which thread it needs to run. 14614 getRunQueue().postDelayed(action, delayMillis); 14615 } 14616 } 14617 14618 /** 14619 * <p>Removes the specified Runnable from the message queue.</p> 14620 * 14621 * @param action The Runnable to remove from the message handling queue 14622 * 14623 * @return true if this view could ask the Handler to remove the Runnable, 14624 * false otherwise. When the returned value is true, the Runnable 14625 * may or may not have been actually removed from the message queue 14626 * (for instance, if the Runnable was not in the queue already.) 14627 * 14628 * @see #post 14629 * @see #postDelayed 14630 * @see #postOnAnimation 14631 * @see #postOnAnimationDelayed 14632 */ 14633 public boolean removeCallbacks(Runnable action) { 14634 if (action != null) { 14635 final AttachInfo attachInfo = mAttachInfo; 14636 if (attachInfo != null) { 14637 attachInfo.mHandler.removeCallbacks(action); 14638 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 14639 Choreographer.CALLBACK_ANIMATION, action, null); 14640 } 14641 getRunQueue().removeCallbacks(action); 14642 } 14643 return true; 14644 } 14645 14646 /** 14647 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 14648 * Use this to invalidate the View from a non-UI thread.</p> 14649 * 14650 * <p>This method can be invoked from outside of the UI thread 14651 * only when this View is attached to a window.</p> 14652 * 14653 * @see #invalidate() 14654 * @see #postInvalidateDelayed(long) 14655 */ 14656 public void postInvalidate() { 14657 postInvalidateDelayed(0); 14658 } 14659 14660 /** 14661 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14662 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 14663 * 14664 * <p>This method can be invoked from outside of the UI thread 14665 * only when this View is attached to a window.</p> 14666 * 14667 * @param left The left coordinate of the rectangle to invalidate. 14668 * @param top The top coordinate of the rectangle to invalidate. 14669 * @param right The right coordinate of the rectangle to invalidate. 14670 * @param bottom The bottom coordinate of the rectangle to invalidate. 14671 * 14672 * @see #invalidate(int, int, int, int) 14673 * @see #invalidate(Rect) 14674 * @see #postInvalidateDelayed(long, int, int, int, int) 14675 */ 14676 public void postInvalidate(int left, int top, int right, int bottom) { 14677 postInvalidateDelayed(0, left, top, right, bottom); 14678 } 14679 14680 /** 14681 * <p>Cause an invalidate to happen on a subsequent cycle through the event 14682 * loop. Waits for the specified amount of time.</p> 14683 * 14684 * <p>This method can be invoked from outside of the UI thread 14685 * only when this View is attached to a window.</p> 14686 * 14687 * @param delayMilliseconds the duration in milliseconds to delay the 14688 * invalidation by 14689 * 14690 * @see #invalidate() 14691 * @see #postInvalidate() 14692 */ 14693 public void postInvalidateDelayed(long delayMilliseconds) { 14694 // We try only with the AttachInfo because there's no point in invalidating 14695 // if we are not attached to our window 14696 final AttachInfo attachInfo = mAttachInfo; 14697 if (attachInfo != null) { 14698 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 14699 } 14700 } 14701 14702 /** 14703 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14704 * through the event loop. Waits for the specified amount of time.</p> 14705 * 14706 * <p>This method can be invoked from outside of the UI thread 14707 * only when this View is attached to a window.</p> 14708 * 14709 * @param delayMilliseconds the duration in milliseconds to delay the 14710 * invalidation by 14711 * @param left The left coordinate of the rectangle to invalidate. 14712 * @param top The top coordinate of the rectangle to invalidate. 14713 * @param right The right coordinate of the rectangle to invalidate. 14714 * @param bottom The bottom coordinate of the rectangle to invalidate. 14715 * 14716 * @see #invalidate(int, int, int, int) 14717 * @see #invalidate(Rect) 14718 * @see #postInvalidate(int, int, int, int) 14719 */ 14720 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 14721 int right, int bottom) { 14722 14723 // We try only with the AttachInfo because there's no point in invalidating 14724 // if we are not attached to our window 14725 final AttachInfo attachInfo = mAttachInfo; 14726 if (attachInfo != null) { 14727 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14728 info.target = this; 14729 info.left = left; 14730 info.top = top; 14731 info.right = right; 14732 info.bottom = bottom; 14733 14734 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 14735 } 14736 } 14737 14738 /** 14739 * <p>Cause an invalidate to happen on the next animation time step, typically the 14740 * next display frame.</p> 14741 * 14742 * <p>This method can be invoked from outside of the UI thread 14743 * only when this View is attached to a window.</p> 14744 * 14745 * @see #invalidate() 14746 */ 14747 public void postInvalidateOnAnimation() { 14748 // We try only with the AttachInfo because there's no point in invalidating 14749 // if we are not attached to our window 14750 final AttachInfo attachInfo = mAttachInfo; 14751 if (attachInfo != null) { 14752 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 14753 } 14754 } 14755 14756 /** 14757 * <p>Cause an invalidate of the specified area to happen on the next animation 14758 * time step, typically the next display frame.</p> 14759 * 14760 * <p>This method can be invoked from outside of the UI thread 14761 * only when this View is attached to a window.</p> 14762 * 14763 * @param left The left coordinate of the rectangle to invalidate. 14764 * @param top The top coordinate of the rectangle to invalidate. 14765 * @param right The right coordinate of the rectangle to invalidate. 14766 * @param bottom The bottom coordinate of the rectangle to invalidate. 14767 * 14768 * @see #invalidate(int, int, int, int) 14769 * @see #invalidate(Rect) 14770 */ 14771 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 14772 // We try only with the AttachInfo because there's no point in invalidating 14773 // if we are not attached to our window 14774 final AttachInfo attachInfo = mAttachInfo; 14775 if (attachInfo != null) { 14776 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14777 info.target = this; 14778 info.left = left; 14779 info.top = top; 14780 info.right = right; 14781 info.bottom = bottom; 14782 14783 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 14784 } 14785 } 14786 14787 /** 14788 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 14789 * This event is sent at most once every 14790 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 14791 */ 14792 private void postSendViewScrolledAccessibilityEventCallback() { 14793 if (mSendViewScrolledAccessibilityEvent == null) { 14794 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 14795 } 14796 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 14797 mSendViewScrolledAccessibilityEvent.mIsPending = true; 14798 postDelayed(mSendViewScrolledAccessibilityEvent, 14799 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 14800 } 14801 } 14802 14803 /** 14804 * Called by a parent to request that a child update its values for mScrollX 14805 * and mScrollY if necessary. This will typically be done if the child is 14806 * animating a scroll using a {@link android.widget.Scroller Scroller} 14807 * object. 14808 */ 14809 public void computeScroll() { 14810 } 14811 14812 /** 14813 * <p>Indicate whether the horizontal edges are faded when the view is 14814 * scrolled horizontally.</p> 14815 * 14816 * @return true if the horizontal edges should are faded on scroll, false 14817 * otherwise 14818 * 14819 * @see #setHorizontalFadingEdgeEnabled(boolean) 14820 * 14821 * @attr ref android.R.styleable#View_requiresFadingEdge 14822 */ 14823 public boolean isHorizontalFadingEdgeEnabled() { 14824 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 14825 } 14826 14827 /** 14828 * <p>Define whether the horizontal edges should be faded when this view 14829 * is scrolled horizontally.</p> 14830 * 14831 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 14832 * be faded when the view is scrolled 14833 * horizontally 14834 * 14835 * @see #isHorizontalFadingEdgeEnabled() 14836 * 14837 * @attr ref android.R.styleable#View_requiresFadingEdge 14838 */ 14839 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 14840 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 14841 if (horizontalFadingEdgeEnabled) { 14842 initScrollCache(); 14843 } 14844 14845 mViewFlags ^= FADING_EDGE_HORIZONTAL; 14846 } 14847 } 14848 14849 /** 14850 * <p>Indicate whether the vertical edges are faded when the view is 14851 * scrolled horizontally.</p> 14852 * 14853 * @return true if the vertical edges should are faded on scroll, false 14854 * otherwise 14855 * 14856 * @see #setVerticalFadingEdgeEnabled(boolean) 14857 * 14858 * @attr ref android.R.styleable#View_requiresFadingEdge 14859 */ 14860 public boolean isVerticalFadingEdgeEnabled() { 14861 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 14862 } 14863 14864 /** 14865 * <p>Define whether the vertical edges should be faded when this view 14866 * is scrolled vertically.</p> 14867 * 14868 * @param verticalFadingEdgeEnabled true if the vertical edges should 14869 * be faded when the view is scrolled 14870 * vertically 14871 * 14872 * @see #isVerticalFadingEdgeEnabled() 14873 * 14874 * @attr ref android.R.styleable#View_requiresFadingEdge 14875 */ 14876 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 14877 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 14878 if (verticalFadingEdgeEnabled) { 14879 initScrollCache(); 14880 } 14881 14882 mViewFlags ^= FADING_EDGE_VERTICAL; 14883 } 14884 } 14885 14886 /** 14887 * Returns the strength, or intensity, of the top faded edge. The strength is 14888 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14889 * returns 0.0 or 1.0 but no value in between. 14890 * 14891 * Subclasses should override this method to provide a smoother fade transition 14892 * when scrolling occurs. 14893 * 14894 * @return the intensity of the top fade as a float between 0.0f and 1.0f 14895 */ 14896 protected float getTopFadingEdgeStrength() { 14897 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 14898 } 14899 14900 /** 14901 * Returns the strength, or intensity, of the bottom faded edge. The strength is 14902 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14903 * returns 0.0 or 1.0 but no value in between. 14904 * 14905 * Subclasses should override this method to provide a smoother fade transition 14906 * when scrolling occurs. 14907 * 14908 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 14909 */ 14910 protected float getBottomFadingEdgeStrength() { 14911 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 14912 computeVerticalScrollRange() ? 1.0f : 0.0f; 14913 } 14914 14915 /** 14916 * Returns the strength, or intensity, of the left faded edge. The strength is 14917 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14918 * returns 0.0 or 1.0 but no value in between. 14919 * 14920 * Subclasses should override this method to provide a smoother fade transition 14921 * when scrolling occurs. 14922 * 14923 * @return the intensity of the left fade as a float between 0.0f and 1.0f 14924 */ 14925 protected float getLeftFadingEdgeStrength() { 14926 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 14927 } 14928 14929 /** 14930 * Returns the strength, or intensity, of the right faded edge. The strength is 14931 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14932 * returns 0.0 or 1.0 but no value in between. 14933 * 14934 * Subclasses should override this method to provide a smoother fade transition 14935 * when scrolling occurs. 14936 * 14937 * @return the intensity of the right fade as a float between 0.0f and 1.0f 14938 */ 14939 protected float getRightFadingEdgeStrength() { 14940 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 14941 computeHorizontalScrollRange() ? 1.0f : 0.0f; 14942 } 14943 14944 /** 14945 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 14946 * scrollbar is not drawn by default.</p> 14947 * 14948 * @return true if the horizontal scrollbar should be painted, false 14949 * otherwise 14950 * 14951 * @see #setHorizontalScrollBarEnabled(boolean) 14952 */ 14953 public boolean isHorizontalScrollBarEnabled() { 14954 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 14955 } 14956 14957 /** 14958 * <p>Define whether the horizontal scrollbar should be drawn or not. The 14959 * scrollbar is not drawn by default.</p> 14960 * 14961 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 14962 * be painted 14963 * 14964 * @see #isHorizontalScrollBarEnabled() 14965 */ 14966 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 14967 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 14968 mViewFlags ^= SCROLLBARS_HORIZONTAL; 14969 computeOpaqueFlags(); 14970 resolvePadding(); 14971 } 14972 } 14973 14974 /** 14975 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 14976 * scrollbar is not drawn by default.</p> 14977 * 14978 * @return true if the vertical scrollbar should be painted, false 14979 * otherwise 14980 * 14981 * @see #setVerticalScrollBarEnabled(boolean) 14982 */ 14983 public boolean isVerticalScrollBarEnabled() { 14984 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 14985 } 14986 14987 /** 14988 * <p>Define whether the vertical scrollbar should be drawn or not. The 14989 * scrollbar is not drawn by default.</p> 14990 * 14991 * @param verticalScrollBarEnabled true if the vertical scrollbar should 14992 * be painted 14993 * 14994 * @see #isVerticalScrollBarEnabled() 14995 */ 14996 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 14997 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 14998 mViewFlags ^= SCROLLBARS_VERTICAL; 14999 computeOpaqueFlags(); 15000 resolvePadding(); 15001 } 15002 } 15003 15004 /** 15005 * @hide 15006 */ 15007 protected void recomputePadding() { 15008 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 15009 } 15010 15011 /** 15012 * Define whether scrollbars will fade when the view is not scrolling. 15013 * 15014 * @param fadeScrollbars whether to enable fading 15015 * 15016 * @attr ref android.R.styleable#View_fadeScrollbars 15017 */ 15018 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 15019 initScrollCache(); 15020 final ScrollabilityCache scrollabilityCache = mScrollCache; 15021 scrollabilityCache.fadeScrollBars = fadeScrollbars; 15022 if (fadeScrollbars) { 15023 scrollabilityCache.state = ScrollabilityCache.OFF; 15024 } else { 15025 scrollabilityCache.state = ScrollabilityCache.ON; 15026 } 15027 } 15028 15029 /** 15030 * 15031 * Returns true if scrollbars will fade when this view is not scrolling 15032 * 15033 * @return true if scrollbar fading is enabled 15034 * 15035 * @attr ref android.R.styleable#View_fadeScrollbars 15036 */ 15037 public boolean isScrollbarFadingEnabled() { 15038 return mScrollCache != null && mScrollCache.fadeScrollBars; 15039 } 15040 15041 /** 15042 * 15043 * Returns the delay before scrollbars fade. 15044 * 15045 * @return the delay before scrollbars fade 15046 * 15047 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 15048 */ 15049 public int getScrollBarDefaultDelayBeforeFade() { 15050 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 15051 mScrollCache.scrollBarDefaultDelayBeforeFade; 15052 } 15053 15054 /** 15055 * Define the delay before scrollbars fade. 15056 * 15057 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 15058 * 15059 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 15060 */ 15061 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 15062 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 15063 } 15064 15065 /** 15066 * 15067 * Returns the scrollbar fade duration. 15068 * 15069 * @return the scrollbar fade duration, in milliseconds 15070 * 15071 * @attr ref android.R.styleable#View_scrollbarFadeDuration 15072 */ 15073 public int getScrollBarFadeDuration() { 15074 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 15075 mScrollCache.scrollBarFadeDuration; 15076 } 15077 15078 /** 15079 * Define the scrollbar fade duration. 15080 * 15081 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 15082 * 15083 * @attr ref android.R.styleable#View_scrollbarFadeDuration 15084 */ 15085 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 15086 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 15087 } 15088 15089 /** 15090 * 15091 * Returns the scrollbar size. 15092 * 15093 * @return the scrollbar size 15094 * 15095 * @attr ref android.R.styleable#View_scrollbarSize 15096 */ 15097 public int getScrollBarSize() { 15098 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 15099 mScrollCache.scrollBarSize; 15100 } 15101 15102 /** 15103 * Define the scrollbar size. 15104 * 15105 * @param scrollBarSize - the scrollbar size 15106 * 15107 * @attr ref android.R.styleable#View_scrollbarSize 15108 */ 15109 public void setScrollBarSize(int scrollBarSize) { 15110 getScrollCache().scrollBarSize = scrollBarSize; 15111 } 15112 15113 /** 15114 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 15115 * inset. When inset, they add to the padding of the view. And the scrollbars 15116 * can be drawn inside the padding area or on the edge of the view. For example, 15117 * if a view has a background drawable and you want to draw the scrollbars 15118 * inside the padding specified by the drawable, you can use 15119 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 15120 * appear at the edge of the view, ignoring the padding, then you can use 15121 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 15122 * @param style the style of the scrollbars. Should be one of 15123 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 15124 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 15125 * @see #SCROLLBARS_INSIDE_OVERLAY 15126 * @see #SCROLLBARS_INSIDE_INSET 15127 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15128 * @see #SCROLLBARS_OUTSIDE_INSET 15129 * 15130 * @attr ref android.R.styleable#View_scrollbarStyle 15131 */ 15132 public void setScrollBarStyle(@ScrollBarStyle int style) { 15133 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 15134 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 15135 computeOpaqueFlags(); 15136 resolvePadding(); 15137 } 15138 } 15139 15140 /** 15141 * <p>Returns the current scrollbar style.</p> 15142 * @return the current scrollbar style 15143 * @see #SCROLLBARS_INSIDE_OVERLAY 15144 * @see #SCROLLBARS_INSIDE_INSET 15145 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15146 * @see #SCROLLBARS_OUTSIDE_INSET 15147 * 15148 * @attr ref android.R.styleable#View_scrollbarStyle 15149 */ 15150 @ViewDebug.ExportedProperty(mapping = { 15151 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 15152 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 15153 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 15154 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 15155 }) 15156 @ScrollBarStyle 15157 public int getScrollBarStyle() { 15158 return mViewFlags & SCROLLBARS_STYLE_MASK; 15159 } 15160 15161 /** 15162 * <p>Compute the horizontal range that the horizontal scrollbar 15163 * represents.</p> 15164 * 15165 * <p>The range is expressed in arbitrary units that must be the same as the 15166 * units used by {@link #computeHorizontalScrollExtent()} and 15167 * {@link #computeHorizontalScrollOffset()}.</p> 15168 * 15169 * <p>The default range is the drawing width of this view.</p> 15170 * 15171 * @return the total horizontal range represented by the horizontal 15172 * scrollbar 15173 * 15174 * @see #computeHorizontalScrollExtent() 15175 * @see #computeHorizontalScrollOffset() 15176 * @see android.widget.ScrollBarDrawable 15177 */ 15178 protected int computeHorizontalScrollRange() { 15179 return getWidth(); 15180 } 15181 15182 /** 15183 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 15184 * within the horizontal range. This value is used to compute the position 15185 * of the thumb within the scrollbar's track.</p> 15186 * 15187 * <p>The range is expressed in arbitrary units that must be the same as the 15188 * units used by {@link #computeHorizontalScrollRange()} and 15189 * {@link #computeHorizontalScrollExtent()}.</p> 15190 * 15191 * <p>The default offset is the scroll offset of this view.</p> 15192 * 15193 * @return the horizontal offset of the scrollbar's thumb 15194 * 15195 * @see #computeHorizontalScrollRange() 15196 * @see #computeHorizontalScrollExtent() 15197 * @see android.widget.ScrollBarDrawable 15198 */ 15199 protected int computeHorizontalScrollOffset() { 15200 return mScrollX; 15201 } 15202 15203 /** 15204 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 15205 * within the horizontal range. This value is used to compute the length 15206 * of the thumb within the scrollbar's track.</p> 15207 * 15208 * <p>The range is expressed in arbitrary units that must be the same as the 15209 * units used by {@link #computeHorizontalScrollRange()} and 15210 * {@link #computeHorizontalScrollOffset()}.</p> 15211 * 15212 * <p>The default extent is the drawing width of this view.</p> 15213 * 15214 * @return the horizontal extent of the scrollbar's thumb 15215 * 15216 * @see #computeHorizontalScrollRange() 15217 * @see #computeHorizontalScrollOffset() 15218 * @see android.widget.ScrollBarDrawable 15219 */ 15220 protected int computeHorizontalScrollExtent() { 15221 return getWidth(); 15222 } 15223 15224 /** 15225 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 15226 * 15227 * <p>The range is expressed in arbitrary units that must be the same as the 15228 * units used by {@link #computeVerticalScrollExtent()} and 15229 * {@link #computeVerticalScrollOffset()}.</p> 15230 * 15231 * @return the total vertical range represented by the vertical scrollbar 15232 * 15233 * <p>The default range is the drawing height of this view.</p> 15234 * 15235 * @see #computeVerticalScrollExtent() 15236 * @see #computeVerticalScrollOffset() 15237 * @see android.widget.ScrollBarDrawable 15238 */ 15239 protected int computeVerticalScrollRange() { 15240 return getHeight(); 15241 } 15242 15243 /** 15244 * <p>Compute the vertical offset of the vertical scrollbar's thumb 15245 * within the horizontal range. This value is used to compute the position 15246 * of the thumb within the scrollbar's track.</p> 15247 * 15248 * <p>The range is expressed in arbitrary units that must be the same as the 15249 * units used by {@link #computeVerticalScrollRange()} and 15250 * {@link #computeVerticalScrollExtent()}.</p> 15251 * 15252 * <p>The default offset is the scroll offset of this view.</p> 15253 * 15254 * @return the vertical offset of the scrollbar's thumb 15255 * 15256 * @see #computeVerticalScrollRange() 15257 * @see #computeVerticalScrollExtent() 15258 * @see android.widget.ScrollBarDrawable 15259 */ 15260 protected int computeVerticalScrollOffset() { 15261 return mScrollY; 15262 } 15263 15264 /** 15265 * <p>Compute the vertical extent of the vertical scrollbar's thumb 15266 * within the vertical range. This value is used to compute the length 15267 * of the thumb within the scrollbar's track.</p> 15268 * 15269 * <p>The range is expressed in arbitrary units that must be the same as the 15270 * units used by {@link #computeVerticalScrollRange()} and 15271 * {@link #computeVerticalScrollOffset()}.</p> 15272 * 15273 * <p>The default extent is the drawing height of this view.</p> 15274 * 15275 * @return the vertical extent of the scrollbar's thumb 15276 * 15277 * @see #computeVerticalScrollRange() 15278 * @see #computeVerticalScrollOffset() 15279 * @see android.widget.ScrollBarDrawable 15280 */ 15281 protected int computeVerticalScrollExtent() { 15282 return getHeight(); 15283 } 15284 15285 /** 15286 * Check if this view can be scrolled horizontally in a certain direction. 15287 * 15288 * @param direction Negative to check scrolling left, positive to check scrolling right. 15289 * @return true if this view can be scrolled in the specified direction, false otherwise. 15290 */ 15291 public boolean canScrollHorizontally(int direction) { 15292 final int offset = computeHorizontalScrollOffset(); 15293 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 15294 if (range == 0) return false; 15295 if (direction < 0) { 15296 return offset > 0; 15297 } else { 15298 return offset < range - 1; 15299 } 15300 } 15301 15302 /** 15303 * Check if this view can be scrolled vertically in a certain direction. 15304 * 15305 * @param direction Negative to check scrolling up, positive to check scrolling down. 15306 * @return true if this view can be scrolled in the specified direction, false otherwise. 15307 */ 15308 public boolean canScrollVertically(int direction) { 15309 final int offset = computeVerticalScrollOffset(); 15310 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 15311 if (range == 0) return false; 15312 if (direction < 0) { 15313 return offset > 0; 15314 } else { 15315 return offset < range - 1; 15316 } 15317 } 15318 15319 void getScrollIndicatorBounds(@NonNull Rect out) { 15320 out.left = mScrollX; 15321 out.right = mScrollX + mRight - mLeft; 15322 out.top = mScrollY; 15323 out.bottom = mScrollY + mBottom - mTop; 15324 } 15325 15326 private void onDrawScrollIndicators(Canvas c) { 15327 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 15328 // No scroll indicators enabled. 15329 return; 15330 } 15331 15332 final Drawable dr = mScrollIndicatorDrawable; 15333 if (dr == null) { 15334 // Scroll indicators aren't supported here. 15335 return; 15336 } 15337 15338 final int h = dr.getIntrinsicHeight(); 15339 final int w = dr.getIntrinsicWidth(); 15340 final Rect rect = mAttachInfo.mTmpInvalRect; 15341 getScrollIndicatorBounds(rect); 15342 15343 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 15344 final boolean canScrollUp = canScrollVertically(-1); 15345 if (canScrollUp) { 15346 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 15347 dr.draw(c); 15348 } 15349 } 15350 15351 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 15352 final boolean canScrollDown = canScrollVertically(1); 15353 if (canScrollDown) { 15354 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 15355 dr.draw(c); 15356 } 15357 } 15358 15359 final int leftRtl; 15360 final int rightRtl; 15361 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15362 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 15363 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 15364 } else { 15365 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 15366 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 15367 } 15368 15369 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 15370 if ((mPrivateFlags3 & leftMask) != 0) { 15371 final boolean canScrollLeft = canScrollHorizontally(-1); 15372 if (canScrollLeft) { 15373 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 15374 dr.draw(c); 15375 } 15376 } 15377 15378 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 15379 if ((mPrivateFlags3 & rightMask) != 0) { 15380 final boolean canScrollRight = canScrollHorizontally(1); 15381 if (canScrollRight) { 15382 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 15383 dr.draw(c); 15384 } 15385 } 15386 } 15387 15388 private void getHorizontalScrollBarBounds(Rect bounds) { 15389 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 15390 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 15391 && !isVerticalScrollBarHidden(); 15392 final int size = getHorizontalScrollbarHeight(); 15393 final int verticalScrollBarGap = drawVerticalScrollBar ? 15394 getVerticalScrollbarWidth() : 0; 15395 final int width = mRight - mLeft; 15396 final int height = mBottom - mTop; 15397 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 15398 bounds.left = mScrollX + (mPaddingLeft & inside); 15399 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 15400 bounds.bottom = bounds.top + size; 15401 } 15402 15403 private void getVerticalScrollBarBounds(Rect bounds) { 15404 if (mRoundScrollbarRenderer == null) { 15405 getStraightVerticalScrollBarBounds(bounds); 15406 } else { 15407 getRoundVerticalScrollBarBounds(bounds); 15408 } 15409 } 15410 15411 private void getRoundVerticalScrollBarBounds(Rect bounds) { 15412 final int width = mRight - mLeft; 15413 final int height = mBottom - mTop; 15414 // Do not take padding into account as we always want the scrollbars 15415 // to hug the screen for round wearable devices. 15416 bounds.left = mScrollX; 15417 bounds.top = mScrollY; 15418 bounds.right = bounds.left + width; 15419 bounds.bottom = mScrollY + height; 15420 } 15421 15422 private void getStraightVerticalScrollBarBounds(Rect bounds) { 15423 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 15424 final int size = getVerticalScrollbarWidth(); 15425 int verticalScrollbarPosition = mVerticalScrollbarPosition; 15426 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 15427 verticalScrollbarPosition = isLayoutRtl() ? 15428 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 15429 } 15430 final int width = mRight - mLeft; 15431 final int height = mBottom - mTop; 15432 switch (verticalScrollbarPosition) { 15433 default: 15434 case SCROLLBAR_POSITION_RIGHT: 15435 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 15436 break; 15437 case SCROLLBAR_POSITION_LEFT: 15438 bounds.left = mScrollX + (mUserPaddingLeft & inside); 15439 break; 15440 } 15441 bounds.top = mScrollY + (mPaddingTop & inside); 15442 bounds.right = bounds.left + size; 15443 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 15444 } 15445 15446 /** 15447 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 15448 * scrollbars are painted only if they have been awakened first.</p> 15449 * 15450 * @param canvas the canvas on which to draw the scrollbars 15451 * 15452 * @see #awakenScrollBars(int) 15453 */ 15454 protected final void onDrawScrollBars(Canvas canvas) { 15455 // scrollbars are drawn only when the animation is running 15456 final ScrollabilityCache cache = mScrollCache; 15457 15458 if (cache != null) { 15459 15460 int state = cache.state; 15461 15462 if (state == ScrollabilityCache.OFF) { 15463 return; 15464 } 15465 15466 boolean invalidate = false; 15467 15468 if (state == ScrollabilityCache.FADING) { 15469 // We're fading -- get our fade interpolation 15470 if (cache.interpolatorValues == null) { 15471 cache.interpolatorValues = new float[1]; 15472 } 15473 15474 float[] values = cache.interpolatorValues; 15475 15476 // Stops the animation if we're done 15477 if (cache.scrollBarInterpolator.timeToValues(values) == 15478 Interpolator.Result.FREEZE_END) { 15479 cache.state = ScrollabilityCache.OFF; 15480 } else { 15481 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 15482 } 15483 15484 // This will make the scroll bars inval themselves after 15485 // drawing. We only want this when we're fading so that 15486 // we prevent excessive redraws 15487 invalidate = true; 15488 } else { 15489 // We're just on -- but we may have been fading before so 15490 // reset alpha 15491 cache.scrollBar.mutate().setAlpha(255); 15492 } 15493 15494 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 15495 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 15496 && !isVerticalScrollBarHidden(); 15497 15498 // Fork out the scroll bar drawing for round wearable devices. 15499 if (mRoundScrollbarRenderer != null) { 15500 if (drawVerticalScrollBar) { 15501 final Rect bounds = cache.mScrollBarBounds; 15502 getVerticalScrollBarBounds(bounds); 15503 mRoundScrollbarRenderer.drawRoundScrollbars( 15504 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 15505 if (invalidate) { 15506 invalidate(); 15507 } 15508 } 15509 // Do not draw horizontal scroll bars for round wearable devices. 15510 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 15511 final ScrollBarDrawable scrollBar = cache.scrollBar; 15512 15513 if (drawHorizontalScrollBar) { 15514 scrollBar.setParameters(computeHorizontalScrollRange(), 15515 computeHorizontalScrollOffset(), 15516 computeHorizontalScrollExtent(), false); 15517 final Rect bounds = cache.mScrollBarBounds; 15518 getHorizontalScrollBarBounds(bounds); 15519 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 15520 bounds.right, bounds.bottom); 15521 if (invalidate) { 15522 invalidate(bounds); 15523 } 15524 } 15525 15526 if (drawVerticalScrollBar) { 15527 scrollBar.setParameters(computeVerticalScrollRange(), 15528 computeVerticalScrollOffset(), 15529 computeVerticalScrollExtent(), true); 15530 final Rect bounds = cache.mScrollBarBounds; 15531 getVerticalScrollBarBounds(bounds); 15532 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 15533 bounds.right, bounds.bottom); 15534 if (invalidate) { 15535 invalidate(bounds); 15536 } 15537 } 15538 } 15539 } 15540 } 15541 15542 /** 15543 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 15544 * FastScroller is visible. 15545 * @return whether to temporarily hide the vertical scrollbar 15546 * @hide 15547 */ 15548 protected boolean isVerticalScrollBarHidden() { 15549 return false; 15550 } 15551 15552 /** 15553 * <p>Draw the horizontal scrollbar if 15554 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 15555 * 15556 * @param canvas the canvas on which to draw the scrollbar 15557 * @param scrollBar the scrollbar's drawable 15558 * 15559 * @see #isHorizontalScrollBarEnabled() 15560 * @see #computeHorizontalScrollRange() 15561 * @see #computeHorizontalScrollExtent() 15562 * @see #computeHorizontalScrollOffset() 15563 * @see android.widget.ScrollBarDrawable 15564 * @hide 15565 */ 15566 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 15567 int l, int t, int r, int b) { 15568 scrollBar.setBounds(l, t, r, b); 15569 scrollBar.draw(canvas); 15570 } 15571 15572 /** 15573 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 15574 * returns true.</p> 15575 * 15576 * @param canvas the canvas on which to draw the scrollbar 15577 * @param scrollBar the scrollbar's drawable 15578 * 15579 * @see #isVerticalScrollBarEnabled() 15580 * @see #computeVerticalScrollRange() 15581 * @see #computeVerticalScrollExtent() 15582 * @see #computeVerticalScrollOffset() 15583 * @see android.widget.ScrollBarDrawable 15584 * @hide 15585 */ 15586 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 15587 int l, int t, int r, int b) { 15588 scrollBar.setBounds(l, t, r, b); 15589 scrollBar.draw(canvas); 15590 } 15591 15592 /** 15593 * Implement this to do your drawing. 15594 * 15595 * @param canvas the canvas on which the background will be drawn 15596 */ 15597 protected void onDraw(Canvas canvas) { 15598 } 15599 15600 /* 15601 * Caller is responsible for calling requestLayout if necessary. 15602 * (This allows addViewInLayout to not request a new layout.) 15603 */ 15604 void assignParent(ViewParent parent) { 15605 if (mParent == null) { 15606 mParent = parent; 15607 } else if (parent == null) { 15608 mParent = null; 15609 } else { 15610 throw new RuntimeException("view " + this + " being added, but" 15611 + " it already has a parent"); 15612 } 15613 } 15614 15615 /** 15616 * This is called when the view is attached to a window. At this point it 15617 * has a Surface and will start drawing. Note that this function is 15618 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 15619 * however it may be called any time before the first onDraw -- including 15620 * before or after {@link #onMeasure(int, int)}. 15621 * 15622 * @see #onDetachedFromWindow() 15623 */ 15624 @CallSuper 15625 protected void onAttachedToWindow() { 15626 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 15627 mParent.requestTransparentRegion(this); 15628 } 15629 15630 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15631 15632 jumpDrawablesToCurrentState(); 15633 15634 resetSubtreeAccessibilityStateChanged(); 15635 15636 // rebuild, since Outline not maintained while View is detached 15637 rebuildOutline(); 15638 15639 if (isFocused()) { 15640 InputMethodManager imm = InputMethodManager.peekInstance(); 15641 if (imm != null) { 15642 imm.focusIn(this); 15643 } 15644 } 15645 } 15646 15647 /** 15648 * Resolve all RTL related properties. 15649 * 15650 * @return true if resolution of RTL properties has been done 15651 * 15652 * @hide 15653 */ 15654 public boolean resolveRtlPropertiesIfNeeded() { 15655 if (!needRtlPropertiesResolution()) return false; 15656 15657 // Order is important here: LayoutDirection MUST be resolved first 15658 if (!isLayoutDirectionResolved()) { 15659 resolveLayoutDirection(); 15660 resolveLayoutParams(); 15661 } 15662 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 15663 if (!isTextDirectionResolved()) { 15664 resolveTextDirection(); 15665 } 15666 if (!isTextAlignmentResolved()) { 15667 resolveTextAlignment(); 15668 } 15669 // Should resolve Drawables before Padding because we need the layout direction of the 15670 // Drawable to correctly resolve Padding. 15671 if (!areDrawablesResolved()) { 15672 resolveDrawables(); 15673 } 15674 if (!isPaddingResolved()) { 15675 resolvePadding(); 15676 } 15677 onRtlPropertiesChanged(getLayoutDirection()); 15678 return true; 15679 } 15680 15681 /** 15682 * Reset resolution of all RTL related properties. 15683 * 15684 * @hide 15685 */ 15686 public void resetRtlProperties() { 15687 resetResolvedLayoutDirection(); 15688 resetResolvedTextDirection(); 15689 resetResolvedTextAlignment(); 15690 resetResolvedPadding(); 15691 resetResolvedDrawables(); 15692 } 15693 15694 /** 15695 * @see #onScreenStateChanged(int) 15696 */ 15697 void dispatchScreenStateChanged(int screenState) { 15698 onScreenStateChanged(screenState); 15699 } 15700 15701 /** 15702 * This method is called whenever the state of the screen this view is 15703 * attached to changes. A state change will usually occurs when the screen 15704 * turns on or off (whether it happens automatically or the user does it 15705 * manually.) 15706 * 15707 * @param screenState The new state of the screen. Can be either 15708 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 15709 */ 15710 public void onScreenStateChanged(int screenState) { 15711 } 15712 15713 /** 15714 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 15715 */ 15716 private boolean hasRtlSupport() { 15717 return mContext.getApplicationInfo().hasRtlSupport(); 15718 } 15719 15720 /** 15721 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 15722 * RTL not supported) 15723 */ 15724 private boolean isRtlCompatibilityMode() { 15725 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 15726 return targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport(); 15727 } 15728 15729 /** 15730 * @return true if RTL properties need resolution. 15731 * 15732 */ 15733 private boolean needRtlPropertiesResolution() { 15734 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 15735 } 15736 15737 /** 15738 * Called when any RTL property (layout direction or text direction or text alignment) has 15739 * been changed. 15740 * 15741 * Subclasses need to override this method to take care of cached information that depends on the 15742 * resolved layout direction, or to inform child views that inherit their layout direction. 15743 * 15744 * The default implementation does nothing. 15745 * 15746 * @param layoutDirection the direction of the layout 15747 * 15748 * @see #LAYOUT_DIRECTION_LTR 15749 * @see #LAYOUT_DIRECTION_RTL 15750 */ 15751 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 15752 } 15753 15754 /** 15755 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 15756 * that the parent directionality can and will be resolved before its children. 15757 * 15758 * @return true if resolution has been done, false otherwise. 15759 * 15760 * @hide 15761 */ 15762 public boolean resolveLayoutDirection() { 15763 // Clear any previous layout direction resolution 15764 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15765 15766 if (hasRtlSupport()) { 15767 // Set resolved depending on layout direction 15768 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 15769 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 15770 case LAYOUT_DIRECTION_INHERIT: 15771 // We cannot resolve yet. LTR is by default and let the resolution happen again 15772 // later to get the correct resolved value 15773 if (!canResolveLayoutDirection()) return false; 15774 15775 // Parent has not yet resolved, LTR is still the default 15776 try { 15777 if (!mParent.isLayoutDirectionResolved()) return false; 15778 15779 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15780 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15781 } 15782 } catch (AbstractMethodError e) { 15783 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15784 " does not fully implement ViewParent", e); 15785 } 15786 break; 15787 case LAYOUT_DIRECTION_RTL: 15788 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15789 break; 15790 case LAYOUT_DIRECTION_LOCALE: 15791 if((LAYOUT_DIRECTION_RTL == 15792 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 15793 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15794 } 15795 break; 15796 default: 15797 // Nothing to do, LTR by default 15798 } 15799 } 15800 15801 // Set to resolved 15802 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 15803 return true; 15804 } 15805 15806 /** 15807 * Check if layout direction resolution can be done. 15808 * 15809 * @return true if layout direction resolution can be done otherwise return false. 15810 */ 15811 public boolean canResolveLayoutDirection() { 15812 switch (getRawLayoutDirection()) { 15813 case LAYOUT_DIRECTION_INHERIT: 15814 if (mParent != null) { 15815 try { 15816 return mParent.canResolveLayoutDirection(); 15817 } catch (AbstractMethodError e) { 15818 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15819 " does not fully implement ViewParent", e); 15820 } 15821 } 15822 return false; 15823 15824 default: 15825 return true; 15826 } 15827 } 15828 15829 /** 15830 * Reset the resolved layout direction. Layout direction will be resolved during a call to 15831 * {@link #onMeasure(int, int)}. 15832 * 15833 * @hide 15834 */ 15835 public void resetResolvedLayoutDirection() { 15836 // Reset the current resolved bits 15837 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15838 } 15839 15840 /** 15841 * @return true if the layout direction is inherited. 15842 * 15843 * @hide 15844 */ 15845 public boolean isLayoutDirectionInherited() { 15846 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 15847 } 15848 15849 /** 15850 * @return true if layout direction has been resolved. 15851 */ 15852 public boolean isLayoutDirectionResolved() { 15853 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 15854 } 15855 15856 /** 15857 * Return if padding has been resolved 15858 * 15859 * @hide 15860 */ 15861 boolean isPaddingResolved() { 15862 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 15863 } 15864 15865 /** 15866 * Resolves padding depending on layout direction, if applicable, and 15867 * recomputes internal padding values to adjust for scroll bars. 15868 * 15869 * @hide 15870 */ 15871 public void resolvePadding() { 15872 final int resolvedLayoutDirection = getLayoutDirection(); 15873 15874 if (!isRtlCompatibilityMode()) { 15875 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 15876 // If start / end padding are defined, they will be resolved (hence overriding) to 15877 // left / right or right / left depending on the resolved layout direction. 15878 // If start / end padding are not defined, use the left / right ones. 15879 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 15880 Rect padding = sThreadLocal.get(); 15881 if (padding == null) { 15882 padding = new Rect(); 15883 sThreadLocal.set(padding); 15884 } 15885 mBackground.getPadding(padding); 15886 if (!mLeftPaddingDefined) { 15887 mUserPaddingLeftInitial = padding.left; 15888 } 15889 if (!mRightPaddingDefined) { 15890 mUserPaddingRightInitial = padding.right; 15891 } 15892 } 15893 switch (resolvedLayoutDirection) { 15894 case LAYOUT_DIRECTION_RTL: 15895 if (mUserPaddingStart != UNDEFINED_PADDING) { 15896 mUserPaddingRight = mUserPaddingStart; 15897 } else { 15898 mUserPaddingRight = mUserPaddingRightInitial; 15899 } 15900 if (mUserPaddingEnd != UNDEFINED_PADDING) { 15901 mUserPaddingLeft = mUserPaddingEnd; 15902 } else { 15903 mUserPaddingLeft = mUserPaddingLeftInitial; 15904 } 15905 break; 15906 case LAYOUT_DIRECTION_LTR: 15907 default: 15908 if (mUserPaddingStart != UNDEFINED_PADDING) { 15909 mUserPaddingLeft = mUserPaddingStart; 15910 } else { 15911 mUserPaddingLeft = mUserPaddingLeftInitial; 15912 } 15913 if (mUserPaddingEnd != UNDEFINED_PADDING) { 15914 mUserPaddingRight = mUserPaddingEnd; 15915 } else { 15916 mUserPaddingRight = mUserPaddingRightInitial; 15917 } 15918 } 15919 15920 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 15921 } 15922 15923 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 15924 onRtlPropertiesChanged(resolvedLayoutDirection); 15925 15926 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 15927 } 15928 15929 /** 15930 * Reset the resolved layout direction. 15931 * 15932 * @hide 15933 */ 15934 public void resetResolvedPadding() { 15935 resetResolvedPaddingInternal(); 15936 } 15937 15938 /** 15939 * Used when we only want to reset *this* view's padding and not trigger overrides 15940 * in ViewGroup that reset children too. 15941 */ 15942 void resetResolvedPaddingInternal() { 15943 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 15944 } 15945 15946 /** 15947 * This is called when the view is detached from a window. At this point it 15948 * no longer has a surface for drawing. 15949 * 15950 * @see #onAttachedToWindow() 15951 */ 15952 @CallSuper 15953 protected void onDetachedFromWindow() { 15954 } 15955 15956 /** 15957 * This is a framework-internal mirror of onDetachedFromWindow() that's called 15958 * after onDetachedFromWindow(). 15959 * 15960 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 15961 * The super method should be called at the end of the overridden method to ensure 15962 * subclasses are destroyed first 15963 * 15964 * @hide 15965 */ 15966 @CallSuper 15967 protected void onDetachedFromWindowInternal() { 15968 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 15969 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15970 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 15971 15972 removeUnsetPressCallback(); 15973 removeLongPressCallback(); 15974 removePerformClickCallback(); 15975 removeSendViewScrolledAccessibilityEventCallback(); 15976 stopNestedScroll(); 15977 15978 // Anything that started animating right before detach should already 15979 // be in its final state when re-attached. 15980 jumpDrawablesToCurrentState(); 15981 15982 destroyDrawingCache(); 15983 15984 cleanupDraw(); 15985 mCurrentAnimation = null; 15986 15987 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 15988 hideTooltip(); 15989 } 15990 } 15991 15992 private void cleanupDraw() { 15993 resetDisplayList(); 15994 if (mAttachInfo != null) { 15995 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 15996 } 15997 } 15998 15999 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 16000 } 16001 16002 /** 16003 * @return The number of times this view has been attached to a window 16004 */ 16005 protected int getWindowAttachCount() { 16006 return mWindowAttachCount; 16007 } 16008 16009 /** 16010 * Retrieve a unique token identifying the window this view is attached to. 16011 * @return Return the window's token for use in 16012 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 16013 */ 16014 public IBinder getWindowToken() { 16015 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 16016 } 16017 16018 /** 16019 * Retrieve the {@link WindowId} for the window this view is 16020 * currently attached to. 16021 */ 16022 public WindowId getWindowId() { 16023 if (mAttachInfo == null) { 16024 return null; 16025 } 16026 if (mAttachInfo.mWindowId == null) { 16027 try { 16028 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 16029 mAttachInfo.mWindowToken); 16030 mAttachInfo.mWindowId = new WindowId( 16031 mAttachInfo.mIWindowId); 16032 } catch (RemoteException e) { 16033 } 16034 } 16035 return mAttachInfo.mWindowId; 16036 } 16037 16038 /** 16039 * Retrieve a unique token identifying the top-level "real" window of 16040 * the window that this view is attached to. That is, this is like 16041 * {@link #getWindowToken}, except if the window this view in is a panel 16042 * window (attached to another containing window), then the token of 16043 * the containing window is returned instead. 16044 * 16045 * @return Returns the associated window token, either 16046 * {@link #getWindowToken()} or the containing window's token. 16047 */ 16048 public IBinder getApplicationWindowToken() { 16049 AttachInfo ai = mAttachInfo; 16050 if (ai != null) { 16051 IBinder appWindowToken = ai.mPanelParentWindowToken; 16052 if (appWindowToken == null) { 16053 appWindowToken = ai.mWindowToken; 16054 } 16055 return appWindowToken; 16056 } 16057 return null; 16058 } 16059 16060 /** 16061 * Gets the logical display to which the view's window has been attached. 16062 * 16063 * @return The logical display, or null if the view is not currently attached to a window. 16064 */ 16065 public Display getDisplay() { 16066 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 16067 } 16068 16069 /** 16070 * Retrieve private session object this view hierarchy is using to 16071 * communicate with the window manager. 16072 * @return the session object to communicate with the window manager 16073 */ 16074 /*package*/ IWindowSession getWindowSession() { 16075 return mAttachInfo != null ? mAttachInfo.mSession : null; 16076 } 16077 16078 /** 16079 * Return the visibility value of the least visible component passed. 16080 */ 16081 int combineVisibility(int vis1, int vis2) { 16082 // This works because VISIBLE < INVISIBLE < GONE. 16083 return Math.max(vis1, vis2); 16084 } 16085 16086 /** 16087 * @param info the {@link android.view.View.AttachInfo} to associated with 16088 * this view 16089 */ 16090 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 16091 mAttachInfo = info; 16092 if (mOverlay != null) { 16093 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 16094 } 16095 mWindowAttachCount++; 16096 // We will need to evaluate the drawable state at least once. 16097 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 16098 if (mFloatingTreeObserver != null) { 16099 info.mTreeObserver.merge(mFloatingTreeObserver); 16100 mFloatingTreeObserver = null; 16101 } 16102 16103 registerPendingFrameMetricsObservers(); 16104 16105 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 16106 mAttachInfo.mScrollContainers.add(this); 16107 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 16108 } 16109 // Transfer all pending runnables. 16110 if (mRunQueue != null) { 16111 mRunQueue.executeActions(info.mHandler); 16112 mRunQueue = null; 16113 } 16114 performCollectViewAttributes(mAttachInfo, visibility); 16115 onAttachedToWindow(); 16116 16117 ListenerInfo li = mListenerInfo; 16118 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 16119 li != null ? li.mOnAttachStateChangeListeners : null; 16120 if (listeners != null && listeners.size() > 0) { 16121 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 16122 // perform the dispatching. The iterator is a safe guard against listeners that 16123 // could mutate the list by calling the various add/remove methods. This prevents 16124 // the array from being modified while we iterate it. 16125 for (OnAttachStateChangeListener listener : listeners) { 16126 listener.onViewAttachedToWindow(this); 16127 } 16128 } 16129 16130 int vis = info.mWindowVisibility; 16131 if (vis != GONE) { 16132 onWindowVisibilityChanged(vis); 16133 if (isShown()) { 16134 // Calling onVisibilityAggregated directly here since the subtree will also 16135 // receive dispatchAttachedToWindow and this same call 16136 onVisibilityAggregated(vis == VISIBLE); 16137 } 16138 } 16139 16140 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 16141 // As all views in the subtree will already receive dispatchAttachedToWindow 16142 // traversing the subtree again here is not desired. 16143 onVisibilityChanged(this, visibility); 16144 16145 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 16146 // If nobody has evaluated the drawable state yet, then do it now. 16147 refreshDrawableState(); 16148 } 16149 needGlobalAttributesUpdate(false); 16150 } 16151 16152 void dispatchDetachedFromWindow() { 16153 AttachInfo info = mAttachInfo; 16154 if (info != null) { 16155 int vis = info.mWindowVisibility; 16156 if (vis != GONE) { 16157 onWindowVisibilityChanged(GONE); 16158 if (isShown()) { 16159 // Invoking onVisibilityAggregated directly here since the subtree 16160 // will also receive detached from window 16161 onVisibilityAggregated(false); 16162 } 16163 } 16164 } 16165 16166 onDetachedFromWindow(); 16167 onDetachedFromWindowInternal(); 16168 16169 InputMethodManager imm = InputMethodManager.peekInstance(); 16170 if (imm != null) { 16171 imm.onViewDetachedFromWindow(this); 16172 } 16173 16174 ListenerInfo li = mListenerInfo; 16175 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 16176 li != null ? li.mOnAttachStateChangeListeners : null; 16177 if (listeners != null && listeners.size() > 0) { 16178 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 16179 // perform the dispatching. The iterator is a safe guard against listeners that 16180 // could mutate the list by calling the various add/remove methods. This prevents 16181 // the array from being modified while we iterate it. 16182 for (OnAttachStateChangeListener listener : listeners) { 16183 listener.onViewDetachedFromWindow(this); 16184 } 16185 } 16186 16187 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 16188 mAttachInfo.mScrollContainers.remove(this); 16189 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 16190 } 16191 16192 mAttachInfo = null; 16193 if (mOverlay != null) { 16194 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 16195 } 16196 } 16197 16198 /** 16199 * Cancel any deferred high-level input events that were previously posted to the event queue. 16200 * 16201 * <p>Many views post high-level events such as click handlers to the event queue 16202 * to run deferred in order to preserve a desired user experience - clearing visible 16203 * pressed states before executing, etc. This method will abort any events of this nature 16204 * that are currently in flight.</p> 16205 * 16206 * <p>Custom views that generate their own high-level deferred input events should override 16207 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 16208 * 16209 * <p>This will also cancel pending input events for any child views.</p> 16210 * 16211 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 16212 * This will not impact newer events posted after this call that may occur as a result of 16213 * lower-level input events still waiting in the queue. If you are trying to prevent 16214 * double-submitted events for the duration of some sort of asynchronous transaction 16215 * you should also take other steps to protect against unexpected double inputs e.g. calling 16216 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 16217 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 16218 */ 16219 public final void cancelPendingInputEvents() { 16220 dispatchCancelPendingInputEvents(); 16221 } 16222 16223 /** 16224 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 16225 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 16226 */ 16227 void dispatchCancelPendingInputEvents() { 16228 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 16229 onCancelPendingInputEvents(); 16230 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 16231 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 16232 " did not call through to super.onCancelPendingInputEvents()"); 16233 } 16234 } 16235 16236 /** 16237 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 16238 * a parent view. 16239 * 16240 * <p>This method is responsible for removing any pending high-level input events that were 16241 * posted to the event queue to run later. Custom view classes that post their own deferred 16242 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 16243 * {@link android.os.Handler} should override this method, call 16244 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 16245 * </p> 16246 */ 16247 public void onCancelPendingInputEvents() { 16248 removePerformClickCallback(); 16249 cancelLongPress(); 16250 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 16251 } 16252 16253 /** 16254 * Store this view hierarchy's frozen state into the given container. 16255 * 16256 * @param container The SparseArray in which to save the view's state. 16257 * 16258 * @see #restoreHierarchyState(android.util.SparseArray) 16259 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16260 * @see #onSaveInstanceState() 16261 */ 16262 public void saveHierarchyState(SparseArray<Parcelable> container) { 16263 dispatchSaveInstanceState(container); 16264 } 16265 16266 /** 16267 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 16268 * this view and its children. May be overridden to modify how freezing happens to a 16269 * view's children; for example, some views may want to not store state for their children. 16270 * 16271 * @param container The SparseArray in which to save the view's state. 16272 * 16273 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16274 * @see #saveHierarchyState(android.util.SparseArray) 16275 * @see #onSaveInstanceState() 16276 */ 16277 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 16278 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 16279 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 16280 Parcelable state = onSaveInstanceState(); 16281 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 16282 throw new IllegalStateException( 16283 "Derived class did not call super.onSaveInstanceState()"); 16284 } 16285 if (state != null) { 16286 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 16287 // + ": " + state); 16288 container.put(mID, state); 16289 } 16290 } 16291 } 16292 16293 /** 16294 * Hook allowing a view to generate a representation of its internal state 16295 * that can later be used to create a new instance with that same state. 16296 * This state should only contain information that is not persistent or can 16297 * not be reconstructed later. For example, you will never store your 16298 * current position on screen because that will be computed again when a 16299 * new instance of the view is placed in its view hierarchy. 16300 * <p> 16301 * Some examples of things you may store here: the current cursor position 16302 * in a text view (but usually not the text itself since that is stored in a 16303 * content provider or other persistent storage), the currently selected 16304 * item in a list view. 16305 * 16306 * @return Returns a Parcelable object containing the view's current dynamic 16307 * state, or null if there is nothing interesting to save. The 16308 * default implementation returns null. 16309 * @see #onRestoreInstanceState(android.os.Parcelable) 16310 * @see #saveHierarchyState(android.util.SparseArray) 16311 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16312 * @see #setSaveEnabled(boolean) 16313 */ 16314 @CallSuper 16315 protected Parcelable onSaveInstanceState() { 16316 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 16317 if (mStartActivityRequestWho != null) { 16318 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 16319 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 16320 return state; 16321 } 16322 return BaseSavedState.EMPTY_STATE; 16323 } 16324 16325 /** 16326 * Restore this view hierarchy's frozen state from the given container. 16327 * 16328 * @param container The SparseArray which holds previously frozen states. 16329 * 16330 * @see #saveHierarchyState(android.util.SparseArray) 16331 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16332 * @see #onRestoreInstanceState(android.os.Parcelable) 16333 */ 16334 public void restoreHierarchyState(SparseArray<Parcelable> container) { 16335 dispatchRestoreInstanceState(container); 16336 } 16337 16338 /** 16339 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 16340 * state for this view and its children. May be overridden to modify how restoring 16341 * happens to a view's children; for example, some views may want to not store state 16342 * for their children. 16343 * 16344 * @param container The SparseArray which holds previously saved state. 16345 * 16346 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16347 * @see #restoreHierarchyState(android.util.SparseArray) 16348 * @see #onRestoreInstanceState(android.os.Parcelable) 16349 */ 16350 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 16351 if (mID != NO_ID) { 16352 Parcelable state = container.get(mID); 16353 if (state != null) { 16354 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 16355 // + ": " + state); 16356 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 16357 onRestoreInstanceState(state); 16358 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 16359 throw new IllegalStateException( 16360 "Derived class did not call super.onRestoreInstanceState()"); 16361 } 16362 } 16363 } 16364 } 16365 16366 /** 16367 * Hook allowing a view to re-apply a representation of its internal state that had previously 16368 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 16369 * null state. 16370 * 16371 * @param state The frozen state that had previously been returned by 16372 * {@link #onSaveInstanceState}. 16373 * 16374 * @see #onSaveInstanceState() 16375 * @see #restoreHierarchyState(android.util.SparseArray) 16376 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16377 */ 16378 @CallSuper 16379 protected void onRestoreInstanceState(Parcelable state) { 16380 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 16381 if (state != null && !(state instanceof AbsSavedState)) { 16382 throw new IllegalArgumentException("Wrong state class, expecting View State but " 16383 + "received " + state.getClass().toString() + " instead. This usually happens " 16384 + "when two views of different type have the same id in the same hierarchy. " 16385 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 16386 + "other views do not use the same id."); 16387 } 16388 if (state != null && state instanceof BaseSavedState) { 16389 mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved; 16390 } 16391 } 16392 16393 /** 16394 * <p>Return the time at which the drawing of the view hierarchy started.</p> 16395 * 16396 * @return the drawing start time in milliseconds 16397 */ 16398 public long getDrawingTime() { 16399 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 16400 } 16401 16402 /** 16403 * <p>Enables or disables the duplication of the parent's state into this view. When 16404 * duplication is enabled, this view gets its drawable state from its parent rather 16405 * than from its own internal properties.</p> 16406 * 16407 * <p>Note: in the current implementation, setting this property to true after the 16408 * view was added to a ViewGroup might have no effect at all. This property should 16409 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 16410 * 16411 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 16412 * property is enabled, an exception will be thrown.</p> 16413 * 16414 * <p>Note: if the child view uses and updates additional states which are unknown to the 16415 * parent, these states should not be affected by this method.</p> 16416 * 16417 * @param enabled True to enable duplication of the parent's drawable state, false 16418 * to disable it. 16419 * 16420 * @see #getDrawableState() 16421 * @see #isDuplicateParentStateEnabled() 16422 */ 16423 public void setDuplicateParentStateEnabled(boolean enabled) { 16424 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 16425 } 16426 16427 /** 16428 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 16429 * 16430 * @return True if this view's drawable state is duplicated from the parent, 16431 * false otherwise 16432 * 16433 * @see #getDrawableState() 16434 * @see #setDuplicateParentStateEnabled(boolean) 16435 */ 16436 public boolean isDuplicateParentStateEnabled() { 16437 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 16438 } 16439 16440 /** 16441 * <p>Specifies the type of layer backing this view. The layer can be 16442 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16443 * {@link #LAYER_TYPE_HARDWARE}.</p> 16444 * 16445 * <p>A layer is associated with an optional {@link android.graphics.Paint} 16446 * instance that controls how the layer is composed on screen. The following 16447 * properties of the paint are taken into account when composing the layer:</p> 16448 * <ul> 16449 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 16450 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 16451 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 16452 * </ul> 16453 * 16454 * <p>If this view has an alpha value set to < 1.0 by calling 16455 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 16456 * by this view's alpha value.</p> 16457 * 16458 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 16459 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 16460 * for more information on when and how to use layers.</p> 16461 * 16462 * @param layerType The type of layer to use with this view, must be one of 16463 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16464 * {@link #LAYER_TYPE_HARDWARE} 16465 * @param paint The paint used to compose the layer. This argument is optional 16466 * and can be null. It is ignored when the layer type is 16467 * {@link #LAYER_TYPE_NONE} 16468 * 16469 * @see #getLayerType() 16470 * @see #LAYER_TYPE_NONE 16471 * @see #LAYER_TYPE_SOFTWARE 16472 * @see #LAYER_TYPE_HARDWARE 16473 * @see #setAlpha(float) 16474 * 16475 * @attr ref android.R.styleable#View_layerType 16476 */ 16477 public void setLayerType(int layerType, @Nullable Paint paint) { 16478 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 16479 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 16480 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 16481 } 16482 16483 boolean typeChanged = mRenderNode.setLayerType(layerType); 16484 16485 if (!typeChanged) { 16486 setLayerPaint(paint); 16487 return; 16488 } 16489 16490 if (layerType != LAYER_TYPE_SOFTWARE) { 16491 // Destroy any previous software drawing cache if present 16492 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 16493 // drawing cache created in View#draw when drawing to a SW canvas. 16494 destroyDrawingCache(); 16495 } 16496 16497 mLayerType = layerType; 16498 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 16499 mRenderNode.setLayerPaint(mLayerPaint); 16500 16501 // draw() behaves differently if we are on a layer, so we need to 16502 // invalidate() here 16503 invalidateParentCaches(); 16504 invalidate(true); 16505 } 16506 16507 /** 16508 * Updates the {@link Paint} object used with the current layer (used only if the current 16509 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 16510 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 16511 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 16512 * ensure that the view gets redrawn immediately. 16513 * 16514 * <p>A layer is associated with an optional {@link android.graphics.Paint} 16515 * instance that controls how the layer is composed on screen. The following 16516 * properties of the paint are taken into account when composing the layer:</p> 16517 * <ul> 16518 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 16519 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 16520 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 16521 * </ul> 16522 * 16523 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 16524 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 16525 * 16526 * @param paint The paint used to compose the layer. This argument is optional 16527 * and can be null. It is ignored when the layer type is 16528 * {@link #LAYER_TYPE_NONE} 16529 * 16530 * @see #setLayerType(int, android.graphics.Paint) 16531 */ 16532 public void setLayerPaint(@Nullable Paint paint) { 16533 int layerType = getLayerType(); 16534 if (layerType != LAYER_TYPE_NONE) { 16535 mLayerPaint = paint; 16536 if (layerType == LAYER_TYPE_HARDWARE) { 16537 if (mRenderNode.setLayerPaint(paint)) { 16538 invalidateViewProperty(false, false); 16539 } 16540 } else { 16541 invalidate(); 16542 } 16543 } 16544 } 16545 16546 /** 16547 * Indicates what type of layer is currently associated with this view. By default 16548 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 16549 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 16550 * for more information on the different types of layers. 16551 * 16552 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16553 * {@link #LAYER_TYPE_HARDWARE} 16554 * 16555 * @see #setLayerType(int, android.graphics.Paint) 16556 * @see #buildLayer() 16557 * @see #LAYER_TYPE_NONE 16558 * @see #LAYER_TYPE_SOFTWARE 16559 * @see #LAYER_TYPE_HARDWARE 16560 */ 16561 public int getLayerType() { 16562 return mLayerType; 16563 } 16564 16565 /** 16566 * Forces this view's layer to be created and this view to be rendered 16567 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 16568 * invoking this method will have no effect. 16569 * 16570 * This method can for instance be used to render a view into its layer before 16571 * starting an animation. If this view is complex, rendering into the layer 16572 * before starting the animation will avoid skipping frames. 16573 * 16574 * @throws IllegalStateException If this view is not attached to a window 16575 * 16576 * @see #setLayerType(int, android.graphics.Paint) 16577 */ 16578 public void buildLayer() { 16579 if (mLayerType == LAYER_TYPE_NONE) return; 16580 16581 final AttachInfo attachInfo = mAttachInfo; 16582 if (attachInfo == null) { 16583 throw new IllegalStateException("This view must be attached to a window first"); 16584 } 16585 16586 if (getWidth() == 0 || getHeight() == 0) { 16587 return; 16588 } 16589 16590 switch (mLayerType) { 16591 case LAYER_TYPE_HARDWARE: 16592 updateDisplayListIfDirty(); 16593 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 16594 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 16595 } 16596 break; 16597 case LAYER_TYPE_SOFTWARE: 16598 buildDrawingCache(true); 16599 break; 16600 } 16601 } 16602 16603 /** 16604 * Destroys all hardware rendering resources. This method is invoked 16605 * when the system needs to reclaim resources. Upon execution of this 16606 * method, you should free any OpenGL resources created by the view. 16607 * 16608 * Note: you <strong>must</strong> call 16609 * <code>super.destroyHardwareResources()</code> when overriding 16610 * this method. 16611 * 16612 * @hide 16613 */ 16614 @CallSuper 16615 protected void destroyHardwareResources() { 16616 if (mOverlay != null) { 16617 mOverlay.getOverlayView().destroyHardwareResources(); 16618 } 16619 if (mGhostView != null) { 16620 mGhostView.destroyHardwareResources(); 16621 } 16622 } 16623 16624 /** 16625 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 16626 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 16627 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 16628 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 16629 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 16630 * null.</p> 16631 * 16632 * <p>Enabling the drawing cache is similar to 16633 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 16634 * acceleration is turned off. When hardware acceleration is turned on, enabling the 16635 * drawing cache has no effect on rendering because the system uses a different mechanism 16636 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 16637 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 16638 * for information on how to enable software and hardware layers.</p> 16639 * 16640 * <p>This API can be used to manually generate 16641 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 16642 * {@link #getDrawingCache()}.</p> 16643 * 16644 * @param enabled true to enable the drawing cache, false otherwise 16645 * 16646 * @see #isDrawingCacheEnabled() 16647 * @see #getDrawingCache() 16648 * @see #buildDrawingCache() 16649 * @see #setLayerType(int, android.graphics.Paint) 16650 */ 16651 public void setDrawingCacheEnabled(boolean enabled) { 16652 mCachingFailed = false; 16653 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 16654 } 16655 16656 /** 16657 * <p>Indicates whether the drawing cache is enabled for this view.</p> 16658 * 16659 * @return true if the drawing cache is enabled 16660 * 16661 * @see #setDrawingCacheEnabled(boolean) 16662 * @see #getDrawingCache() 16663 */ 16664 @ViewDebug.ExportedProperty(category = "drawing") 16665 public boolean isDrawingCacheEnabled() { 16666 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 16667 } 16668 16669 /** 16670 * Debugging utility which recursively outputs the dirty state of a view and its 16671 * descendants. 16672 * 16673 * @hide 16674 */ 16675 @SuppressWarnings({"UnusedDeclaration"}) 16676 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 16677 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 16678 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 16679 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 16680 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 16681 if (clear) { 16682 mPrivateFlags &= clearMask; 16683 } 16684 if (this instanceof ViewGroup) { 16685 ViewGroup parent = (ViewGroup) this; 16686 final int count = parent.getChildCount(); 16687 for (int i = 0; i < count; i++) { 16688 final View child = parent.getChildAt(i); 16689 child.outputDirtyFlags(indent + " ", clear, clearMask); 16690 } 16691 } 16692 } 16693 16694 /** 16695 * This method is used by ViewGroup to cause its children to restore or recreate their 16696 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 16697 * to recreate its own display list, which would happen if it went through the normal 16698 * draw/dispatchDraw mechanisms. 16699 * 16700 * @hide 16701 */ 16702 protected void dispatchGetDisplayList() {} 16703 16704 /** 16705 * A view that is not attached or hardware accelerated cannot create a display list. 16706 * This method checks these conditions and returns the appropriate result. 16707 * 16708 * @return true if view has the ability to create a display list, false otherwise. 16709 * 16710 * @hide 16711 */ 16712 public boolean canHaveDisplayList() { 16713 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 16714 } 16715 16716 /** 16717 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 16718 * @hide 16719 */ 16720 @NonNull 16721 public RenderNode updateDisplayListIfDirty() { 16722 final RenderNode renderNode = mRenderNode; 16723 if (!canHaveDisplayList()) { 16724 // can't populate RenderNode, don't try 16725 return renderNode; 16726 } 16727 16728 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 16729 || !renderNode.isValid() 16730 || (mRecreateDisplayList)) { 16731 // Don't need to recreate the display list, just need to tell our 16732 // children to restore/recreate theirs 16733 if (renderNode.isValid() 16734 && !mRecreateDisplayList) { 16735 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16736 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16737 dispatchGetDisplayList(); 16738 16739 return renderNode; // no work needed 16740 } 16741 16742 // If we got here, we're recreating it. Mark it as such to ensure that 16743 // we copy in child display lists into ours in drawChild() 16744 mRecreateDisplayList = true; 16745 16746 int width = mRight - mLeft; 16747 int height = mBottom - mTop; 16748 int layerType = getLayerType(); 16749 16750 final DisplayListCanvas canvas = renderNode.start(width, height); 16751 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 16752 16753 try { 16754 if (layerType == LAYER_TYPE_SOFTWARE) { 16755 buildDrawingCache(true); 16756 Bitmap cache = getDrawingCache(true); 16757 if (cache != null) { 16758 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 16759 } 16760 } else { 16761 computeScroll(); 16762 16763 canvas.translate(-mScrollX, -mScrollY); 16764 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16765 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16766 16767 // Fast path for layouts with no backgrounds 16768 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16769 dispatchDraw(canvas); 16770 if (mOverlay != null && !mOverlay.isEmpty()) { 16771 mOverlay.getOverlayView().draw(canvas); 16772 } 16773 if (debugDraw()) { 16774 debugDrawFocus(canvas); 16775 } 16776 } else { 16777 draw(canvas); 16778 } 16779 } 16780 } finally { 16781 renderNode.end(canvas); 16782 setDisplayListProperties(renderNode); 16783 } 16784 } else { 16785 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16786 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16787 } 16788 return renderNode; 16789 } 16790 16791 private void resetDisplayList() { 16792 mRenderNode.discardDisplayList(); 16793 if (mBackgroundRenderNode != null) { 16794 mBackgroundRenderNode.discardDisplayList(); 16795 } 16796 } 16797 16798 /** 16799 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 16800 * 16801 * @return A non-scaled bitmap representing this view or null if cache is disabled. 16802 * 16803 * @see #getDrawingCache(boolean) 16804 */ 16805 public Bitmap getDrawingCache() { 16806 return getDrawingCache(false); 16807 } 16808 16809 /** 16810 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 16811 * is null when caching is disabled. If caching is enabled and the cache is not ready, 16812 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 16813 * draw from the cache when the cache is enabled. To benefit from the cache, you must 16814 * request the drawing cache by calling this method and draw it on screen if the 16815 * returned bitmap is not null.</p> 16816 * 16817 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16818 * this method will create a bitmap of the same size as this view. Because this bitmap 16819 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16820 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16821 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16822 * size than the view. This implies that your application must be able to handle this 16823 * size.</p> 16824 * 16825 * @param autoScale Indicates whether the generated bitmap should be scaled based on 16826 * the current density of the screen when the application is in compatibility 16827 * mode. 16828 * 16829 * @return A bitmap representing this view or null if cache is disabled. 16830 * 16831 * @see #setDrawingCacheEnabled(boolean) 16832 * @see #isDrawingCacheEnabled() 16833 * @see #buildDrawingCache(boolean) 16834 * @see #destroyDrawingCache() 16835 */ 16836 public Bitmap getDrawingCache(boolean autoScale) { 16837 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 16838 return null; 16839 } 16840 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 16841 buildDrawingCache(autoScale); 16842 } 16843 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 16844 } 16845 16846 /** 16847 * <p>Frees the resources used by the drawing cache. If you call 16848 * {@link #buildDrawingCache()} manually without calling 16849 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16850 * should cleanup the cache with this method afterwards.</p> 16851 * 16852 * @see #setDrawingCacheEnabled(boolean) 16853 * @see #buildDrawingCache() 16854 * @see #getDrawingCache() 16855 */ 16856 public void destroyDrawingCache() { 16857 if (mDrawingCache != null) { 16858 mDrawingCache.recycle(); 16859 mDrawingCache = null; 16860 } 16861 if (mUnscaledDrawingCache != null) { 16862 mUnscaledDrawingCache.recycle(); 16863 mUnscaledDrawingCache = null; 16864 } 16865 } 16866 16867 /** 16868 * Setting a solid background color for the drawing cache's bitmaps will improve 16869 * performance and memory usage. Note, though that this should only be used if this 16870 * view will always be drawn on top of a solid color. 16871 * 16872 * @param color The background color to use for the drawing cache's bitmap 16873 * 16874 * @see #setDrawingCacheEnabled(boolean) 16875 * @see #buildDrawingCache() 16876 * @see #getDrawingCache() 16877 */ 16878 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 16879 if (color != mDrawingCacheBackgroundColor) { 16880 mDrawingCacheBackgroundColor = color; 16881 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16882 } 16883 } 16884 16885 /** 16886 * @see #setDrawingCacheBackgroundColor(int) 16887 * 16888 * @return The background color to used for the drawing cache's bitmap 16889 */ 16890 @ColorInt 16891 public int getDrawingCacheBackgroundColor() { 16892 return mDrawingCacheBackgroundColor; 16893 } 16894 16895 /** 16896 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 16897 * 16898 * @see #buildDrawingCache(boolean) 16899 */ 16900 public void buildDrawingCache() { 16901 buildDrawingCache(false); 16902 } 16903 16904 /** 16905 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 16906 * 16907 * <p>If you call {@link #buildDrawingCache()} manually without calling 16908 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16909 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 16910 * 16911 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16912 * this method will create a bitmap of the same size as this view. Because this bitmap 16913 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16914 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16915 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16916 * size than the view. This implies that your application must be able to handle this 16917 * size.</p> 16918 * 16919 * <p>You should avoid calling this method when hardware acceleration is enabled. If 16920 * you do not need the drawing cache bitmap, calling this method will increase memory 16921 * usage and cause the view to be rendered in software once, thus negatively impacting 16922 * performance.</p> 16923 * 16924 * @see #getDrawingCache() 16925 * @see #destroyDrawingCache() 16926 */ 16927 public void buildDrawingCache(boolean autoScale) { 16928 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 16929 mDrawingCache == null : mUnscaledDrawingCache == null)) { 16930 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 16931 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 16932 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 16933 } 16934 try { 16935 buildDrawingCacheImpl(autoScale); 16936 } finally { 16937 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 16938 } 16939 } 16940 } 16941 16942 /** 16943 * private, internal implementation of buildDrawingCache, used to enable tracing 16944 */ 16945 private void buildDrawingCacheImpl(boolean autoScale) { 16946 mCachingFailed = false; 16947 16948 int width = mRight - mLeft; 16949 int height = mBottom - mTop; 16950 16951 final AttachInfo attachInfo = mAttachInfo; 16952 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 16953 16954 if (autoScale && scalingRequired) { 16955 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 16956 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 16957 } 16958 16959 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 16960 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 16961 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 16962 16963 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 16964 final long drawingCacheSize = 16965 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 16966 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 16967 if (width > 0 && height > 0) { 16968 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 16969 + " too large to fit into a software layer (or drawing cache), needs " 16970 + projectedBitmapSize + " bytes, only " 16971 + drawingCacheSize + " available"); 16972 } 16973 destroyDrawingCache(); 16974 mCachingFailed = true; 16975 return; 16976 } 16977 16978 boolean clear = true; 16979 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 16980 16981 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 16982 Bitmap.Config quality; 16983 if (!opaque) { 16984 // Never pick ARGB_4444 because it looks awful 16985 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 16986 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 16987 case DRAWING_CACHE_QUALITY_AUTO: 16988 case DRAWING_CACHE_QUALITY_LOW: 16989 case DRAWING_CACHE_QUALITY_HIGH: 16990 default: 16991 quality = Bitmap.Config.ARGB_8888; 16992 break; 16993 } 16994 } else { 16995 // Optimization for translucent windows 16996 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 16997 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 16998 } 16999 17000 // Try to cleanup memory 17001 if (bitmap != null) bitmap.recycle(); 17002 17003 try { 17004 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17005 width, height, quality); 17006 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 17007 if (autoScale) { 17008 mDrawingCache = bitmap; 17009 } else { 17010 mUnscaledDrawingCache = bitmap; 17011 } 17012 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 17013 } catch (OutOfMemoryError e) { 17014 // If there is not enough memory to create the bitmap cache, just 17015 // ignore the issue as bitmap caches are not required to draw the 17016 // view hierarchy 17017 if (autoScale) { 17018 mDrawingCache = null; 17019 } else { 17020 mUnscaledDrawingCache = null; 17021 } 17022 mCachingFailed = true; 17023 return; 17024 } 17025 17026 clear = drawingCacheBackgroundColor != 0; 17027 } 17028 17029 Canvas canvas; 17030 if (attachInfo != null) { 17031 canvas = attachInfo.mCanvas; 17032 if (canvas == null) { 17033 canvas = new Canvas(); 17034 } 17035 canvas.setBitmap(bitmap); 17036 // Temporarily clobber the cached Canvas in case one of our children 17037 // is also using a drawing cache. Without this, the children would 17038 // steal the canvas by attaching their own bitmap to it and bad, bad 17039 // thing would happen (invisible views, corrupted drawings, etc.) 17040 attachInfo.mCanvas = null; 17041 } else { 17042 // This case should hopefully never or seldom happen 17043 canvas = new Canvas(bitmap); 17044 } 17045 17046 if (clear) { 17047 bitmap.eraseColor(drawingCacheBackgroundColor); 17048 } 17049 17050 computeScroll(); 17051 final int restoreCount = canvas.save(); 17052 17053 if (autoScale && scalingRequired) { 17054 final float scale = attachInfo.mApplicationScale; 17055 canvas.scale(scale, scale); 17056 } 17057 17058 canvas.translate(-mScrollX, -mScrollY); 17059 17060 mPrivateFlags |= PFLAG_DRAWN; 17061 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 17062 mLayerType != LAYER_TYPE_NONE) { 17063 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 17064 } 17065 17066 // Fast path for layouts with no backgrounds 17067 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17068 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17069 dispatchDraw(canvas); 17070 if (mOverlay != null && !mOverlay.isEmpty()) { 17071 mOverlay.getOverlayView().draw(canvas); 17072 } 17073 } else { 17074 draw(canvas); 17075 } 17076 17077 canvas.restoreToCount(restoreCount); 17078 canvas.setBitmap(null); 17079 17080 if (attachInfo != null) { 17081 // Restore the cached Canvas for our siblings 17082 attachInfo.mCanvas = canvas; 17083 } 17084 } 17085 17086 /** 17087 * Create a snapshot of the view into a bitmap. We should probably make 17088 * some form of this public, but should think about the API. 17089 * 17090 * @hide 17091 */ 17092 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 17093 int width = mRight - mLeft; 17094 int height = mBottom - mTop; 17095 17096 final AttachInfo attachInfo = mAttachInfo; 17097 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 17098 width = (int) ((width * scale) + 0.5f); 17099 height = (int) ((height * scale) + 0.5f); 17100 17101 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17102 width > 0 ? width : 1, height > 0 ? height : 1, quality); 17103 if (bitmap == null) { 17104 throw new OutOfMemoryError(); 17105 } 17106 17107 Resources resources = getResources(); 17108 if (resources != null) { 17109 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 17110 } 17111 17112 Canvas canvas; 17113 if (attachInfo != null) { 17114 canvas = attachInfo.mCanvas; 17115 if (canvas == null) { 17116 canvas = new Canvas(); 17117 } 17118 canvas.setBitmap(bitmap); 17119 // Temporarily clobber the cached Canvas in case one of our children 17120 // is also using a drawing cache. Without this, the children would 17121 // steal the canvas by attaching their own bitmap to it and bad, bad 17122 // things would happen (invisible views, corrupted drawings, etc.) 17123 attachInfo.mCanvas = null; 17124 } else { 17125 // This case should hopefully never or seldom happen 17126 canvas = new Canvas(bitmap); 17127 } 17128 17129 if ((backgroundColor & 0xff000000) != 0) { 17130 bitmap.eraseColor(backgroundColor); 17131 } 17132 17133 computeScroll(); 17134 final int restoreCount = canvas.save(); 17135 canvas.scale(scale, scale); 17136 canvas.translate(-mScrollX, -mScrollY); 17137 17138 // Temporarily remove the dirty mask 17139 int flags = mPrivateFlags; 17140 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17141 17142 // Fast path for layouts with no backgrounds 17143 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17144 dispatchDraw(canvas); 17145 if (mOverlay != null && !mOverlay.isEmpty()) { 17146 mOverlay.getOverlayView().draw(canvas); 17147 } 17148 } else { 17149 draw(canvas); 17150 } 17151 17152 mPrivateFlags = flags; 17153 17154 canvas.restoreToCount(restoreCount); 17155 canvas.setBitmap(null); 17156 17157 if (attachInfo != null) { 17158 // Restore the cached Canvas for our siblings 17159 attachInfo.mCanvas = canvas; 17160 } 17161 17162 return bitmap; 17163 } 17164 17165 /** 17166 * Indicates whether this View is currently in edit mode. A View is usually 17167 * in edit mode when displayed within a developer tool. For instance, if 17168 * this View is being drawn by a visual user interface builder, this method 17169 * should return true. 17170 * 17171 * Subclasses should check the return value of this method to provide 17172 * different behaviors if their normal behavior might interfere with the 17173 * host environment. For instance: the class spawns a thread in its 17174 * constructor, the drawing code relies on device-specific features, etc. 17175 * 17176 * This method is usually checked in the drawing code of custom widgets. 17177 * 17178 * @return True if this View is in edit mode, false otherwise. 17179 */ 17180 public boolean isInEditMode() { 17181 return false; 17182 } 17183 17184 /** 17185 * If the View draws content inside its padding and enables fading edges, 17186 * it needs to support padding offsets. Padding offsets are added to the 17187 * fading edges to extend the length of the fade so that it covers pixels 17188 * drawn inside the padding. 17189 * 17190 * Subclasses of this class should override this method if they need 17191 * to draw content inside the padding. 17192 * 17193 * @return True if padding offset must be applied, false otherwise. 17194 * 17195 * @see #getLeftPaddingOffset() 17196 * @see #getRightPaddingOffset() 17197 * @see #getTopPaddingOffset() 17198 * @see #getBottomPaddingOffset() 17199 * 17200 * @since CURRENT 17201 */ 17202 protected boolean isPaddingOffsetRequired() { 17203 return false; 17204 } 17205 17206 /** 17207 * Amount by which to extend the left fading region. Called only when 17208 * {@link #isPaddingOffsetRequired()} returns true. 17209 * 17210 * @return The left padding offset in pixels. 17211 * 17212 * @see #isPaddingOffsetRequired() 17213 * 17214 * @since CURRENT 17215 */ 17216 protected int getLeftPaddingOffset() { 17217 return 0; 17218 } 17219 17220 /** 17221 * Amount by which to extend the right fading region. Called only when 17222 * {@link #isPaddingOffsetRequired()} returns true. 17223 * 17224 * @return The right padding offset in pixels. 17225 * 17226 * @see #isPaddingOffsetRequired() 17227 * 17228 * @since CURRENT 17229 */ 17230 protected int getRightPaddingOffset() { 17231 return 0; 17232 } 17233 17234 /** 17235 * Amount by which to extend the top fading region. Called only when 17236 * {@link #isPaddingOffsetRequired()} returns true. 17237 * 17238 * @return The top padding offset in pixels. 17239 * 17240 * @see #isPaddingOffsetRequired() 17241 * 17242 * @since CURRENT 17243 */ 17244 protected int getTopPaddingOffset() { 17245 return 0; 17246 } 17247 17248 /** 17249 * Amount by which to extend the bottom fading region. Called only when 17250 * {@link #isPaddingOffsetRequired()} returns true. 17251 * 17252 * @return The bottom padding offset in pixels. 17253 * 17254 * @see #isPaddingOffsetRequired() 17255 * 17256 * @since CURRENT 17257 */ 17258 protected int getBottomPaddingOffset() { 17259 return 0; 17260 } 17261 17262 /** 17263 * @hide 17264 * @param offsetRequired 17265 */ 17266 protected int getFadeTop(boolean offsetRequired) { 17267 int top = mPaddingTop; 17268 if (offsetRequired) top += getTopPaddingOffset(); 17269 return top; 17270 } 17271 17272 /** 17273 * @hide 17274 * @param offsetRequired 17275 */ 17276 protected int getFadeHeight(boolean offsetRequired) { 17277 int padding = mPaddingTop; 17278 if (offsetRequired) padding += getTopPaddingOffset(); 17279 return mBottom - mTop - mPaddingBottom - padding; 17280 } 17281 17282 /** 17283 * <p>Indicates whether this view is attached to a hardware accelerated 17284 * window or not.</p> 17285 * 17286 * <p>Even if this method returns true, it does not mean that every call 17287 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 17288 * accelerated {@link android.graphics.Canvas}. For instance, if this view 17289 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 17290 * window is hardware accelerated, 17291 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 17292 * return false, and this method will return true.</p> 17293 * 17294 * @return True if the view is attached to a window and the window is 17295 * hardware accelerated; false in any other case. 17296 */ 17297 @ViewDebug.ExportedProperty(category = "drawing") 17298 public boolean isHardwareAccelerated() { 17299 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 17300 } 17301 17302 /** 17303 * Sets a rectangular area on this view to which the view will be clipped 17304 * when it is drawn. Setting the value to null will remove the clip bounds 17305 * and the view will draw normally, using its full bounds. 17306 * 17307 * @param clipBounds The rectangular area, in the local coordinates of 17308 * this view, to which future drawing operations will be clipped. 17309 */ 17310 public void setClipBounds(Rect clipBounds) { 17311 if (clipBounds == mClipBounds 17312 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 17313 return; 17314 } 17315 if (clipBounds != null) { 17316 if (mClipBounds == null) { 17317 mClipBounds = new Rect(clipBounds); 17318 } else { 17319 mClipBounds.set(clipBounds); 17320 } 17321 } else { 17322 mClipBounds = null; 17323 } 17324 mRenderNode.setClipBounds(mClipBounds); 17325 invalidateViewProperty(false, false); 17326 } 17327 17328 /** 17329 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 17330 * 17331 * @return A copy of the current clip bounds if clip bounds are set, 17332 * otherwise null. 17333 */ 17334 public Rect getClipBounds() { 17335 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 17336 } 17337 17338 17339 /** 17340 * Populates an output rectangle with the clip bounds of the view, 17341 * returning {@code true} if successful or {@code false} if the view's 17342 * clip bounds are {@code null}. 17343 * 17344 * @param outRect rectangle in which to place the clip bounds of the view 17345 * @return {@code true} if successful or {@code false} if the view's 17346 * clip bounds are {@code null} 17347 */ 17348 public boolean getClipBounds(Rect outRect) { 17349 if (mClipBounds != null) { 17350 outRect.set(mClipBounds); 17351 return true; 17352 } 17353 return false; 17354 } 17355 17356 /** 17357 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 17358 * case of an active Animation being run on the view. 17359 */ 17360 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 17361 Animation a, boolean scalingRequired) { 17362 Transformation invalidationTransform; 17363 final int flags = parent.mGroupFlags; 17364 final boolean initialized = a.isInitialized(); 17365 if (!initialized) { 17366 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 17367 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 17368 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 17369 onAnimationStart(); 17370 } 17371 17372 final Transformation t = parent.getChildTransformation(); 17373 boolean more = a.getTransformation(drawingTime, t, 1f); 17374 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 17375 if (parent.mInvalidationTransformation == null) { 17376 parent.mInvalidationTransformation = new Transformation(); 17377 } 17378 invalidationTransform = parent.mInvalidationTransformation; 17379 a.getTransformation(drawingTime, invalidationTransform, 1f); 17380 } else { 17381 invalidationTransform = t; 17382 } 17383 17384 if (more) { 17385 if (!a.willChangeBounds()) { 17386 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 17387 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 17388 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 17389 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 17390 // The child need to draw an animation, potentially offscreen, so 17391 // make sure we do not cancel invalidate requests 17392 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17393 parent.invalidate(mLeft, mTop, mRight, mBottom); 17394 } 17395 } else { 17396 if (parent.mInvalidateRegion == null) { 17397 parent.mInvalidateRegion = new RectF(); 17398 } 17399 final RectF region = parent.mInvalidateRegion; 17400 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 17401 invalidationTransform); 17402 17403 // The child need to draw an animation, potentially offscreen, so 17404 // make sure we do not cancel invalidate requests 17405 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17406 17407 final int left = mLeft + (int) region.left; 17408 final int top = mTop + (int) region.top; 17409 parent.invalidate(left, top, left + (int) (region.width() + .5f), 17410 top + (int) (region.height() + .5f)); 17411 } 17412 } 17413 return more; 17414 } 17415 17416 /** 17417 * This method is called by getDisplayList() when a display list is recorded for a View. 17418 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 17419 */ 17420 void setDisplayListProperties(RenderNode renderNode) { 17421 if (renderNode != null) { 17422 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 17423 renderNode.setClipToBounds(mParent instanceof ViewGroup 17424 && ((ViewGroup) mParent).getClipChildren()); 17425 17426 float alpha = 1; 17427 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 17428 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17429 ViewGroup parentVG = (ViewGroup) mParent; 17430 final Transformation t = parentVG.getChildTransformation(); 17431 if (parentVG.getChildStaticTransformation(this, t)) { 17432 final int transformType = t.getTransformationType(); 17433 if (transformType != Transformation.TYPE_IDENTITY) { 17434 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 17435 alpha = t.getAlpha(); 17436 } 17437 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 17438 renderNode.setStaticMatrix(t.getMatrix()); 17439 } 17440 } 17441 } 17442 } 17443 if (mTransformationInfo != null) { 17444 alpha *= getFinalAlpha(); 17445 if (alpha < 1) { 17446 final int multipliedAlpha = (int) (255 * alpha); 17447 if (onSetAlpha(multipliedAlpha)) { 17448 alpha = 1; 17449 } 17450 } 17451 renderNode.setAlpha(alpha); 17452 } else if (alpha < 1) { 17453 renderNode.setAlpha(alpha); 17454 } 17455 } 17456 } 17457 17458 /** 17459 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 17460 * 17461 * This is where the View specializes rendering behavior based on layer type, 17462 * and hardware acceleration. 17463 */ 17464 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 17465 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 17466 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 17467 * 17468 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 17469 * HW accelerated, it can't handle drawing RenderNodes. 17470 */ 17471 boolean drawingWithRenderNode = mAttachInfo != null 17472 && mAttachInfo.mHardwareAccelerated 17473 && hardwareAcceleratedCanvas; 17474 17475 boolean more = false; 17476 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 17477 final int parentFlags = parent.mGroupFlags; 17478 17479 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 17480 parent.getChildTransformation().clear(); 17481 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17482 } 17483 17484 Transformation transformToApply = null; 17485 boolean concatMatrix = false; 17486 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 17487 final Animation a = getAnimation(); 17488 if (a != null) { 17489 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 17490 concatMatrix = a.willChangeTransformationMatrix(); 17491 if (concatMatrix) { 17492 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17493 } 17494 transformToApply = parent.getChildTransformation(); 17495 } else { 17496 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 17497 // No longer animating: clear out old animation matrix 17498 mRenderNode.setAnimationMatrix(null); 17499 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17500 } 17501 if (!drawingWithRenderNode 17502 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17503 final Transformation t = parent.getChildTransformation(); 17504 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 17505 if (hasTransform) { 17506 final int transformType = t.getTransformationType(); 17507 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 17508 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 17509 } 17510 } 17511 } 17512 17513 concatMatrix |= !childHasIdentityMatrix; 17514 17515 // Sets the flag as early as possible to allow draw() implementations 17516 // to call invalidate() successfully when doing animations 17517 mPrivateFlags |= PFLAG_DRAWN; 17518 17519 if (!concatMatrix && 17520 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 17521 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 17522 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 17523 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 17524 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 17525 return more; 17526 } 17527 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 17528 17529 if (hardwareAcceleratedCanvas) { 17530 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 17531 // retain the flag's value temporarily in the mRecreateDisplayList flag 17532 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 17533 mPrivateFlags &= ~PFLAG_INVALIDATED; 17534 } 17535 17536 RenderNode renderNode = null; 17537 Bitmap cache = null; 17538 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 17539 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 17540 if (layerType != LAYER_TYPE_NONE) { 17541 // If not drawing with RenderNode, treat HW layers as SW 17542 layerType = LAYER_TYPE_SOFTWARE; 17543 buildDrawingCache(true); 17544 } 17545 cache = getDrawingCache(true); 17546 } 17547 17548 if (drawingWithRenderNode) { 17549 // Delay getting the display list until animation-driven alpha values are 17550 // set up and possibly passed on to the view 17551 renderNode = updateDisplayListIfDirty(); 17552 if (!renderNode.isValid()) { 17553 // Uncommon, but possible. If a view is removed from the hierarchy during the call 17554 // to getDisplayList(), the display list will be marked invalid and we should not 17555 // try to use it again. 17556 renderNode = null; 17557 drawingWithRenderNode = false; 17558 } 17559 } 17560 17561 int sx = 0; 17562 int sy = 0; 17563 if (!drawingWithRenderNode) { 17564 computeScroll(); 17565 sx = mScrollX; 17566 sy = mScrollY; 17567 } 17568 17569 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 17570 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 17571 17572 int restoreTo = -1; 17573 if (!drawingWithRenderNode || transformToApply != null) { 17574 restoreTo = canvas.save(); 17575 } 17576 if (offsetForScroll) { 17577 canvas.translate(mLeft - sx, mTop - sy); 17578 } else { 17579 if (!drawingWithRenderNode) { 17580 canvas.translate(mLeft, mTop); 17581 } 17582 if (scalingRequired) { 17583 if (drawingWithRenderNode) { 17584 // TODO: Might not need this if we put everything inside the DL 17585 restoreTo = canvas.save(); 17586 } 17587 // mAttachInfo cannot be null, otherwise scalingRequired == false 17588 final float scale = 1.0f / mAttachInfo.mApplicationScale; 17589 canvas.scale(scale, scale); 17590 } 17591 } 17592 17593 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 17594 if (transformToApply != null 17595 || alpha < 1 17596 || !hasIdentityMatrix() 17597 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17598 if (transformToApply != null || !childHasIdentityMatrix) { 17599 int transX = 0; 17600 int transY = 0; 17601 17602 if (offsetForScroll) { 17603 transX = -sx; 17604 transY = -sy; 17605 } 17606 17607 if (transformToApply != null) { 17608 if (concatMatrix) { 17609 if (drawingWithRenderNode) { 17610 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 17611 } else { 17612 // Undo the scroll translation, apply the transformation matrix, 17613 // then redo the scroll translate to get the correct result. 17614 canvas.translate(-transX, -transY); 17615 canvas.concat(transformToApply.getMatrix()); 17616 canvas.translate(transX, transY); 17617 } 17618 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17619 } 17620 17621 float transformAlpha = transformToApply.getAlpha(); 17622 if (transformAlpha < 1) { 17623 alpha *= transformAlpha; 17624 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17625 } 17626 } 17627 17628 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 17629 canvas.translate(-transX, -transY); 17630 canvas.concat(getMatrix()); 17631 canvas.translate(transX, transY); 17632 } 17633 } 17634 17635 // Deal with alpha if it is or used to be <1 17636 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17637 if (alpha < 1) { 17638 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17639 } else { 17640 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17641 } 17642 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17643 if (!drawingWithDrawingCache) { 17644 final int multipliedAlpha = (int) (255 * alpha); 17645 if (!onSetAlpha(multipliedAlpha)) { 17646 if (drawingWithRenderNode) { 17647 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 17648 } else if (layerType == LAYER_TYPE_NONE) { 17649 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 17650 multipliedAlpha); 17651 } 17652 } else { 17653 // Alpha is handled by the child directly, clobber the layer's alpha 17654 mPrivateFlags |= PFLAG_ALPHA_SET; 17655 } 17656 } 17657 } 17658 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17659 onSetAlpha(255); 17660 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17661 } 17662 17663 if (!drawingWithRenderNode) { 17664 // apply clips directly, since RenderNode won't do it for this draw 17665 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 17666 if (offsetForScroll) { 17667 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 17668 } else { 17669 if (!scalingRequired || cache == null) { 17670 canvas.clipRect(0, 0, getWidth(), getHeight()); 17671 } else { 17672 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 17673 } 17674 } 17675 } 17676 17677 if (mClipBounds != null) { 17678 // clip bounds ignore scroll 17679 canvas.clipRect(mClipBounds); 17680 } 17681 } 17682 17683 if (!drawingWithDrawingCache) { 17684 if (drawingWithRenderNode) { 17685 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17686 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 17687 } else { 17688 // Fast path for layouts with no backgrounds 17689 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17690 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17691 dispatchDraw(canvas); 17692 } else { 17693 draw(canvas); 17694 } 17695 } 17696 } else if (cache != null) { 17697 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17698 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 17699 // no layer paint, use temporary paint to draw bitmap 17700 Paint cachePaint = parent.mCachePaint; 17701 if (cachePaint == null) { 17702 cachePaint = new Paint(); 17703 cachePaint.setDither(false); 17704 parent.mCachePaint = cachePaint; 17705 } 17706 cachePaint.setAlpha((int) (alpha * 255)); 17707 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 17708 } else { 17709 // use layer paint to draw the bitmap, merging the two alphas, but also restore 17710 int layerPaintAlpha = mLayerPaint.getAlpha(); 17711 if (alpha < 1) { 17712 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 17713 } 17714 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 17715 if (alpha < 1) { 17716 mLayerPaint.setAlpha(layerPaintAlpha); 17717 } 17718 } 17719 } 17720 17721 if (restoreTo >= 0) { 17722 canvas.restoreToCount(restoreTo); 17723 } 17724 17725 if (a != null && !more) { 17726 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 17727 onSetAlpha(255); 17728 } 17729 parent.finishAnimatingView(this, a); 17730 } 17731 17732 if (more && hardwareAcceleratedCanvas) { 17733 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17734 // alpha animations should cause the child to recreate its display list 17735 invalidate(true); 17736 } 17737 } 17738 17739 mRecreateDisplayList = false; 17740 17741 return more; 17742 } 17743 17744 static Paint getDebugPaint() { 17745 if (sDebugPaint == null) { 17746 sDebugPaint = new Paint(); 17747 sDebugPaint.setAntiAlias(false); 17748 } 17749 return sDebugPaint; 17750 } 17751 17752 final int dipsToPixels(int dips) { 17753 float scale = getContext().getResources().getDisplayMetrics().density; 17754 return (int) (dips * scale + 0.5f); 17755 } 17756 17757 final private void debugDrawFocus(Canvas canvas) { 17758 if (isFocused()) { 17759 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 17760 final int l = mScrollX; 17761 final int r = l + mRight - mLeft; 17762 final int t = mScrollY; 17763 final int b = t + mBottom - mTop; 17764 17765 final Paint paint = getDebugPaint(); 17766 paint.setColor(DEBUG_CORNERS_COLOR); 17767 17768 // Draw squares in corners. 17769 paint.setStyle(Paint.Style.FILL); 17770 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 17771 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 17772 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 17773 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 17774 17775 // Draw big X across the view. 17776 paint.setStyle(Paint.Style.STROKE); 17777 canvas.drawLine(l, t, r, b, paint); 17778 canvas.drawLine(l, b, r, t, paint); 17779 } 17780 } 17781 17782 /** 17783 * Manually render this view (and all of its children) to the given Canvas. 17784 * The view must have already done a full layout before this function is 17785 * called. When implementing a view, implement 17786 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 17787 * If you do need to override this method, call the superclass version. 17788 * 17789 * @param canvas The Canvas to which the View is rendered. 17790 */ 17791 @CallSuper 17792 public void draw(Canvas canvas) { 17793 final int privateFlags = mPrivateFlags; 17794 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 17795 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 17796 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 17797 17798 /* 17799 * Draw traversal performs several drawing steps which must be executed 17800 * in the appropriate order: 17801 * 17802 * 1. Draw the background 17803 * 2. If necessary, save the canvas' layers to prepare for fading 17804 * 3. Draw view's content 17805 * 4. Draw children 17806 * 5. If necessary, draw the fading edges and restore layers 17807 * 6. Draw decorations (scrollbars for instance) 17808 */ 17809 17810 // Step 1, draw the background, if needed 17811 int saveCount; 17812 17813 if (!dirtyOpaque) { 17814 drawBackground(canvas); 17815 } 17816 17817 // skip step 2 & 5 if possible (common case) 17818 final int viewFlags = mViewFlags; 17819 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 17820 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 17821 if (!verticalEdges && !horizontalEdges) { 17822 // Step 3, draw the content 17823 if (!dirtyOpaque) onDraw(canvas); 17824 17825 // Step 4, draw the children 17826 dispatchDraw(canvas); 17827 17828 // Overlay is part of the content and draws beneath Foreground 17829 if (mOverlay != null && !mOverlay.isEmpty()) { 17830 mOverlay.getOverlayView().dispatchDraw(canvas); 17831 } 17832 17833 // Step 6, draw decorations (foreground, scrollbars) 17834 onDrawForeground(canvas); 17835 17836 if (debugDraw()) { 17837 debugDrawFocus(canvas); 17838 } 17839 17840 // we're done... 17841 return; 17842 } 17843 17844 /* 17845 * Here we do the full fledged routine... 17846 * (this is an uncommon case where speed matters less, 17847 * this is why we repeat some of the tests that have been 17848 * done above) 17849 */ 17850 17851 boolean drawTop = false; 17852 boolean drawBottom = false; 17853 boolean drawLeft = false; 17854 boolean drawRight = false; 17855 17856 float topFadeStrength = 0.0f; 17857 float bottomFadeStrength = 0.0f; 17858 float leftFadeStrength = 0.0f; 17859 float rightFadeStrength = 0.0f; 17860 17861 // Step 2, save the canvas' layers 17862 int paddingLeft = mPaddingLeft; 17863 17864 final boolean offsetRequired = isPaddingOffsetRequired(); 17865 if (offsetRequired) { 17866 paddingLeft += getLeftPaddingOffset(); 17867 } 17868 17869 int left = mScrollX + paddingLeft; 17870 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 17871 int top = mScrollY + getFadeTop(offsetRequired); 17872 int bottom = top + getFadeHeight(offsetRequired); 17873 17874 if (offsetRequired) { 17875 right += getRightPaddingOffset(); 17876 bottom += getBottomPaddingOffset(); 17877 } 17878 17879 final ScrollabilityCache scrollabilityCache = mScrollCache; 17880 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 17881 int length = (int) fadeHeight; 17882 17883 // clip the fade length if top and bottom fades overlap 17884 // overlapping fades produce odd-looking artifacts 17885 if (verticalEdges && (top + length > bottom - length)) { 17886 length = (bottom - top) / 2; 17887 } 17888 17889 // also clip horizontal fades if necessary 17890 if (horizontalEdges && (left + length > right - length)) { 17891 length = (right - left) / 2; 17892 } 17893 17894 if (verticalEdges) { 17895 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 17896 drawTop = topFadeStrength * fadeHeight > 1.0f; 17897 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 17898 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 17899 } 17900 17901 if (horizontalEdges) { 17902 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 17903 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 17904 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 17905 drawRight = rightFadeStrength * fadeHeight > 1.0f; 17906 } 17907 17908 saveCount = canvas.getSaveCount(); 17909 17910 int solidColor = getSolidColor(); 17911 if (solidColor == 0) { 17912 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 17913 17914 if (drawTop) { 17915 canvas.saveLayer(left, top, right, top + length, null, flags); 17916 } 17917 17918 if (drawBottom) { 17919 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 17920 } 17921 17922 if (drawLeft) { 17923 canvas.saveLayer(left, top, left + length, bottom, null, flags); 17924 } 17925 17926 if (drawRight) { 17927 canvas.saveLayer(right - length, top, right, bottom, null, flags); 17928 } 17929 } else { 17930 scrollabilityCache.setFadeColor(solidColor); 17931 } 17932 17933 // Step 3, draw the content 17934 if (!dirtyOpaque) onDraw(canvas); 17935 17936 // Step 4, draw the children 17937 dispatchDraw(canvas); 17938 17939 // Step 5, draw the fade effect and restore layers 17940 final Paint p = scrollabilityCache.paint; 17941 final Matrix matrix = scrollabilityCache.matrix; 17942 final Shader fade = scrollabilityCache.shader; 17943 17944 if (drawTop) { 17945 matrix.setScale(1, fadeHeight * topFadeStrength); 17946 matrix.postTranslate(left, top); 17947 fade.setLocalMatrix(matrix); 17948 p.setShader(fade); 17949 canvas.drawRect(left, top, right, top + length, p); 17950 } 17951 17952 if (drawBottom) { 17953 matrix.setScale(1, fadeHeight * bottomFadeStrength); 17954 matrix.postRotate(180); 17955 matrix.postTranslate(left, bottom); 17956 fade.setLocalMatrix(matrix); 17957 p.setShader(fade); 17958 canvas.drawRect(left, bottom - length, right, bottom, p); 17959 } 17960 17961 if (drawLeft) { 17962 matrix.setScale(1, fadeHeight * leftFadeStrength); 17963 matrix.postRotate(-90); 17964 matrix.postTranslate(left, top); 17965 fade.setLocalMatrix(matrix); 17966 p.setShader(fade); 17967 canvas.drawRect(left, top, left + length, bottom, p); 17968 } 17969 17970 if (drawRight) { 17971 matrix.setScale(1, fadeHeight * rightFadeStrength); 17972 matrix.postRotate(90); 17973 matrix.postTranslate(right, top); 17974 fade.setLocalMatrix(matrix); 17975 p.setShader(fade); 17976 canvas.drawRect(right - length, top, right, bottom, p); 17977 } 17978 17979 canvas.restoreToCount(saveCount); 17980 17981 // Overlay is part of the content and draws beneath Foreground 17982 if (mOverlay != null && !mOverlay.isEmpty()) { 17983 mOverlay.getOverlayView().dispatchDraw(canvas); 17984 } 17985 17986 // Step 6, draw decorations (foreground, scrollbars) 17987 onDrawForeground(canvas); 17988 17989 if (debugDraw()) { 17990 debugDrawFocus(canvas); 17991 } 17992 } 17993 17994 /** 17995 * Draws the background onto the specified canvas. 17996 * 17997 * @param canvas Canvas on which to draw the background 17998 */ 17999 private void drawBackground(Canvas canvas) { 18000 final Drawable background = mBackground; 18001 if (background == null) { 18002 return; 18003 } 18004 18005 setBackgroundBounds(); 18006 18007 // Attempt to use a display list if requested. 18008 if (canvas.isHardwareAccelerated() && mAttachInfo != null 18009 && mAttachInfo.mThreadedRenderer != null) { 18010 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 18011 18012 final RenderNode renderNode = mBackgroundRenderNode; 18013 if (renderNode != null && renderNode.isValid()) { 18014 setBackgroundRenderNodeProperties(renderNode); 18015 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18016 return; 18017 } 18018 } 18019 18020 final int scrollX = mScrollX; 18021 final int scrollY = mScrollY; 18022 if ((scrollX | scrollY) == 0) { 18023 background.draw(canvas); 18024 } else { 18025 canvas.translate(scrollX, scrollY); 18026 background.draw(canvas); 18027 canvas.translate(-scrollX, -scrollY); 18028 } 18029 } 18030 18031 /** 18032 * Sets the correct background bounds and rebuilds the outline, if needed. 18033 * <p/> 18034 * This is called by LayoutLib. 18035 */ 18036 void setBackgroundBounds() { 18037 if (mBackgroundSizeChanged && mBackground != null) { 18038 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 18039 mBackgroundSizeChanged = false; 18040 rebuildOutline(); 18041 } 18042 } 18043 18044 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 18045 renderNode.setTranslationX(mScrollX); 18046 renderNode.setTranslationY(mScrollY); 18047 } 18048 18049 /** 18050 * Creates a new display list or updates the existing display list for the 18051 * specified Drawable. 18052 * 18053 * @param drawable Drawable for which to create a display list 18054 * @param renderNode Existing RenderNode, or {@code null} 18055 * @return A valid display list for the specified drawable 18056 */ 18057 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 18058 if (renderNode == null) { 18059 renderNode = RenderNode.create(drawable.getClass().getName(), this); 18060 } 18061 18062 final Rect bounds = drawable.getBounds(); 18063 final int width = bounds.width(); 18064 final int height = bounds.height(); 18065 final DisplayListCanvas canvas = renderNode.start(width, height); 18066 18067 // Reverse left/top translation done by drawable canvas, which will 18068 // instead be applied by rendernode's LTRB bounds below. This way, the 18069 // drawable's bounds match with its rendernode bounds and its content 18070 // will lie within those bounds in the rendernode tree. 18071 canvas.translate(-bounds.left, -bounds.top); 18072 18073 try { 18074 drawable.draw(canvas); 18075 } finally { 18076 renderNode.end(canvas); 18077 } 18078 18079 // Set up drawable properties that are view-independent. 18080 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 18081 renderNode.setProjectBackwards(drawable.isProjected()); 18082 renderNode.setProjectionReceiver(true); 18083 renderNode.setClipToBounds(false); 18084 return renderNode; 18085 } 18086 18087 /** 18088 * Returns the overlay for this view, creating it if it does not yet exist. 18089 * Adding drawables to the overlay will cause them to be displayed whenever 18090 * the view itself is redrawn. Objects in the overlay should be actively 18091 * managed: remove them when they should not be displayed anymore. The 18092 * overlay will always have the same size as its host view. 18093 * 18094 * <p>Note: Overlays do not currently work correctly with {@link 18095 * SurfaceView} or {@link TextureView}; contents in overlays for these 18096 * types of views may not display correctly.</p> 18097 * 18098 * @return The ViewOverlay object for this view. 18099 * @see ViewOverlay 18100 */ 18101 public ViewOverlay getOverlay() { 18102 if (mOverlay == null) { 18103 mOverlay = new ViewOverlay(mContext, this); 18104 } 18105 return mOverlay; 18106 } 18107 18108 /** 18109 * Override this if your view is known to always be drawn on top of a solid color background, 18110 * and needs to draw fading edges. Returning a non-zero color enables the view system to 18111 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 18112 * should be set to 0xFF. 18113 * 18114 * @see #setVerticalFadingEdgeEnabled(boolean) 18115 * @see #setHorizontalFadingEdgeEnabled(boolean) 18116 * 18117 * @return The known solid color background for this view, or 0 if the color may vary 18118 */ 18119 @ViewDebug.ExportedProperty(category = "drawing") 18120 @ColorInt 18121 public int getSolidColor() { 18122 return 0; 18123 } 18124 18125 /** 18126 * Build a human readable string representation of the specified view flags. 18127 * 18128 * @param flags the view flags to convert to a string 18129 * @return a String representing the supplied flags 18130 */ 18131 private static String printFlags(int flags) { 18132 String output = ""; 18133 int numFlags = 0; 18134 if ((flags & FOCUSABLE) == FOCUSABLE) { 18135 output += "TAKES_FOCUS"; 18136 numFlags++; 18137 } 18138 18139 switch (flags & VISIBILITY_MASK) { 18140 case INVISIBLE: 18141 if (numFlags > 0) { 18142 output += " "; 18143 } 18144 output += "INVISIBLE"; 18145 // USELESS HERE numFlags++; 18146 break; 18147 case GONE: 18148 if (numFlags > 0) { 18149 output += " "; 18150 } 18151 output += "GONE"; 18152 // USELESS HERE numFlags++; 18153 break; 18154 default: 18155 break; 18156 } 18157 return output; 18158 } 18159 18160 /** 18161 * Build a human readable string representation of the specified private 18162 * view flags. 18163 * 18164 * @param privateFlags the private view flags to convert to a string 18165 * @return a String representing the supplied flags 18166 */ 18167 private static String printPrivateFlags(int privateFlags) { 18168 String output = ""; 18169 int numFlags = 0; 18170 18171 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 18172 output += "WANTS_FOCUS"; 18173 numFlags++; 18174 } 18175 18176 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 18177 if (numFlags > 0) { 18178 output += " "; 18179 } 18180 output += "FOCUSED"; 18181 numFlags++; 18182 } 18183 18184 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 18185 if (numFlags > 0) { 18186 output += " "; 18187 } 18188 output += "SELECTED"; 18189 numFlags++; 18190 } 18191 18192 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 18193 if (numFlags > 0) { 18194 output += " "; 18195 } 18196 output += "IS_ROOT_NAMESPACE"; 18197 numFlags++; 18198 } 18199 18200 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 18201 if (numFlags > 0) { 18202 output += " "; 18203 } 18204 output += "HAS_BOUNDS"; 18205 numFlags++; 18206 } 18207 18208 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 18209 if (numFlags > 0) { 18210 output += " "; 18211 } 18212 output += "DRAWN"; 18213 // USELESS HERE numFlags++; 18214 } 18215 return output; 18216 } 18217 18218 /** 18219 * <p>Indicates whether or not this view's layout will be requested during 18220 * the next hierarchy layout pass.</p> 18221 * 18222 * @return true if the layout will be forced during next layout pass 18223 */ 18224 public boolean isLayoutRequested() { 18225 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 18226 } 18227 18228 /** 18229 * Return true if o is a ViewGroup that is laying out using optical bounds. 18230 * @hide 18231 */ 18232 public static boolean isLayoutModeOptical(Object o) { 18233 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 18234 } 18235 18236 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 18237 Insets parentInsets = mParent instanceof View ? 18238 ((View) mParent).getOpticalInsets() : Insets.NONE; 18239 Insets childInsets = getOpticalInsets(); 18240 return setFrame( 18241 left + parentInsets.left - childInsets.left, 18242 top + parentInsets.top - childInsets.top, 18243 right + parentInsets.left + childInsets.right, 18244 bottom + parentInsets.top + childInsets.bottom); 18245 } 18246 18247 /** 18248 * Assign a size and position to a view and all of its 18249 * descendants 18250 * 18251 * <p>This is the second phase of the layout mechanism. 18252 * (The first is measuring). In this phase, each parent calls 18253 * layout on all of its children to position them. 18254 * This is typically done using the child measurements 18255 * that were stored in the measure pass().</p> 18256 * 18257 * <p>Derived classes should not override this method. 18258 * Derived classes with children should override 18259 * onLayout. In that method, they should 18260 * call layout on each of their children.</p> 18261 * 18262 * @param l Left position, relative to parent 18263 * @param t Top position, relative to parent 18264 * @param r Right position, relative to parent 18265 * @param b Bottom position, relative to parent 18266 */ 18267 @SuppressWarnings({"unchecked"}) 18268 public void layout(int l, int t, int r, int b) { 18269 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 18270 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 18271 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 18272 } 18273 18274 int oldL = mLeft; 18275 int oldT = mTop; 18276 int oldB = mBottom; 18277 int oldR = mRight; 18278 18279 boolean changed = isLayoutModeOptical(mParent) ? 18280 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 18281 18282 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 18283 onLayout(changed, l, t, r, b); 18284 18285 if (shouldDrawRoundScrollbar()) { 18286 if(mRoundScrollbarRenderer == null) { 18287 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 18288 } 18289 } else { 18290 mRoundScrollbarRenderer = null; 18291 } 18292 18293 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 18294 18295 ListenerInfo li = mListenerInfo; 18296 if (li != null && li.mOnLayoutChangeListeners != null) { 18297 ArrayList<OnLayoutChangeListener> listenersCopy = 18298 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 18299 int numListeners = listenersCopy.size(); 18300 for (int i = 0; i < numListeners; ++i) { 18301 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 18302 } 18303 } 18304 } 18305 18306 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 18307 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 18308 } 18309 18310 /** 18311 * Called from layout when this view should 18312 * assign a size and position to each of its children. 18313 * 18314 * Derived classes with children should override 18315 * this method and call layout on each of 18316 * their children. 18317 * @param changed This is a new size or position for this view 18318 * @param left Left position, relative to parent 18319 * @param top Top position, relative to parent 18320 * @param right Right position, relative to parent 18321 * @param bottom Bottom position, relative to parent 18322 */ 18323 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 18324 } 18325 18326 /** 18327 * Assign a size and position to this view. 18328 * 18329 * This is called from layout. 18330 * 18331 * @param left Left position, relative to parent 18332 * @param top Top position, relative to parent 18333 * @param right Right position, relative to parent 18334 * @param bottom Bottom position, relative to parent 18335 * @return true if the new size and position are different than the 18336 * previous ones 18337 * {@hide} 18338 */ 18339 protected boolean setFrame(int left, int top, int right, int bottom) { 18340 boolean changed = false; 18341 18342 if (DBG) { 18343 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 18344 + right + "," + bottom + ")"); 18345 } 18346 18347 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 18348 changed = true; 18349 18350 // Remember our drawn bit 18351 int drawn = mPrivateFlags & PFLAG_DRAWN; 18352 18353 int oldWidth = mRight - mLeft; 18354 int oldHeight = mBottom - mTop; 18355 int newWidth = right - left; 18356 int newHeight = bottom - top; 18357 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 18358 18359 // Invalidate our old position 18360 invalidate(sizeChanged); 18361 18362 mLeft = left; 18363 mTop = top; 18364 mRight = right; 18365 mBottom = bottom; 18366 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 18367 18368 mPrivateFlags |= PFLAG_HAS_BOUNDS; 18369 18370 18371 if (sizeChanged) { 18372 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 18373 } 18374 18375 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 18376 // If we are visible, force the DRAWN bit to on so that 18377 // this invalidate will go through (at least to our parent). 18378 // This is because someone may have invalidated this view 18379 // before this call to setFrame came in, thereby clearing 18380 // the DRAWN bit. 18381 mPrivateFlags |= PFLAG_DRAWN; 18382 invalidate(sizeChanged); 18383 // parent display list may need to be recreated based on a change in the bounds 18384 // of any child 18385 invalidateParentCaches(); 18386 } 18387 18388 // Reset drawn bit to original value (invalidate turns it off) 18389 mPrivateFlags |= drawn; 18390 18391 mBackgroundSizeChanged = true; 18392 if (mForegroundInfo != null) { 18393 mForegroundInfo.mBoundsChanged = true; 18394 } 18395 18396 notifySubtreeAccessibilityStateChangedIfNeeded(); 18397 } 18398 return changed; 18399 } 18400 18401 /** 18402 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 18403 * @hide 18404 */ 18405 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 18406 setFrame(left, top, right, bottom); 18407 } 18408 18409 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 18410 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 18411 if (mOverlay != null) { 18412 mOverlay.getOverlayView().setRight(newWidth); 18413 mOverlay.getOverlayView().setBottom(newHeight); 18414 } 18415 rebuildOutline(); 18416 } 18417 18418 /** 18419 * Finalize inflating a view from XML. This is called as the last phase 18420 * of inflation, after all child views have been added. 18421 * 18422 * <p>Even if the subclass overrides onFinishInflate, they should always be 18423 * sure to call the super method, so that we get called. 18424 */ 18425 @CallSuper 18426 protected void onFinishInflate() { 18427 } 18428 18429 /** 18430 * Returns the resources associated with this view. 18431 * 18432 * @return Resources object. 18433 */ 18434 public Resources getResources() { 18435 return mResources; 18436 } 18437 18438 /** 18439 * Invalidates the specified Drawable. 18440 * 18441 * @param drawable the drawable to invalidate 18442 */ 18443 @Override 18444 public void invalidateDrawable(@NonNull Drawable drawable) { 18445 if (verifyDrawable(drawable)) { 18446 final Rect dirty = drawable.getDirtyBounds(); 18447 final int scrollX = mScrollX; 18448 final int scrollY = mScrollY; 18449 18450 invalidate(dirty.left + scrollX, dirty.top + scrollY, 18451 dirty.right + scrollX, dirty.bottom + scrollY); 18452 rebuildOutline(); 18453 } 18454 } 18455 18456 /** 18457 * Schedules an action on a drawable to occur at a specified time. 18458 * 18459 * @param who the recipient of the action 18460 * @param what the action to run on the drawable 18461 * @param when the time at which the action must occur. Uses the 18462 * {@link SystemClock#uptimeMillis} timebase. 18463 */ 18464 @Override 18465 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 18466 if (verifyDrawable(who) && what != null) { 18467 final long delay = when - SystemClock.uptimeMillis(); 18468 if (mAttachInfo != null) { 18469 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 18470 Choreographer.CALLBACK_ANIMATION, what, who, 18471 Choreographer.subtractFrameDelay(delay)); 18472 } else { 18473 // Postpone the runnable until we know 18474 // on which thread it needs to run. 18475 getRunQueue().postDelayed(what, delay); 18476 } 18477 } 18478 } 18479 18480 /** 18481 * Cancels a scheduled action on a drawable. 18482 * 18483 * @param who the recipient of the action 18484 * @param what the action to cancel 18485 */ 18486 @Override 18487 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 18488 if (verifyDrawable(who) && what != null) { 18489 if (mAttachInfo != null) { 18490 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18491 Choreographer.CALLBACK_ANIMATION, what, who); 18492 } 18493 getRunQueue().removeCallbacks(what); 18494 } 18495 } 18496 18497 /** 18498 * Unschedule any events associated with the given Drawable. This can be 18499 * used when selecting a new Drawable into a view, so that the previous 18500 * one is completely unscheduled. 18501 * 18502 * @param who The Drawable to unschedule. 18503 * 18504 * @see #drawableStateChanged 18505 */ 18506 public void unscheduleDrawable(Drawable who) { 18507 if (mAttachInfo != null && who != null) { 18508 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18509 Choreographer.CALLBACK_ANIMATION, null, who); 18510 } 18511 } 18512 18513 /** 18514 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 18515 * that the View directionality can and will be resolved before its Drawables. 18516 * 18517 * Will call {@link View#onResolveDrawables} when resolution is done. 18518 * 18519 * @hide 18520 */ 18521 protected void resolveDrawables() { 18522 // Drawables resolution may need to happen before resolving the layout direction (which is 18523 // done only during the measure() call). 18524 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 18525 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 18526 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 18527 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 18528 // direction to be resolved as its resolved value will be the same as its raw value. 18529 if (!isLayoutDirectionResolved() && 18530 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 18531 return; 18532 } 18533 18534 final int layoutDirection = isLayoutDirectionResolved() ? 18535 getLayoutDirection() : getRawLayoutDirection(); 18536 18537 if (mBackground != null) { 18538 mBackground.setLayoutDirection(layoutDirection); 18539 } 18540 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18541 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 18542 } 18543 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 18544 onResolveDrawables(layoutDirection); 18545 } 18546 18547 boolean areDrawablesResolved() { 18548 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 18549 } 18550 18551 /** 18552 * Called when layout direction has been resolved. 18553 * 18554 * The default implementation does nothing. 18555 * 18556 * @param layoutDirection The resolved layout direction. 18557 * 18558 * @see #LAYOUT_DIRECTION_LTR 18559 * @see #LAYOUT_DIRECTION_RTL 18560 * 18561 * @hide 18562 */ 18563 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 18564 } 18565 18566 /** 18567 * @hide 18568 */ 18569 protected void resetResolvedDrawables() { 18570 resetResolvedDrawablesInternal(); 18571 } 18572 18573 void resetResolvedDrawablesInternal() { 18574 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 18575 } 18576 18577 /** 18578 * If your view subclass is displaying its own Drawable objects, it should 18579 * override this function and return true for any Drawable it is 18580 * displaying. This allows animations for those drawables to be 18581 * scheduled. 18582 * 18583 * <p>Be sure to call through to the super class when overriding this 18584 * function. 18585 * 18586 * @param who The Drawable to verify. Return true if it is one you are 18587 * displaying, else return the result of calling through to the 18588 * super class. 18589 * 18590 * @return boolean If true than the Drawable is being displayed in the 18591 * view; else false and it is not allowed to animate. 18592 * 18593 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 18594 * @see #drawableStateChanged() 18595 */ 18596 @CallSuper 18597 protected boolean verifyDrawable(@NonNull Drawable who) { 18598 // Avoid verifying the scroll bar drawable so that we don't end up in 18599 // an invalidation loop. This effectively prevents the scroll bar 18600 // drawable from triggering invalidations and scheduling runnables. 18601 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); 18602 } 18603 18604 /** 18605 * This function is called whenever the state of the view changes in such 18606 * a way that it impacts the state of drawables being shown. 18607 * <p> 18608 * If the View has a StateListAnimator, it will also be called to run necessary state 18609 * change animations. 18610 * <p> 18611 * Be sure to call through to the superclass when overriding this function. 18612 * 18613 * @see Drawable#setState(int[]) 18614 */ 18615 @CallSuper 18616 protected void drawableStateChanged() { 18617 final int[] state = getDrawableState(); 18618 boolean changed = false; 18619 18620 final Drawable bg = mBackground; 18621 if (bg != null && bg.isStateful()) { 18622 changed |= bg.setState(state); 18623 } 18624 18625 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 18626 if (fg != null && fg.isStateful()) { 18627 changed |= fg.setState(state); 18628 } 18629 18630 if (mScrollCache != null) { 18631 final Drawable scrollBar = mScrollCache.scrollBar; 18632 if (scrollBar != null && scrollBar.isStateful()) { 18633 changed |= scrollBar.setState(state) 18634 && mScrollCache.state != ScrollabilityCache.OFF; 18635 } 18636 } 18637 18638 if (mStateListAnimator != null) { 18639 mStateListAnimator.setState(state); 18640 } 18641 18642 if (changed) { 18643 invalidate(); 18644 } 18645 } 18646 18647 /** 18648 * This function is called whenever the view hotspot changes and needs to 18649 * be propagated to drawables or child views managed by the view. 18650 * <p> 18651 * Dispatching to child views is handled by 18652 * {@link #dispatchDrawableHotspotChanged(float, float)}. 18653 * <p> 18654 * Be sure to call through to the superclass when overriding this function. 18655 * 18656 * @param x hotspot x coordinate 18657 * @param y hotspot y coordinate 18658 */ 18659 @CallSuper 18660 public void drawableHotspotChanged(float x, float y) { 18661 if (mBackground != null) { 18662 mBackground.setHotspot(x, y); 18663 } 18664 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18665 mForegroundInfo.mDrawable.setHotspot(x, y); 18666 } 18667 18668 dispatchDrawableHotspotChanged(x, y); 18669 } 18670 18671 /** 18672 * Dispatches drawableHotspotChanged to all of this View's children. 18673 * 18674 * @param x hotspot x coordinate 18675 * @param y hotspot y coordinate 18676 * @see #drawableHotspotChanged(float, float) 18677 */ 18678 public void dispatchDrawableHotspotChanged(float x, float y) { 18679 } 18680 18681 /** 18682 * Call this to force a view to update its drawable state. This will cause 18683 * drawableStateChanged to be called on this view. Views that are interested 18684 * in the new state should call getDrawableState. 18685 * 18686 * @see #drawableStateChanged 18687 * @see #getDrawableState 18688 */ 18689 public void refreshDrawableState() { 18690 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 18691 drawableStateChanged(); 18692 18693 ViewParent parent = mParent; 18694 if (parent != null) { 18695 parent.childDrawableStateChanged(this); 18696 } 18697 } 18698 18699 /** 18700 * Return an array of resource IDs of the drawable states representing the 18701 * current state of the view. 18702 * 18703 * @return The current drawable state 18704 * 18705 * @see Drawable#setState(int[]) 18706 * @see #drawableStateChanged() 18707 * @see #onCreateDrawableState(int) 18708 */ 18709 public final int[] getDrawableState() { 18710 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 18711 return mDrawableState; 18712 } else { 18713 mDrawableState = onCreateDrawableState(0); 18714 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 18715 return mDrawableState; 18716 } 18717 } 18718 18719 /** 18720 * Generate the new {@link android.graphics.drawable.Drawable} state for 18721 * this view. This is called by the view 18722 * system when the cached Drawable state is determined to be invalid. To 18723 * retrieve the current state, you should use {@link #getDrawableState}. 18724 * 18725 * @param extraSpace if non-zero, this is the number of extra entries you 18726 * would like in the returned array in which you can place your own 18727 * states. 18728 * 18729 * @return Returns an array holding the current {@link Drawable} state of 18730 * the view. 18731 * 18732 * @see #mergeDrawableStates(int[], int[]) 18733 */ 18734 protected int[] onCreateDrawableState(int extraSpace) { 18735 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 18736 mParent instanceof View) { 18737 return ((View) mParent).onCreateDrawableState(extraSpace); 18738 } 18739 18740 int[] drawableState; 18741 18742 int privateFlags = mPrivateFlags; 18743 18744 int viewStateIndex = 0; 18745 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 18746 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 18747 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 18748 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 18749 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 18750 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 18751 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 18752 ThreadedRenderer.isAvailable()) { 18753 // This is set if HW acceleration is requested, even if the current 18754 // process doesn't allow it. This is just to allow app preview 18755 // windows to better match their app. 18756 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 18757 } 18758 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 18759 18760 final int privateFlags2 = mPrivateFlags2; 18761 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 18762 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 18763 } 18764 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 18765 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 18766 } 18767 18768 drawableState = StateSet.get(viewStateIndex); 18769 18770 //noinspection ConstantIfStatement 18771 if (false) { 18772 Log.i("View", "drawableStateIndex=" + viewStateIndex); 18773 Log.i("View", toString() 18774 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 18775 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 18776 + " fo=" + hasFocus() 18777 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 18778 + " wf=" + hasWindowFocus() 18779 + ": " + Arrays.toString(drawableState)); 18780 } 18781 18782 if (extraSpace == 0) { 18783 return drawableState; 18784 } 18785 18786 final int[] fullState; 18787 if (drawableState != null) { 18788 fullState = new int[drawableState.length + extraSpace]; 18789 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 18790 } else { 18791 fullState = new int[extraSpace]; 18792 } 18793 18794 return fullState; 18795 } 18796 18797 /** 18798 * Merge your own state values in <var>additionalState</var> into the base 18799 * state values <var>baseState</var> that were returned by 18800 * {@link #onCreateDrawableState(int)}. 18801 * 18802 * @param baseState The base state values returned by 18803 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 18804 * own additional state values. 18805 * 18806 * @param additionalState The additional state values you would like 18807 * added to <var>baseState</var>; this array is not modified. 18808 * 18809 * @return As a convenience, the <var>baseState</var> array you originally 18810 * passed into the function is returned. 18811 * 18812 * @see #onCreateDrawableState(int) 18813 */ 18814 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 18815 final int N = baseState.length; 18816 int i = N - 1; 18817 while (i >= 0 && baseState[i] == 0) { 18818 i--; 18819 } 18820 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 18821 return baseState; 18822 } 18823 18824 /** 18825 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 18826 * on all Drawable objects associated with this view. 18827 * <p> 18828 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 18829 * attached to this view. 18830 */ 18831 @CallSuper 18832 public void jumpDrawablesToCurrentState() { 18833 if (mBackground != null) { 18834 mBackground.jumpToCurrentState(); 18835 } 18836 if (mStateListAnimator != null) { 18837 mStateListAnimator.jumpToCurrentState(); 18838 } 18839 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18840 mForegroundInfo.mDrawable.jumpToCurrentState(); 18841 } 18842 } 18843 18844 /** 18845 * Sets the background color for this view. 18846 * @param color the color of the background 18847 */ 18848 @RemotableViewMethod 18849 public void setBackgroundColor(@ColorInt int color) { 18850 if (mBackground instanceof ColorDrawable) { 18851 ((ColorDrawable) mBackground.mutate()).setColor(color); 18852 computeOpaqueFlags(); 18853 mBackgroundResource = 0; 18854 } else { 18855 setBackground(new ColorDrawable(color)); 18856 } 18857 } 18858 18859 /** 18860 * Set the background to a given resource. The resource should refer to 18861 * a Drawable object or 0 to remove the background. 18862 * @param resid The identifier of the resource. 18863 * 18864 * @attr ref android.R.styleable#View_background 18865 */ 18866 @RemotableViewMethod 18867 public void setBackgroundResource(@DrawableRes int resid) { 18868 if (resid != 0 && resid == mBackgroundResource) { 18869 return; 18870 } 18871 18872 Drawable d = null; 18873 if (resid != 0) { 18874 d = mContext.getDrawable(resid); 18875 } 18876 setBackground(d); 18877 18878 mBackgroundResource = resid; 18879 } 18880 18881 /** 18882 * Set the background to a given Drawable, or remove the background. If the 18883 * background has padding, this View's padding is set to the background's 18884 * padding. However, when a background is removed, this View's padding isn't 18885 * touched. If setting the padding is desired, please use 18886 * {@link #setPadding(int, int, int, int)}. 18887 * 18888 * @param background The Drawable to use as the background, or null to remove the 18889 * background 18890 */ 18891 public void setBackground(Drawable background) { 18892 //noinspection deprecation 18893 setBackgroundDrawable(background); 18894 } 18895 18896 /** 18897 * @deprecated use {@link #setBackground(Drawable)} instead 18898 */ 18899 @Deprecated 18900 public void setBackgroundDrawable(Drawable background) { 18901 computeOpaqueFlags(); 18902 18903 if (background == mBackground) { 18904 return; 18905 } 18906 18907 boolean requestLayout = false; 18908 18909 mBackgroundResource = 0; 18910 18911 /* 18912 * Regardless of whether we're setting a new background or not, we want 18913 * to clear the previous drawable. setVisible first while we still have the callback set. 18914 */ 18915 if (mBackground != null) { 18916 if (isAttachedToWindow()) { 18917 mBackground.setVisible(false, false); 18918 } 18919 mBackground.setCallback(null); 18920 unscheduleDrawable(mBackground); 18921 } 18922 18923 if (background != null) { 18924 Rect padding = sThreadLocal.get(); 18925 if (padding == null) { 18926 padding = new Rect(); 18927 sThreadLocal.set(padding); 18928 } 18929 resetResolvedDrawablesInternal(); 18930 background.setLayoutDirection(getLayoutDirection()); 18931 if (background.getPadding(padding)) { 18932 resetResolvedPaddingInternal(); 18933 switch (background.getLayoutDirection()) { 18934 case LAYOUT_DIRECTION_RTL: 18935 mUserPaddingLeftInitial = padding.right; 18936 mUserPaddingRightInitial = padding.left; 18937 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 18938 break; 18939 case LAYOUT_DIRECTION_LTR: 18940 default: 18941 mUserPaddingLeftInitial = padding.left; 18942 mUserPaddingRightInitial = padding.right; 18943 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 18944 } 18945 mLeftPaddingDefined = false; 18946 mRightPaddingDefined = false; 18947 } 18948 18949 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 18950 // if it has a different minimum size, we should layout again 18951 if (mBackground == null 18952 || mBackground.getMinimumHeight() != background.getMinimumHeight() 18953 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 18954 requestLayout = true; 18955 } 18956 18957 // Set mBackground before we set this as the callback and start making other 18958 // background drawable state change calls. In particular, the setVisible call below 18959 // can result in drawables attempting to start animations or otherwise invalidate, 18960 // which requires the view set as the callback (us) to recognize the drawable as 18961 // belonging to it as per verifyDrawable. 18962 mBackground = background; 18963 if (background.isStateful()) { 18964 background.setState(getDrawableState()); 18965 } 18966 if (isAttachedToWindow()) { 18967 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 18968 } 18969 18970 applyBackgroundTint(); 18971 18972 // Set callback last, since the view may still be initializing. 18973 background.setCallback(this); 18974 18975 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 18976 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 18977 requestLayout = true; 18978 } 18979 } else { 18980 /* Remove the background */ 18981 mBackground = null; 18982 if ((mViewFlags & WILL_NOT_DRAW) != 0 18983 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 18984 mPrivateFlags |= PFLAG_SKIP_DRAW; 18985 } 18986 18987 /* 18988 * When the background is set, we try to apply its padding to this 18989 * View. When the background is removed, we don't touch this View's 18990 * padding. This is noted in the Javadocs. Hence, we don't need to 18991 * requestLayout(), the invalidate() below is sufficient. 18992 */ 18993 18994 // The old background's minimum size could have affected this 18995 // View's layout, so let's requestLayout 18996 requestLayout = true; 18997 } 18998 18999 computeOpaqueFlags(); 19000 19001 if (requestLayout) { 19002 requestLayout(); 19003 } 19004 19005 mBackgroundSizeChanged = true; 19006 invalidate(true); 19007 invalidateOutline(); 19008 } 19009 19010 /** 19011 * Gets the background drawable 19012 * 19013 * @return The drawable used as the background for this view, if any. 19014 * 19015 * @see #setBackground(Drawable) 19016 * 19017 * @attr ref android.R.styleable#View_background 19018 */ 19019 public Drawable getBackground() { 19020 return mBackground; 19021 } 19022 19023 /** 19024 * Applies a tint to the background drawable. Does not modify the current tint 19025 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19026 * <p> 19027 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 19028 * mutate the drawable and apply the specified tint and tint mode using 19029 * {@link Drawable#setTintList(ColorStateList)}. 19030 * 19031 * @param tint the tint to apply, may be {@code null} to clear tint 19032 * 19033 * @attr ref android.R.styleable#View_backgroundTint 19034 * @see #getBackgroundTintList() 19035 * @see Drawable#setTintList(ColorStateList) 19036 */ 19037 public void setBackgroundTintList(@Nullable ColorStateList tint) { 19038 if (mBackgroundTint == null) { 19039 mBackgroundTint = new TintInfo(); 19040 } 19041 mBackgroundTint.mTintList = tint; 19042 mBackgroundTint.mHasTintList = true; 19043 19044 applyBackgroundTint(); 19045 } 19046 19047 /** 19048 * Return the tint applied to the background drawable, if specified. 19049 * 19050 * @return the tint applied to the background drawable 19051 * @attr ref android.R.styleable#View_backgroundTint 19052 * @see #setBackgroundTintList(ColorStateList) 19053 */ 19054 @Nullable 19055 public ColorStateList getBackgroundTintList() { 19056 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 19057 } 19058 19059 /** 19060 * Specifies the blending mode used to apply the tint specified by 19061 * {@link #setBackgroundTintList(ColorStateList)}} to the background 19062 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19063 * 19064 * @param tintMode the blending mode used to apply the tint, may be 19065 * {@code null} to clear tint 19066 * @attr ref android.R.styleable#View_backgroundTintMode 19067 * @see #getBackgroundTintMode() 19068 * @see Drawable#setTintMode(PorterDuff.Mode) 19069 */ 19070 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19071 if (mBackgroundTint == null) { 19072 mBackgroundTint = new TintInfo(); 19073 } 19074 mBackgroundTint.mTintMode = tintMode; 19075 mBackgroundTint.mHasTintMode = true; 19076 19077 applyBackgroundTint(); 19078 } 19079 19080 /** 19081 * Return the blending mode used to apply the tint to the background 19082 * drawable, if specified. 19083 * 19084 * @return the blending mode used to apply the tint to the background 19085 * drawable 19086 * @attr ref android.R.styleable#View_backgroundTintMode 19087 * @see #setBackgroundTintMode(PorterDuff.Mode) 19088 */ 19089 @Nullable 19090 public PorterDuff.Mode getBackgroundTintMode() { 19091 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 19092 } 19093 19094 private void applyBackgroundTint() { 19095 if (mBackground != null && mBackgroundTint != null) { 19096 final TintInfo tintInfo = mBackgroundTint; 19097 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19098 mBackground = mBackground.mutate(); 19099 19100 if (tintInfo.mHasTintList) { 19101 mBackground.setTintList(tintInfo.mTintList); 19102 } 19103 19104 if (tintInfo.mHasTintMode) { 19105 mBackground.setTintMode(tintInfo.mTintMode); 19106 } 19107 19108 // The drawable (or one of its children) may not have been 19109 // stateful before applying the tint, so let's try again. 19110 if (mBackground.isStateful()) { 19111 mBackground.setState(getDrawableState()); 19112 } 19113 } 19114 } 19115 } 19116 19117 /** 19118 * Returns the drawable used as the foreground of this View. The 19119 * foreground drawable, if non-null, is always drawn on top of the view's content. 19120 * 19121 * @return a Drawable or null if no foreground was set 19122 * 19123 * @see #onDrawForeground(Canvas) 19124 */ 19125 public Drawable getForeground() { 19126 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19127 } 19128 19129 /** 19130 * Supply a Drawable that is to be rendered on top of all of the content in the view. 19131 * 19132 * @param foreground the Drawable to be drawn on top of the children 19133 * 19134 * @attr ref android.R.styleable#View_foreground 19135 */ 19136 public void setForeground(Drawable foreground) { 19137 if (mForegroundInfo == null) { 19138 if (foreground == null) { 19139 // Nothing to do. 19140 return; 19141 } 19142 mForegroundInfo = new ForegroundInfo(); 19143 } 19144 19145 if (foreground == mForegroundInfo.mDrawable) { 19146 // Nothing to do 19147 return; 19148 } 19149 19150 if (mForegroundInfo.mDrawable != null) { 19151 if (isAttachedToWindow()) { 19152 mForegroundInfo.mDrawable.setVisible(false, false); 19153 } 19154 mForegroundInfo.mDrawable.setCallback(null); 19155 unscheduleDrawable(mForegroundInfo.mDrawable); 19156 } 19157 19158 mForegroundInfo.mDrawable = foreground; 19159 mForegroundInfo.mBoundsChanged = true; 19160 if (foreground != null) { 19161 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19162 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19163 } 19164 foreground.setLayoutDirection(getLayoutDirection()); 19165 if (foreground.isStateful()) { 19166 foreground.setState(getDrawableState()); 19167 } 19168 applyForegroundTint(); 19169 if (isAttachedToWindow()) { 19170 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 19171 } 19172 // Set callback last, since the view may still be initializing. 19173 foreground.setCallback(this); 19174 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) { 19175 mPrivateFlags |= PFLAG_SKIP_DRAW; 19176 } 19177 requestLayout(); 19178 invalidate(); 19179 } 19180 19181 /** 19182 * Magic bit used to support features of framework-internal window decor implementation details. 19183 * This used to live exclusively in FrameLayout. 19184 * 19185 * @return true if the foreground should draw inside the padding region or false 19186 * if it should draw inset by the view's padding 19187 * @hide internal use only; only used by FrameLayout and internal screen layouts. 19188 */ 19189 public boolean isForegroundInsidePadding() { 19190 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 19191 } 19192 19193 /** 19194 * Describes how the foreground is positioned. 19195 * 19196 * @return foreground gravity. 19197 * 19198 * @see #setForegroundGravity(int) 19199 * 19200 * @attr ref android.R.styleable#View_foregroundGravity 19201 */ 19202 public int getForegroundGravity() { 19203 return mForegroundInfo != null ? mForegroundInfo.mGravity 19204 : Gravity.START | Gravity.TOP; 19205 } 19206 19207 /** 19208 * Describes how the foreground is positioned. Defaults to START and TOP. 19209 * 19210 * @param gravity see {@link android.view.Gravity} 19211 * 19212 * @see #getForegroundGravity() 19213 * 19214 * @attr ref android.R.styleable#View_foregroundGravity 19215 */ 19216 public void setForegroundGravity(int gravity) { 19217 if (mForegroundInfo == null) { 19218 mForegroundInfo = new ForegroundInfo(); 19219 } 19220 19221 if (mForegroundInfo.mGravity != gravity) { 19222 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 19223 gravity |= Gravity.START; 19224 } 19225 19226 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 19227 gravity |= Gravity.TOP; 19228 } 19229 19230 mForegroundInfo.mGravity = gravity; 19231 requestLayout(); 19232 } 19233 } 19234 19235 /** 19236 * Applies a tint to the foreground drawable. Does not modify the current tint 19237 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19238 * <p> 19239 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 19240 * mutate the drawable and apply the specified tint and tint mode using 19241 * {@link Drawable#setTintList(ColorStateList)}. 19242 * 19243 * @param tint the tint to apply, may be {@code null} to clear tint 19244 * 19245 * @attr ref android.R.styleable#View_foregroundTint 19246 * @see #getForegroundTintList() 19247 * @see Drawable#setTintList(ColorStateList) 19248 */ 19249 public void setForegroundTintList(@Nullable ColorStateList tint) { 19250 if (mForegroundInfo == null) { 19251 mForegroundInfo = new ForegroundInfo(); 19252 } 19253 if (mForegroundInfo.mTintInfo == null) { 19254 mForegroundInfo.mTintInfo = new TintInfo(); 19255 } 19256 mForegroundInfo.mTintInfo.mTintList = tint; 19257 mForegroundInfo.mTintInfo.mHasTintList = true; 19258 19259 applyForegroundTint(); 19260 } 19261 19262 /** 19263 * Return the tint applied to the foreground drawable, if specified. 19264 * 19265 * @return the tint applied to the foreground drawable 19266 * @attr ref android.R.styleable#View_foregroundTint 19267 * @see #setForegroundTintList(ColorStateList) 19268 */ 19269 @Nullable 19270 public ColorStateList getForegroundTintList() { 19271 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19272 ? mForegroundInfo.mTintInfo.mTintList : null; 19273 } 19274 19275 /** 19276 * Specifies the blending mode used to apply the tint specified by 19277 * {@link #setForegroundTintList(ColorStateList)}} to the background 19278 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19279 * 19280 * @param tintMode the blending mode used to apply the tint, may be 19281 * {@code null} to clear tint 19282 * @attr ref android.R.styleable#View_foregroundTintMode 19283 * @see #getForegroundTintMode() 19284 * @see Drawable#setTintMode(PorterDuff.Mode) 19285 */ 19286 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19287 if (mForegroundInfo == null) { 19288 mForegroundInfo = new ForegroundInfo(); 19289 } 19290 if (mForegroundInfo.mTintInfo == null) { 19291 mForegroundInfo.mTintInfo = new TintInfo(); 19292 } 19293 mForegroundInfo.mTintInfo.mTintMode = tintMode; 19294 mForegroundInfo.mTintInfo.mHasTintMode = true; 19295 19296 applyForegroundTint(); 19297 } 19298 19299 /** 19300 * Return the blending mode used to apply the tint to the foreground 19301 * drawable, if specified. 19302 * 19303 * @return the blending mode used to apply the tint to the foreground 19304 * drawable 19305 * @attr ref android.R.styleable#View_foregroundTintMode 19306 * @see #setForegroundTintMode(PorterDuff.Mode) 19307 */ 19308 @Nullable 19309 public PorterDuff.Mode getForegroundTintMode() { 19310 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19311 ? mForegroundInfo.mTintInfo.mTintMode : null; 19312 } 19313 19314 private void applyForegroundTint() { 19315 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 19316 && mForegroundInfo.mTintInfo != null) { 19317 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 19318 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19319 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 19320 19321 if (tintInfo.mHasTintList) { 19322 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 19323 } 19324 19325 if (tintInfo.mHasTintMode) { 19326 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 19327 } 19328 19329 // The drawable (or one of its children) may not have been 19330 // stateful before applying the tint, so let's try again. 19331 if (mForegroundInfo.mDrawable.isStateful()) { 19332 mForegroundInfo.mDrawable.setState(getDrawableState()); 19333 } 19334 } 19335 } 19336 } 19337 19338 /** 19339 * Draw any foreground content for this view. 19340 * 19341 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 19342 * drawable or other view-specific decorations. The foreground is drawn on top of the 19343 * primary view content.</p> 19344 * 19345 * @param canvas canvas to draw into 19346 */ 19347 public void onDrawForeground(Canvas canvas) { 19348 onDrawScrollIndicators(canvas); 19349 onDrawScrollBars(canvas); 19350 19351 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19352 if (foreground != null) { 19353 if (mForegroundInfo.mBoundsChanged) { 19354 mForegroundInfo.mBoundsChanged = false; 19355 final Rect selfBounds = mForegroundInfo.mSelfBounds; 19356 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 19357 19358 if (mForegroundInfo.mInsidePadding) { 19359 selfBounds.set(0, 0, getWidth(), getHeight()); 19360 } else { 19361 selfBounds.set(getPaddingLeft(), getPaddingTop(), 19362 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 19363 } 19364 19365 final int ld = getLayoutDirection(); 19366 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 19367 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 19368 foreground.setBounds(overlayBounds); 19369 } 19370 19371 foreground.draw(canvas); 19372 } 19373 } 19374 19375 /** 19376 * Sets the padding. The view may add on the space required to display 19377 * the scrollbars, depending on the style and visibility of the scrollbars. 19378 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 19379 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 19380 * from the values set in this call. 19381 * 19382 * @attr ref android.R.styleable#View_padding 19383 * @attr ref android.R.styleable#View_paddingBottom 19384 * @attr ref android.R.styleable#View_paddingLeft 19385 * @attr ref android.R.styleable#View_paddingRight 19386 * @attr ref android.R.styleable#View_paddingTop 19387 * @param left the left padding in pixels 19388 * @param top the top padding in pixels 19389 * @param right the right padding in pixels 19390 * @param bottom the bottom padding in pixels 19391 */ 19392 public void setPadding(int left, int top, int right, int bottom) { 19393 resetResolvedPaddingInternal(); 19394 19395 mUserPaddingStart = UNDEFINED_PADDING; 19396 mUserPaddingEnd = UNDEFINED_PADDING; 19397 19398 mUserPaddingLeftInitial = left; 19399 mUserPaddingRightInitial = right; 19400 19401 mLeftPaddingDefined = true; 19402 mRightPaddingDefined = true; 19403 19404 internalSetPadding(left, top, right, bottom); 19405 } 19406 19407 /** 19408 * @hide 19409 */ 19410 protected void internalSetPadding(int left, int top, int right, int bottom) { 19411 mUserPaddingLeft = left; 19412 mUserPaddingRight = right; 19413 mUserPaddingBottom = bottom; 19414 19415 final int viewFlags = mViewFlags; 19416 boolean changed = false; 19417 19418 // Common case is there are no scroll bars. 19419 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 19420 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 19421 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 19422 ? 0 : getVerticalScrollbarWidth(); 19423 switch (mVerticalScrollbarPosition) { 19424 case SCROLLBAR_POSITION_DEFAULT: 19425 if (isLayoutRtl()) { 19426 left += offset; 19427 } else { 19428 right += offset; 19429 } 19430 break; 19431 case SCROLLBAR_POSITION_RIGHT: 19432 right += offset; 19433 break; 19434 case SCROLLBAR_POSITION_LEFT: 19435 left += offset; 19436 break; 19437 } 19438 } 19439 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 19440 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 19441 ? 0 : getHorizontalScrollbarHeight(); 19442 } 19443 } 19444 19445 if (mPaddingLeft != left) { 19446 changed = true; 19447 mPaddingLeft = left; 19448 } 19449 if (mPaddingTop != top) { 19450 changed = true; 19451 mPaddingTop = top; 19452 } 19453 if (mPaddingRight != right) { 19454 changed = true; 19455 mPaddingRight = right; 19456 } 19457 if (mPaddingBottom != bottom) { 19458 changed = true; 19459 mPaddingBottom = bottom; 19460 } 19461 19462 if (changed) { 19463 requestLayout(); 19464 invalidateOutline(); 19465 } 19466 } 19467 19468 /** 19469 * Sets the relative padding. The view may add on the space required to display 19470 * the scrollbars, depending on the style and visibility of the scrollbars. 19471 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 19472 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 19473 * from the values set in this call. 19474 * 19475 * @attr ref android.R.styleable#View_padding 19476 * @attr ref android.R.styleable#View_paddingBottom 19477 * @attr ref android.R.styleable#View_paddingStart 19478 * @attr ref android.R.styleable#View_paddingEnd 19479 * @attr ref android.R.styleable#View_paddingTop 19480 * @param start the start padding in pixels 19481 * @param top the top padding in pixels 19482 * @param end the end padding in pixels 19483 * @param bottom the bottom padding in pixels 19484 */ 19485 public void setPaddingRelative(int start, int top, int end, int bottom) { 19486 resetResolvedPaddingInternal(); 19487 19488 mUserPaddingStart = start; 19489 mUserPaddingEnd = end; 19490 mLeftPaddingDefined = true; 19491 mRightPaddingDefined = true; 19492 19493 switch(getLayoutDirection()) { 19494 case LAYOUT_DIRECTION_RTL: 19495 mUserPaddingLeftInitial = end; 19496 mUserPaddingRightInitial = start; 19497 internalSetPadding(end, top, start, bottom); 19498 break; 19499 case LAYOUT_DIRECTION_LTR: 19500 default: 19501 mUserPaddingLeftInitial = start; 19502 mUserPaddingRightInitial = end; 19503 internalSetPadding(start, top, end, bottom); 19504 } 19505 } 19506 19507 /** 19508 * Returns the top padding of this view. 19509 * 19510 * @return the top padding in pixels 19511 */ 19512 public int getPaddingTop() { 19513 return mPaddingTop; 19514 } 19515 19516 /** 19517 * Returns the bottom padding of this view. If there are inset and enabled 19518 * scrollbars, this value may include the space required to display the 19519 * scrollbars as well. 19520 * 19521 * @return the bottom padding in pixels 19522 */ 19523 public int getPaddingBottom() { 19524 return mPaddingBottom; 19525 } 19526 19527 /** 19528 * Returns the left padding of this view. If there are inset and enabled 19529 * scrollbars, this value may include the space required to display the 19530 * scrollbars as well. 19531 * 19532 * @return the left padding in pixels 19533 */ 19534 public int getPaddingLeft() { 19535 if (!isPaddingResolved()) { 19536 resolvePadding(); 19537 } 19538 return mPaddingLeft; 19539 } 19540 19541 /** 19542 * Returns the start padding of this view depending on its resolved layout direction. 19543 * If there are inset and enabled scrollbars, this value may include the space 19544 * required to display the scrollbars as well. 19545 * 19546 * @return the start padding in pixels 19547 */ 19548 public int getPaddingStart() { 19549 if (!isPaddingResolved()) { 19550 resolvePadding(); 19551 } 19552 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19553 mPaddingRight : mPaddingLeft; 19554 } 19555 19556 /** 19557 * Returns the right padding of this view. If there are inset and enabled 19558 * scrollbars, this value may include the space required to display the 19559 * scrollbars as well. 19560 * 19561 * @return the right padding in pixels 19562 */ 19563 public int getPaddingRight() { 19564 if (!isPaddingResolved()) { 19565 resolvePadding(); 19566 } 19567 return mPaddingRight; 19568 } 19569 19570 /** 19571 * Returns the end padding of this view depending on its resolved layout direction. 19572 * If there are inset and enabled scrollbars, this value may include the space 19573 * required to display the scrollbars as well. 19574 * 19575 * @return the end padding in pixels 19576 */ 19577 public int getPaddingEnd() { 19578 if (!isPaddingResolved()) { 19579 resolvePadding(); 19580 } 19581 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19582 mPaddingLeft : mPaddingRight; 19583 } 19584 19585 /** 19586 * Return if the padding has been set through relative values 19587 * {@link #setPaddingRelative(int, int, int, int)} or through 19588 * @attr ref android.R.styleable#View_paddingStart or 19589 * @attr ref android.R.styleable#View_paddingEnd 19590 * 19591 * @return true if the padding is relative or false if it is not. 19592 */ 19593 public boolean isPaddingRelative() { 19594 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 19595 } 19596 19597 Insets computeOpticalInsets() { 19598 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 19599 } 19600 19601 /** 19602 * @hide 19603 */ 19604 public void resetPaddingToInitialValues() { 19605 if (isRtlCompatibilityMode()) { 19606 mPaddingLeft = mUserPaddingLeftInitial; 19607 mPaddingRight = mUserPaddingRightInitial; 19608 return; 19609 } 19610 if (isLayoutRtl()) { 19611 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 19612 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 19613 } else { 19614 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 19615 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 19616 } 19617 } 19618 19619 /** 19620 * @hide 19621 */ 19622 public Insets getOpticalInsets() { 19623 if (mLayoutInsets == null) { 19624 mLayoutInsets = computeOpticalInsets(); 19625 } 19626 return mLayoutInsets; 19627 } 19628 19629 /** 19630 * Set this view's optical insets. 19631 * 19632 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 19633 * property. Views that compute their own optical insets should call it as part of measurement. 19634 * This method does not request layout. If you are setting optical insets outside of 19635 * measure/layout itself you will want to call requestLayout() yourself. 19636 * </p> 19637 * @hide 19638 */ 19639 public void setOpticalInsets(Insets insets) { 19640 mLayoutInsets = insets; 19641 } 19642 19643 /** 19644 * Changes the selection state of this view. A view can be selected or not. 19645 * Note that selection is not the same as focus. Views are typically 19646 * selected in the context of an AdapterView like ListView or GridView; 19647 * the selected view is the view that is highlighted. 19648 * 19649 * @param selected true if the view must be selected, false otherwise 19650 */ 19651 public void setSelected(boolean selected) { 19652 //noinspection DoubleNegation 19653 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 19654 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 19655 if (!selected) resetPressedState(); 19656 invalidate(true); 19657 refreshDrawableState(); 19658 dispatchSetSelected(selected); 19659 if (selected) { 19660 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 19661 } else { 19662 notifyViewAccessibilityStateChangedIfNeeded( 19663 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 19664 } 19665 } 19666 } 19667 19668 /** 19669 * Dispatch setSelected to all of this View's children. 19670 * 19671 * @see #setSelected(boolean) 19672 * 19673 * @param selected The new selected state 19674 */ 19675 protected void dispatchSetSelected(boolean selected) { 19676 } 19677 19678 /** 19679 * Indicates the selection state of this view. 19680 * 19681 * @return true if the view is selected, false otherwise 19682 */ 19683 @ViewDebug.ExportedProperty 19684 public boolean isSelected() { 19685 return (mPrivateFlags & PFLAG_SELECTED) != 0; 19686 } 19687 19688 /** 19689 * Changes the activated state of this view. A view can be activated or not. 19690 * Note that activation is not the same as selection. Selection is 19691 * a transient property, representing the view (hierarchy) the user is 19692 * currently interacting with. Activation is a longer-term state that the 19693 * user can move views in and out of. For example, in a list view with 19694 * single or multiple selection enabled, the views in the current selection 19695 * set are activated. (Um, yeah, we are deeply sorry about the terminology 19696 * here.) The activated state is propagated down to children of the view it 19697 * is set on. 19698 * 19699 * @param activated true if the view must be activated, false otherwise 19700 */ 19701 public void setActivated(boolean activated) { 19702 //noinspection DoubleNegation 19703 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 19704 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 19705 invalidate(true); 19706 refreshDrawableState(); 19707 dispatchSetActivated(activated); 19708 } 19709 } 19710 19711 /** 19712 * Dispatch setActivated to all of this View's children. 19713 * 19714 * @see #setActivated(boolean) 19715 * 19716 * @param activated The new activated state 19717 */ 19718 protected void dispatchSetActivated(boolean activated) { 19719 } 19720 19721 /** 19722 * Indicates the activation state of this view. 19723 * 19724 * @return true if the view is activated, false otherwise 19725 */ 19726 @ViewDebug.ExportedProperty 19727 public boolean isActivated() { 19728 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 19729 } 19730 19731 /** 19732 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 19733 * observer can be used to get notifications when global events, like 19734 * layout, happen. 19735 * 19736 * The returned ViewTreeObserver observer is not guaranteed to remain 19737 * valid for the lifetime of this View. If the caller of this method keeps 19738 * a long-lived reference to ViewTreeObserver, it should always check for 19739 * the return value of {@link ViewTreeObserver#isAlive()}. 19740 * 19741 * @return The ViewTreeObserver for this view's hierarchy. 19742 */ 19743 public ViewTreeObserver getViewTreeObserver() { 19744 if (mAttachInfo != null) { 19745 return mAttachInfo.mTreeObserver; 19746 } 19747 if (mFloatingTreeObserver == null) { 19748 mFloatingTreeObserver = new ViewTreeObserver(mContext); 19749 } 19750 return mFloatingTreeObserver; 19751 } 19752 19753 /** 19754 * <p>Finds the topmost view in the current view hierarchy.</p> 19755 * 19756 * @return the topmost view containing this view 19757 */ 19758 public View getRootView() { 19759 if (mAttachInfo != null) { 19760 final View v = mAttachInfo.mRootView; 19761 if (v != null) { 19762 return v; 19763 } 19764 } 19765 19766 View parent = this; 19767 19768 while (parent.mParent != null && parent.mParent instanceof View) { 19769 parent = (View) parent.mParent; 19770 } 19771 19772 return parent; 19773 } 19774 19775 /** 19776 * Transforms a motion event from view-local coordinates to on-screen 19777 * coordinates. 19778 * 19779 * @param ev the view-local motion event 19780 * @return false if the transformation could not be applied 19781 * @hide 19782 */ 19783 public boolean toGlobalMotionEvent(MotionEvent ev) { 19784 final AttachInfo info = mAttachInfo; 19785 if (info == null) { 19786 return false; 19787 } 19788 19789 final Matrix m = info.mTmpMatrix; 19790 m.set(Matrix.IDENTITY_MATRIX); 19791 transformMatrixToGlobal(m); 19792 ev.transform(m); 19793 return true; 19794 } 19795 19796 /** 19797 * Transforms a motion event from on-screen coordinates to view-local 19798 * coordinates. 19799 * 19800 * @param ev the on-screen motion event 19801 * @return false if the transformation could not be applied 19802 * @hide 19803 */ 19804 public boolean toLocalMotionEvent(MotionEvent ev) { 19805 final AttachInfo info = mAttachInfo; 19806 if (info == null) { 19807 return false; 19808 } 19809 19810 final Matrix m = info.mTmpMatrix; 19811 m.set(Matrix.IDENTITY_MATRIX); 19812 transformMatrixToLocal(m); 19813 ev.transform(m); 19814 return true; 19815 } 19816 19817 /** 19818 * Modifies the input matrix such that it maps view-local coordinates to 19819 * on-screen coordinates. 19820 * 19821 * @param m input matrix to modify 19822 * @hide 19823 */ 19824 public void transformMatrixToGlobal(Matrix m) { 19825 final ViewParent parent = mParent; 19826 if (parent instanceof View) { 19827 final View vp = (View) parent; 19828 vp.transformMatrixToGlobal(m); 19829 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 19830 } else if (parent instanceof ViewRootImpl) { 19831 final ViewRootImpl vr = (ViewRootImpl) parent; 19832 vr.transformMatrixToGlobal(m); 19833 m.preTranslate(0, -vr.mCurScrollY); 19834 } 19835 19836 m.preTranslate(mLeft, mTop); 19837 19838 if (!hasIdentityMatrix()) { 19839 m.preConcat(getMatrix()); 19840 } 19841 } 19842 19843 /** 19844 * Modifies the input matrix such that it maps on-screen coordinates to 19845 * view-local coordinates. 19846 * 19847 * @param m input matrix to modify 19848 * @hide 19849 */ 19850 public void transformMatrixToLocal(Matrix m) { 19851 final ViewParent parent = mParent; 19852 if (parent instanceof View) { 19853 final View vp = (View) parent; 19854 vp.transformMatrixToLocal(m); 19855 m.postTranslate(vp.mScrollX, vp.mScrollY); 19856 } else if (parent instanceof ViewRootImpl) { 19857 final ViewRootImpl vr = (ViewRootImpl) parent; 19858 vr.transformMatrixToLocal(m); 19859 m.postTranslate(0, vr.mCurScrollY); 19860 } 19861 19862 m.postTranslate(-mLeft, -mTop); 19863 19864 if (!hasIdentityMatrix()) { 19865 m.postConcat(getInverseMatrix()); 19866 } 19867 } 19868 19869 /** 19870 * @hide 19871 */ 19872 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 19873 @ViewDebug.IntToString(from = 0, to = "x"), 19874 @ViewDebug.IntToString(from = 1, to = "y") 19875 }) 19876 public int[] getLocationOnScreen() { 19877 int[] location = new int[2]; 19878 getLocationOnScreen(location); 19879 return location; 19880 } 19881 19882 /** 19883 * <p>Computes the coordinates of this view on the screen. The argument 19884 * must be an array of two integers. After the method returns, the array 19885 * contains the x and y location in that order.</p> 19886 * 19887 * @param outLocation an array of two integers in which to hold the coordinates 19888 */ 19889 public void getLocationOnScreen(@Size(2) int[] outLocation) { 19890 getLocationInWindow(outLocation); 19891 19892 final AttachInfo info = mAttachInfo; 19893 if (info != null) { 19894 outLocation[0] += info.mWindowLeft; 19895 outLocation[1] += info.mWindowTop; 19896 } 19897 } 19898 19899 /** 19900 * <p>Computes the coordinates of this view in its window. The argument 19901 * must be an array of two integers. After the method returns, the array 19902 * contains the x and y location in that order.</p> 19903 * 19904 * @param outLocation an array of two integers in which to hold the coordinates 19905 */ 19906 public void getLocationInWindow(@Size(2) int[] outLocation) { 19907 if (outLocation == null || outLocation.length < 2) { 19908 throw new IllegalArgumentException("outLocation must be an array of two integers"); 19909 } 19910 19911 outLocation[0] = 0; 19912 outLocation[1] = 0; 19913 19914 transformFromViewToWindowSpace(outLocation); 19915 } 19916 19917 /** @hide */ 19918 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 19919 if (inOutLocation == null || inOutLocation.length < 2) { 19920 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 19921 } 19922 19923 if (mAttachInfo == null) { 19924 // When the view is not attached to a window, this method does not make sense 19925 inOutLocation[0] = inOutLocation[1] = 0; 19926 return; 19927 } 19928 19929 float position[] = mAttachInfo.mTmpTransformLocation; 19930 position[0] = inOutLocation[0]; 19931 position[1] = inOutLocation[1]; 19932 19933 if (!hasIdentityMatrix()) { 19934 getMatrix().mapPoints(position); 19935 } 19936 19937 position[0] += mLeft; 19938 position[1] += mTop; 19939 19940 ViewParent viewParent = mParent; 19941 while (viewParent instanceof View) { 19942 final View view = (View) viewParent; 19943 19944 position[0] -= view.mScrollX; 19945 position[1] -= view.mScrollY; 19946 19947 if (!view.hasIdentityMatrix()) { 19948 view.getMatrix().mapPoints(position); 19949 } 19950 19951 position[0] += view.mLeft; 19952 position[1] += view.mTop; 19953 19954 viewParent = view.mParent; 19955 } 19956 19957 if (viewParent instanceof ViewRootImpl) { 19958 // *cough* 19959 final ViewRootImpl vr = (ViewRootImpl) viewParent; 19960 position[1] -= vr.mCurScrollY; 19961 } 19962 19963 inOutLocation[0] = Math.round(position[0]); 19964 inOutLocation[1] = Math.round(position[1]); 19965 } 19966 19967 /** 19968 * {@hide} 19969 * @param id the id of the view to be found 19970 * @return the view of the specified id, null if cannot be found 19971 */ 19972 protected View findViewTraversal(@IdRes int id) { 19973 if (id == mID) { 19974 return this; 19975 } 19976 return null; 19977 } 19978 19979 /** 19980 * {@hide} 19981 * @param tag the tag of the view to be found 19982 * @return the view of specified tag, null if cannot be found 19983 */ 19984 protected View findViewWithTagTraversal(Object tag) { 19985 if (tag != null && tag.equals(mTag)) { 19986 return this; 19987 } 19988 return null; 19989 } 19990 19991 /** 19992 * {@hide} 19993 * @param predicate The predicate to evaluate. 19994 * @param childToSkip If not null, ignores this child during the recursive traversal. 19995 * @return The first view that matches the predicate or null. 19996 */ 19997 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 19998 if (predicate.apply(this)) { 19999 return this; 20000 } 20001 return null; 20002 } 20003 20004 /** 20005 * Look for a child view with the given id. If this view has the given 20006 * id, return this view. 20007 * 20008 * @param id The id to search for. 20009 * @return The view that has the given id in the hierarchy or null 20010 */ 20011 @Nullable 20012 public final View findViewById(@IdRes int id) { 20013 if (id < 0) { 20014 return null; 20015 } 20016 return findViewTraversal(id); 20017 } 20018 20019 /** 20020 * Finds a view by its unuque and stable accessibility id. 20021 * 20022 * @param accessibilityId The searched accessibility id. 20023 * @return The found view. 20024 */ 20025 final View findViewByAccessibilityId(int accessibilityId) { 20026 if (accessibilityId < 0) { 20027 return null; 20028 } 20029 View view = findViewByAccessibilityIdTraversal(accessibilityId); 20030 if (view != null) { 20031 return view.includeForAccessibility() ? view : null; 20032 } 20033 return null; 20034 } 20035 20036 /** 20037 * Performs the traversal to find a view by its unuque and stable accessibility id. 20038 * 20039 * <strong>Note:</strong>This method does not stop at the root namespace 20040 * boundary since the user can touch the screen at an arbitrary location 20041 * potentially crossing the root namespace bounday which will send an 20042 * accessibility event to accessibility services and they should be able 20043 * to obtain the event source. Also accessibility ids are guaranteed to be 20044 * unique in the window. 20045 * 20046 * @param accessibilityId The accessibility id. 20047 * @return The found view. 20048 * 20049 * @hide 20050 */ 20051 public View findViewByAccessibilityIdTraversal(int accessibilityId) { 20052 if (getAccessibilityViewId() == accessibilityId) { 20053 return this; 20054 } 20055 return null; 20056 } 20057 20058 /** 20059 * Look for a child view with the given tag. If this view has the given 20060 * tag, return this view. 20061 * 20062 * @param tag The tag to search for, using "tag.equals(getTag())". 20063 * @return The View that has the given tag in the hierarchy or null 20064 */ 20065 public final View findViewWithTag(Object tag) { 20066 if (tag == null) { 20067 return null; 20068 } 20069 return findViewWithTagTraversal(tag); 20070 } 20071 20072 /** 20073 * {@hide} 20074 * Look for a child view that matches the specified predicate. 20075 * If this view matches the predicate, return this view. 20076 * 20077 * @param predicate The predicate to evaluate. 20078 * @return The first view that matches the predicate or null. 20079 */ 20080 public final View findViewByPredicate(Predicate<View> predicate) { 20081 return findViewByPredicateTraversal(predicate, null); 20082 } 20083 20084 /** 20085 * {@hide} 20086 * Look for a child view that matches the specified predicate, 20087 * starting with the specified view and its descendents and then 20088 * recusively searching the ancestors and siblings of that view 20089 * until this view is reached. 20090 * 20091 * This method is useful in cases where the predicate does not match 20092 * a single unique view (perhaps multiple views use the same id) 20093 * and we are trying to find the view that is "closest" in scope to the 20094 * starting view. 20095 * 20096 * @param start The view to start from. 20097 * @param predicate The predicate to evaluate. 20098 * @return The first view that matches the predicate or null. 20099 */ 20100 public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) { 20101 View childToSkip = null; 20102 for (;;) { 20103 View view = start.findViewByPredicateTraversal(predicate, childToSkip); 20104 if (view != null || start == this) { 20105 return view; 20106 } 20107 20108 ViewParent parent = start.getParent(); 20109 if (parent == null || !(parent instanceof View)) { 20110 return null; 20111 } 20112 20113 childToSkip = start; 20114 start = (View) parent; 20115 } 20116 } 20117 20118 /** 20119 * Sets the identifier for this view. The identifier does not have to be 20120 * unique in this view's hierarchy. The identifier should be a positive 20121 * number. 20122 * 20123 * @see #NO_ID 20124 * @see #getId() 20125 * @see #findViewById(int) 20126 * 20127 * @param id a number used to identify the view 20128 * 20129 * @attr ref android.R.styleable#View_id 20130 */ 20131 public void setId(@IdRes int id) { 20132 mID = id; 20133 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 20134 mID = generateViewId(); 20135 } 20136 } 20137 20138 /** 20139 * {@hide} 20140 * 20141 * @param isRoot true if the view belongs to the root namespace, false 20142 * otherwise 20143 */ 20144 public void setIsRootNamespace(boolean isRoot) { 20145 if (isRoot) { 20146 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 20147 } else { 20148 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 20149 } 20150 } 20151 20152 /** 20153 * {@hide} 20154 * 20155 * @return true if the view belongs to the root namespace, false otherwise 20156 */ 20157 public boolean isRootNamespace() { 20158 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 20159 } 20160 20161 /** 20162 * Returns this view's identifier. 20163 * 20164 * @return a positive integer used to identify the view or {@link #NO_ID} 20165 * if the view has no ID 20166 * 20167 * @see #setId(int) 20168 * @see #findViewById(int) 20169 * @attr ref android.R.styleable#View_id 20170 */ 20171 @IdRes 20172 @ViewDebug.CapturedViewProperty 20173 public int getId() { 20174 return mID; 20175 } 20176 20177 /** 20178 * Returns this view's tag. 20179 * 20180 * @return the Object stored in this view as a tag, or {@code null} if not 20181 * set 20182 * 20183 * @see #setTag(Object) 20184 * @see #getTag(int) 20185 */ 20186 @ViewDebug.ExportedProperty 20187 public Object getTag() { 20188 return mTag; 20189 } 20190 20191 /** 20192 * Sets the tag associated with this view. A tag can be used to mark 20193 * a view in its hierarchy and does not have to be unique within the 20194 * hierarchy. Tags can also be used to store data within a view without 20195 * resorting to another data structure. 20196 * 20197 * @param tag an Object to tag the view with 20198 * 20199 * @see #getTag() 20200 * @see #setTag(int, Object) 20201 */ 20202 public void setTag(final Object tag) { 20203 mTag = tag; 20204 } 20205 20206 /** 20207 * Returns the tag associated with this view and the specified key. 20208 * 20209 * @param key The key identifying the tag 20210 * 20211 * @return the Object stored in this view as a tag, or {@code null} if not 20212 * set 20213 * 20214 * @see #setTag(int, Object) 20215 * @see #getTag() 20216 */ 20217 public Object getTag(int key) { 20218 if (mKeyedTags != null) return mKeyedTags.get(key); 20219 return null; 20220 } 20221 20222 /** 20223 * Sets a tag associated with this view and a key. A tag can be used 20224 * to mark a view in its hierarchy and does not have to be unique within 20225 * the hierarchy. Tags can also be used to store data within a view 20226 * without resorting to another data structure. 20227 * 20228 * The specified key should be an id declared in the resources of the 20229 * application to ensure it is unique (see the <a 20230 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 20231 * Keys identified as belonging to 20232 * the Android framework or not associated with any package will cause 20233 * an {@link IllegalArgumentException} to be thrown. 20234 * 20235 * @param key The key identifying the tag 20236 * @param tag An Object to tag the view with 20237 * 20238 * @throws IllegalArgumentException If they specified key is not valid 20239 * 20240 * @see #setTag(Object) 20241 * @see #getTag(int) 20242 */ 20243 public void setTag(int key, final Object tag) { 20244 // If the package id is 0x00 or 0x01, it's either an undefined package 20245 // or a framework id 20246 if ((key >>> 24) < 2) { 20247 throw new IllegalArgumentException("The key must be an application-specific " 20248 + "resource id."); 20249 } 20250 20251 setKeyedTag(key, tag); 20252 } 20253 20254 /** 20255 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 20256 * framework id. 20257 * 20258 * @hide 20259 */ 20260 public void setTagInternal(int key, Object tag) { 20261 if ((key >>> 24) != 0x1) { 20262 throw new IllegalArgumentException("The key must be a framework-specific " 20263 + "resource id."); 20264 } 20265 20266 setKeyedTag(key, tag); 20267 } 20268 20269 private void setKeyedTag(int key, Object tag) { 20270 if (mKeyedTags == null) { 20271 mKeyedTags = new SparseArray<Object>(2); 20272 } 20273 20274 mKeyedTags.put(key, tag); 20275 } 20276 20277 /** 20278 * Prints information about this view in the log output, with the tag 20279 * {@link #VIEW_LOG_TAG}. 20280 * 20281 * @hide 20282 */ 20283 public void debug() { 20284 debug(0); 20285 } 20286 20287 /** 20288 * Prints information about this view in the log output, with the tag 20289 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 20290 * indentation defined by the <code>depth</code>. 20291 * 20292 * @param depth the indentation level 20293 * 20294 * @hide 20295 */ 20296 protected void debug(int depth) { 20297 String output = debugIndent(depth - 1); 20298 20299 output += "+ " + this; 20300 int id = getId(); 20301 if (id != -1) { 20302 output += " (id=" + id + ")"; 20303 } 20304 Object tag = getTag(); 20305 if (tag != null) { 20306 output += " (tag=" + tag + ")"; 20307 } 20308 Log.d(VIEW_LOG_TAG, output); 20309 20310 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 20311 output = debugIndent(depth) + " FOCUSED"; 20312 Log.d(VIEW_LOG_TAG, output); 20313 } 20314 20315 output = debugIndent(depth); 20316 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 20317 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 20318 + "} "; 20319 Log.d(VIEW_LOG_TAG, output); 20320 20321 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 20322 || mPaddingBottom != 0) { 20323 output = debugIndent(depth); 20324 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 20325 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 20326 Log.d(VIEW_LOG_TAG, output); 20327 } 20328 20329 output = debugIndent(depth); 20330 output += "mMeasureWidth=" + mMeasuredWidth + 20331 " mMeasureHeight=" + mMeasuredHeight; 20332 Log.d(VIEW_LOG_TAG, output); 20333 20334 output = debugIndent(depth); 20335 if (mLayoutParams == null) { 20336 output += "BAD! no layout params"; 20337 } else { 20338 output = mLayoutParams.debug(output); 20339 } 20340 Log.d(VIEW_LOG_TAG, output); 20341 20342 output = debugIndent(depth); 20343 output += "flags={"; 20344 output += View.printFlags(mViewFlags); 20345 output += "}"; 20346 Log.d(VIEW_LOG_TAG, output); 20347 20348 output = debugIndent(depth); 20349 output += "privateFlags={"; 20350 output += View.printPrivateFlags(mPrivateFlags); 20351 output += "}"; 20352 Log.d(VIEW_LOG_TAG, output); 20353 } 20354 20355 /** 20356 * Creates a string of whitespaces used for indentation. 20357 * 20358 * @param depth the indentation level 20359 * @return a String containing (depth * 2 + 3) * 2 white spaces 20360 * 20361 * @hide 20362 */ 20363 protected static String debugIndent(int depth) { 20364 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 20365 for (int i = 0; i < (depth * 2) + 3; i++) { 20366 spaces.append(' ').append(' '); 20367 } 20368 return spaces.toString(); 20369 } 20370 20371 /** 20372 * <p>Return the offset of the widget's text baseline from the widget's top 20373 * boundary. If this widget does not support baseline alignment, this 20374 * method returns -1. </p> 20375 * 20376 * @return the offset of the baseline within the widget's bounds or -1 20377 * if baseline alignment is not supported 20378 */ 20379 @ViewDebug.ExportedProperty(category = "layout") 20380 public int getBaseline() { 20381 return -1; 20382 } 20383 20384 /** 20385 * Returns whether the view hierarchy is currently undergoing a layout pass. This 20386 * information is useful to avoid situations such as calling {@link #requestLayout()} during 20387 * a layout pass. 20388 * 20389 * @return whether the view hierarchy is currently undergoing a layout pass 20390 */ 20391 public boolean isInLayout() { 20392 ViewRootImpl viewRoot = getViewRootImpl(); 20393 return (viewRoot != null && viewRoot.isInLayout()); 20394 } 20395 20396 /** 20397 * Call this when something has changed which has invalidated the 20398 * layout of this view. This will schedule a layout pass of the view 20399 * tree. This should not be called while the view hierarchy is currently in a layout 20400 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 20401 * end of the current layout pass (and then layout will run again) or after the current 20402 * frame is drawn and the next layout occurs. 20403 * 20404 * <p>Subclasses which override this method should call the superclass method to 20405 * handle possible request-during-layout errors correctly.</p> 20406 */ 20407 @CallSuper 20408 public void requestLayout() { 20409 if (mMeasureCache != null) mMeasureCache.clear(); 20410 20411 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 20412 // Only trigger request-during-layout logic if this is the view requesting it, 20413 // not the views in its parent hierarchy 20414 ViewRootImpl viewRoot = getViewRootImpl(); 20415 if (viewRoot != null && viewRoot.isInLayout()) { 20416 if (!viewRoot.requestLayoutDuringLayout(this)) { 20417 return; 20418 } 20419 } 20420 mAttachInfo.mViewRequestingLayout = this; 20421 } 20422 20423 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20424 mPrivateFlags |= PFLAG_INVALIDATED; 20425 20426 if (mParent != null && !mParent.isLayoutRequested()) { 20427 mParent.requestLayout(); 20428 } 20429 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 20430 mAttachInfo.mViewRequestingLayout = null; 20431 } 20432 } 20433 20434 /** 20435 * Forces this view to be laid out during the next layout pass. 20436 * This method does not call requestLayout() or forceLayout() 20437 * on the parent. 20438 */ 20439 public void forceLayout() { 20440 if (mMeasureCache != null) mMeasureCache.clear(); 20441 20442 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20443 mPrivateFlags |= PFLAG_INVALIDATED; 20444 } 20445 20446 /** 20447 * <p> 20448 * This is called to find out how big a view should be. The parent 20449 * supplies constraint information in the width and height parameters. 20450 * </p> 20451 * 20452 * <p> 20453 * The actual measurement work of a view is performed in 20454 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 20455 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 20456 * </p> 20457 * 20458 * 20459 * @param widthMeasureSpec Horizontal space requirements as imposed by the 20460 * parent 20461 * @param heightMeasureSpec Vertical space requirements as imposed by the 20462 * parent 20463 * 20464 * @see #onMeasure(int, int) 20465 */ 20466 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 20467 boolean optical = isLayoutModeOptical(this); 20468 if (optical != isLayoutModeOptical(mParent)) { 20469 Insets insets = getOpticalInsets(); 20470 int oWidth = insets.left + insets.right; 20471 int oHeight = insets.top + insets.bottom; 20472 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 20473 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 20474 } 20475 20476 // Suppress sign extension for the low bytes 20477 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 20478 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 20479 20480 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 20481 20482 // Optimize layout by avoiding an extra EXACTLY pass when the view is 20483 // already measured as the correct size. In API 23 and below, this 20484 // extra pass is required to make LinearLayout re-distribute weight. 20485 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 20486 || heightMeasureSpec != mOldHeightMeasureSpec; 20487 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 20488 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 20489 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 20490 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 20491 final boolean needsLayout = specChanged 20492 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 20493 20494 if (forceLayout || needsLayout) { 20495 // first clears the measured dimension flag 20496 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 20497 20498 resolveRtlPropertiesIfNeeded(); 20499 20500 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 20501 if (cacheIndex < 0 || sIgnoreMeasureCache) { 20502 // measure ourselves, this should set the measured dimension flag back 20503 onMeasure(widthMeasureSpec, heightMeasureSpec); 20504 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20505 } else { 20506 long value = mMeasureCache.valueAt(cacheIndex); 20507 // Casting a long to int drops the high 32 bits, no mask needed 20508 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 20509 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20510 } 20511 20512 // flag not set, setMeasuredDimension() was not invoked, we raise 20513 // an exception to warn the developer 20514 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 20515 throw new IllegalStateException("View with id " + getId() + ": " 20516 + getClass().getName() + "#onMeasure() did not set the" 20517 + " measured dimension by calling" 20518 + " setMeasuredDimension()"); 20519 } 20520 20521 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 20522 } 20523 20524 mOldWidthMeasureSpec = widthMeasureSpec; 20525 mOldHeightMeasureSpec = heightMeasureSpec; 20526 20527 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 20528 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 20529 } 20530 20531 /** 20532 * <p> 20533 * Measure the view and its content to determine the measured width and the 20534 * measured height. This method is invoked by {@link #measure(int, int)} and 20535 * should be overridden by subclasses to provide accurate and efficient 20536 * measurement of their contents. 20537 * </p> 20538 * 20539 * <p> 20540 * <strong>CONTRACT:</strong> When overriding this method, you 20541 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 20542 * measured width and height of this view. Failure to do so will trigger an 20543 * <code>IllegalStateException</code>, thrown by 20544 * {@link #measure(int, int)}. Calling the superclass' 20545 * {@link #onMeasure(int, int)} is a valid use. 20546 * </p> 20547 * 20548 * <p> 20549 * The base class implementation of measure defaults to the background size, 20550 * unless a larger size is allowed by the MeasureSpec. Subclasses should 20551 * override {@link #onMeasure(int, int)} to provide better measurements of 20552 * their content. 20553 * </p> 20554 * 20555 * <p> 20556 * If this method is overridden, it is the subclass's responsibility to make 20557 * sure the measured height and width are at least the view's minimum height 20558 * and width ({@link #getSuggestedMinimumHeight()} and 20559 * {@link #getSuggestedMinimumWidth()}). 20560 * </p> 20561 * 20562 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 20563 * The requirements are encoded with 20564 * {@link android.view.View.MeasureSpec}. 20565 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 20566 * The requirements are encoded with 20567 * {@link android.view.View.MeasureSpec}. 20568 * 20569 * @see #getMeasuredWidth() 20570 * @see #getMeasuredHeight() 20571 * @see #setMeasuredDimension(int, int) 20572 * @see #getSuggestedMinimumHeight() 20573 * @see #getSuggestedMinimumWidth() 20574 * @see android.view.View.MeasureSpec#getMode(int) 20575 * @see android.view.View.MeasureSpec#getSize(int) 20576 */ 20577 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 20578 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 20579 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 20580 } 20581 20582 /** 20583 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 20584 * measured width and measured height. Failing to do so will trigger an 20585 * exception at measurement time.</p> 20586 * 20587 * @param measuredWidth The measured width of this view. May be a complex 20588 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20589 * {@link #MEASURED_STATE_TOO_SMALL}. 20590 * @param measuredHeight The measured height of this view. May be a complex 20591 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20592 * {@link #MEASURED_STATE_TOO_SMALL}. 20593 */ 20594 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 20595 boolean optical = isLayoutModeOptical(this); 20596 if (optical != isLayoutModeOptical(mParent)) { 20597 Insets insets = getOpticalInsets(); 20598 int opticalWidth = insets.left + insets.right; 20599 int opticalHeight = insets.top + insets.bottom; 20600 20601 measuredWidth += optical ? opticalWidth : -opticalWidth; 20602 measuredHeight += optical ? opticalHeight : -opticalHeight; 20603 } 20604 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 20605 } 20606 20607 /** 20608 * Sets the measured dimension without extra processing for things like optical bounds. 20609 * Useful for reapplying consistent values that have already been cooked with adjustments 20610 * for optical bounds, etc. such as those from the measurement cache. 20611 * 20612 * @param measuredWidth The measured width of this view. May be a complex 20613 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20614 * {@link #MEASURED_STATE_TOO_SMALL}. 20615 * @param measuredHeight The measured height of this view. May be a complex 20616 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20617 * {@link #MEASURED_STATE_TOO_SMALL}. 20618 */ 20619 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 20620 mMeasuredWidth = measuredWidth; 20621 mMeasuredHeight = measuredHeight; 20622 20623 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 20624 } 20625 20626 /** 20627 * Merge two states as returned by {@link #getMeasuredState()}. 20628 * @param curState The current state as returned from a view or the result 20629 * of combining multiple views. 20630 * @param newState The new view state to combine. 20631 * @return Returns a new integer reflecting the combination of the two 20632 * states. 20633 */ 20634 public static int combineMeasuredStates(int curState, int newState) { 20635 return curState | newState; 20636 } 20637 20638 /** 20639 * Version of {@link #resolveSizeAndState(int, int, int)} 20640 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 20641 */ 20642 public static int resolveSize(int size, int measureSpec) { 20643 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 20644 } 20645 20646 /** 20647 * Utility to reconcile a desired size and state, with constraints imposed 20648 * by a MeasureSpec. Will take the desired size, unless a different size 20649 * is imposed by the constraints. The returned value is a compound integer, 20650 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 20651 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 20652 * resulting size is smaller than the size the view wants to be. 20653 * 20654 * @param size How big the view wants to be. 20655 * @param measureSpec Constraints imposed by the parent. 20656 * @param childMeasuredState Size information bit mask for the view's 20657 * children. 20658 * @return Size information bit mask as defined by 20659 * {@link #MEASURED_SIZE_MASK} and 20660 * {@link #MEASURED_STATE_TOO_SMALL}. 20661 */ 20662 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 20663 final int specMode = MeasureSpec.getMode(measureSpec); 20664 final int specSize = MeasureSpec.getSize(measureSpec); 20665 final int result; 20666 switch (specMode) { 20667 case MeasureSpec.AT_MOST: 20668 if (specSize < size) { 20669 result = specSize | MEASURED_STATE_TOO_SMALL; 20670 } else { 20671 result = size; 20672 } 20673 break; 20674 case MeasureSpec.EXACTLY: 20675 result = specSize; 20676 break; 20677 case MeasureSpec.UNSPECIFIED: 20678 default: 20679 result = size; 20680 } 20681 return result | (childMeasuredState & MEASURED_STATE_MASK); 20682 } 20683 20684 /** 20685 * Utility to return a default size. Uses the supplied size if the 20686 * MeasureSpec imposed no constraints. Will get larger if allowed 20687 * by the MeasureSpec. 20688 * 20689 * @param size Default size for this view 20690 * @param measureSpec Constraints imposed by the parent 20691 * @return The size this view should be. 20692 */ 20693 public static int getDefaultSize(int size, int measureSpec) { 20694 int result = size; 20695 int specMode = MeasureSpec.getMode(measureSpec); 20696 int specSize = MeasureSpec.getSize(measureSpec); 20697 20698 switch (specMode) { 20699 case MeasureSpec.UNSPECIFIED: 20700 result = size; 20701 break; 20702 case MeasureSpec.AT_MOST: 20703 case MeasureSpec.EXACTLY: 20704 result = specSize; 20705 break; 20706 } 20707 return result; 20708 } 20709 20710 /** 20711 * Returns the suggested minimum height that the view should use. This 20712 * returns the maximum of the view's minimum height 20713 * and the background's minimum height 20714 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 20715 * <p> 20716 * When being used in {@link #onMeasure(int, int)}, the caller should still 20717 * ensure the returned height is within the requirements of the parent. 20718 * 20719 * @return The suggested minimum height of the view. 20720 */ 20721 protected int getSuggestedMinimumHeight() { 20722 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 20723 20724 } 20725 20726 /** 20727 * Returns the suggested minimum width that the view should use. This 20728 * returns the maximum of the view's minimum width 20729 * and the background's minimum width 20730 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 20731 * <p> 20732 * When being used in {@link #onMeasure(int, int)}, the caller should still 20733 * ensure the returned width is within the requirements of the parent. 20734 * 20735 * @return The suggested minimum width of the view. 20736 */ 20737 protected int getSuggestedMinimumWidth() { 20738 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 20739 } 20740 20741 /** 20742 * Returns the minimum height of the view. 20743 * 20744 * @return the minimum height the view will try to be, in pixels 20745 * 20746 * @see #setMinimumHeight(int) 20747 * 20748 * @attr ref android.R.styleable#View_minHeight 20749 */ 20750 public int getMinimumHeight() { 20751 return mMinHeight; 20752 } 20753 20754 /** 20755 * Sets the minimum height of the view. It is not guaranteed the view will 20756 * be able to achieve this minimum height (for example, if its parent layout 20757 * constrains it with less available height). 20758 * 20759 * @param minHeight The minimum height the view will try to be, in pixels 20760 * 20761 * @see #getMinimumHeight() 20762 * 20763 * @attr ref android.R.styleable#View_minHeight 20764 */ 20765 @RemotableViewMethod 20766 public void setMinimumHeight(int minHeight) { 20767 mMinHeight = minHeight; 20768 requestLayout(); 20769 } 20770 20771 /** 20772 * Returns the minimum width of the view. 20773 * 20774 * @return the minimum width the view will try to be, in pixels 20775 * 20776 * @see #setMinimumWidth(int) 20777 * 20778 * @attr ref android.R.styleable#View_minWidth 20779 */ 20780 public int getMinimumWidth() { 20781 return mMinWidth; 20782 } 20783 20784 /** 20785 * Sets the minimum width of the view. It is not guaranteed the view will 20786 * be able to achieve this minimum width (for example, if its parent layout 20787 * constrains it with less available width). 20788 * 20789 * @param minWidth The minimum width the view will try to be, in pixels 20790 * 20791 * @see #getMinimumWidth() 20792 * 20793 * @attr ref android.R.styleable#View_minWidth 20794 */ 20795 public void setMinimumWidth(int minWidth) { 20796 mMinWidth = minWidth; 20797 requestLayout(); 20798 20799 } 20800 20801 /** 20802 * Get the animation currently associated with this view. 20803 * 20804 * @return The animation that is currently playing or 20805 * scheduled to play for this view. 20806 */ 20807 public Animation getAnimation() { 20808 return mCurrentAnimation; 20809 } 20810 20811 /** 20812 * Start the specified animation now. 20813 * 20814 * @param animation the animation to start now 20815 */ 20816 public void startAnimation(Animation animation) { 20817 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 20818 setAnimation(animation); 20819 invalidateParentCaches(); 20820 invalidate(true); 20821 } 20822 20823 /** 20824 * Cancels any animations for this view. 20825 */ 20826 public void clearAnimation() { 20827 if (mCurrentAnimation != null) { 20828 mCurrentAnimation.detach(); 20829 } 20830 mCurrentAnimation = null; 20831 invalidateParentIfNeeded(); 20832 } 20833 20834 /** 20835 * Sets the next animation to play for this view. 20836 * If you want the animation to play immediately, use 20837 * {@link #startAnimation(android.view.animation.Animation)} instead. 20838 * This method provides allows fine-grained 20839 * control over the start time and invalidation, but you 20840 * must make sure that 1) the animation has a start time set, and 20841 * 2) the view's parent (which controls animations on its children) 20842 * will be invalidated when the animation is supposed to 20843 * start. 20844 * 20845 * @param animation The next animation, or null. 20846 */ 20847 public void setAnimation(Animation animation) { 20848 mCurrentAnimation = animation; 20849 20850 if (animation != null) { 20851 // If the screen is off assume the animation start time is now instead of 20852 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 20853 // would cause the animation to start when the screen turns back on 20854 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 20855 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 20856 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 20857 } 20858 animation.reset(); 20859 } 20860 } 20861 20862 /** 20863 * Invoked by a parent ViewGroup to notify the start of the animation 20864 * currently associated with this view. If you override this method, 20865 * always call super.onAnimationStart(); 20866 * 20867 * @see #setAnimation(android.view.animation.Animation) 20868 * @see #getAnimation() 20869 */ 20870 @CallSuper 20871 protected void onAnimationStart() { 20872 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 20873 } 20874 20875 /** 20876 * Invoked by a parent ViewGroup to notify the end of the animation 20877 * currently associated with this view. If you override this method, 20878 * always call super.onAnimationEnd(); 20879 * 20880 * @see #setAnimation(android.view.animation.Animation) 20881 * @see #getAnimation() 20882 */ 20883 @CallSuper 20884 protected void onAnimationEnd() { 20885 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 20886 } 20887 20888 /** 20889 * Invoked if there is a Transform that involves alpha. Subclass that can 20890 * draw themselves with the specified alpha should return true, and then 20891 * respect that alpha when their onDraw() is called. If this returns false 20892 * then the view may be redirected to draw into an offscreen buffer to 20893 * fulfill the request, which will look fine, but may be slower than if the 20894 * subclass handles it internally. The default implementation returns false. 20895 * 20896 * @param alpha The alpha (0..255) to apply to the view's drawing 20897 * @return true if the view can draw with the specified alpha. 20898 */ 20899 protected boolean onSetAlpha(int alpha) { 20900 return false; 20901 } 20902 20903 /** 20904 * This is used by the RootView to perform an optimization when 20905 * the view hierarchy contains one or several SurfaceView. 20906 * SurfaceView is always considered transparent, but its children are not, 20907 * therefore all View objects remove themselves from the global transparent 20908 * region (passed as a parameter to this function). 20909 * 20910 * @param region The transparent region for this ViewAncestor (window). 20911 * 20912 * @return Returns true if the effective visibility of the view at this 20913 * point is opaque, regardless of the transparent region; returns false 20914 * if it is possible for underlying windows to be seen behind the view. 20915 * 20916 * {@hide} 20917 */ 20918 public boolean gatherTransparentRegion(Region region) { 20919 final AttachInfo attachInfo = mAttachInfo; 20920 if (region != null && attachInfo != null) { 20921 final int pflags = mPrivateFlags; 20922 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 20923 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 20924 // remove it from the transparent region. 20925 final int[] location = attachInfo.mTransparentLocation; 20926 getLocationInWindow(location); 20927 // When a view has Z value, then it will be better to leave some area below the view 20928 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 20929 // the bottom part needs more offset than the left, top and right parts due to the 20930 // spot light effects. 20931 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 20932 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 20933 location[0] + mRight - mLeft + shadowOffset, 20934 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 20935 } else { 20936 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 20937 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 20938 // the background drawable's non-transparent parts from this transparent region. 20939 applyDrawableToTransparentRegion(mBackground, region); 20940 } 20941 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20942 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 20943 // Similarly, we remove the foreground drawable's non-transparent parts. 20944 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 20945 } 20946 } 20947 } 20948 return true; 20949 } 20950 20951 /** 20952 * Play a sound effect for this view. 20953 * 20954 * <p>The framework will play sound effects for some built in actions, such as 20955 * clicking, but you may wish to play these effects in your widget, 20956 * for instance, for internal navigation. 20957 * 20958 * <p>The sound effect will only be played if sound effects are enabled by the user, and 20959 * {@link #isSoundEffectsEnabled()} is true. 20960 * 20961 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 20962 */ 20963 public void playSoundEffect(int soundConstant) { 20964 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 20965 return; 20966 } 20967 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 20968 } 20969 20970 /** 20971 * BZZZTT!!1! 20972 * 20973 * <p>Provide haptic feedback to the user for this view. 20974 * 20975 * <p>The framework will provide haptic feedback for some built in actions, 20976 * such as long presses, but you may wish to provide feedback for your 20977 * own widget. 20978 * 20979 * <p>The feedback will only be performed if 20980 * {@link #isHapticFeedbackEnabled()} is true. 20981 * 20982 * @param feedbackConstant One of the constants defined in 20983 * {@link HapticFeedbackConstants} 20984 */ 20985 public boolean performHapticFeedback(int feedbackConstant) { 20986 return performHapticFeedback(feedbackConstant, 0); 20987 } 20988 20989 /** 20990 * BZZZTT!!1! 20991 * 20992 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 20993 * 20994 * @param feedbackConstant One of the constants defined in 20995 * {@link HapticFeedbackConstants} 20996 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 20997 */ 20998 public boolean performHapticFeedback(int feedbackConstant, int flags) { 20999 if (mAttachInfo == null) { 21000 return false; 21001 } 21002 //noinspection SimplifiableIfStatement 21003 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 21004 && !isHapticFeedbackEnabled()) { 21005 return false; 21006 } 21007 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 21008 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 21009 } 21010 21011 /** 21012 * Request that the visibility of the status bar or other screen/window 21013 * decorations be changed. 21014 * 21015 * <p>This method is used to put the over device UI into temporary modes 21016 * where the user's attention is focused more on the application content, 21017 * by dimming or hiding surrounding system affordances. This is typically 21018 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 21019 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 21020 * to be placed behind the action bar (and with these flags other system 21021 * affordances) so that smooth transitions between hiding and showing them 21022 * can be done. 21023 * 21024 * <p>Two representative examples of the use of system UI visibility is 21025 * implementing a content browsing application (like a magazine reader) 21026 * and a video playing application. 21027 * 21028 * <p>The first code shows a typical implementation of a View in a content 21029 * browsing application. In this implementation, the application goes 21030 * into a content-oriented mode by hiding the status bar and action bar, 21031 * and putting the navigation elements into lights out mode. The user can 21032 * then interact with content while in this mode. Such an application should 21033 * provide an easy way for the user to toggle out of the mode (such as to 21034 * check information in the status bar or access notifications). In the 21035 * implementation here, this is done simply by tapping on the content. 21036 * 21037 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 21038 * content} 21039 * 21040 * <p>This second code sample shows a typical implementation of a View 21041 * in a video playing application. In this situation, while the video is 21042 * playing the application would like to go into a complete full-screen mode, 21043 * to use as much of the display as possible for the video. When in this state 21044 * the user can not interact with the application; the system intercepts 21045 * touching on the screen to pop the UI out of full screen mode. See 21046 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 21047 * 21048 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 21049 * content} 21050 * 21051 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 21052 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 21053 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 21054 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 21055 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 21056 */ 21057 public void setSystemUiVisibility(int visibility) { 21058 if (visibility != mSystemUiVisibility) { 21059 mSystemUiVisibility = visibility; 21060 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 21061 mParent.recomputeViewAttributes(this); 21062 } 21063 } 21064 } 21065 21066 /** 21067 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 21068 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 21069 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 21070 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 21071 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 21072 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 21073 */ 21074 public int getSystemUiVisibility() { 21075 return mSystemUiVisibility; 21076 } 21077 21078 /** 21079 * Returns the current system UI visibility that is currently set for 21080 * the entire window. This is the combination of the 21081 * {@link #setSystemUiVisibility(int)} values supplied by all of the 21082 * views in the window. 21083 */ 21084 public int getWindowSystemUiVisibility() { 21085 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 21086 } 21087 21088 /** 21089 * Override to find out when the window's requested system UI visibility 21090 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 21091 * This is different from the callbacks received through 21092 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 21093 * in that this is only telling you about the local request of the window, 21094 * not the actual values applied by the system. 21095 */ 21096 public void onWindowSystemUiVisibilityChanged(int visible) { 21097 } 21098 21099 /** 21100 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 21101 * the view hierarchy. 21102 */ 21103 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 21104 onWindowSystemUiVisibilityChanged(visible); 21105 } 21106 21107 /** 21108 * Set a listener to receive callbacks when the visibility of the system bar changes. 21109 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 21110 */ 21111 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 21112 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 21113 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 21114 mParent.recomputeViewAttributes(this); 21115 } 21116 } 21117 21118 /** 21119 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 21120 * the view hierarchy. 21121 */ 21122 public void dispatchSystemUiVisibilityChanged(int visibility) { 21123 ListenerInfo li = mListenerInfo; 21124 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 21125 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 21126 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 21127 } 21128 } 21129 21130 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 21131 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 21132 if (val != mSystemUiVisibility) { 21133 setSystemUiVisibility(val); 21134 return true; 21135 } 21136 return false; 21137 } 21138 21139 /** @hide */ 21140 public void setDisabledSystemUiVisibility(int flags) { 21141 if (mAttachInfo != null) { 21142 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 21143 mAttachInfo.mDisabledSystemUiVisibility = flags; 21144 if (mParent != null) { 21145 mParent.recomputeViewAttributes(this); 21146 } 21147 } 21148 } 21149 } 21150 21151 /** 21152 * Creates an image that the system displays during the drag and drop 21153 * operation. This is called a "drag shadow". The default implementation 21154 * for a DragShadowBuilder based on a View returns an image that has exactly the same 21155 * appearance as the given View. The default also positions the center of the drag shadow 21156 * directly under the touch point. If no View is provided (the constructor with no parameters 21157 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 21158 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 21159 * default is an invisible drag shadow. 21160 * <p> 21161 * You are not required to use the View you provide to the constructor as the basis of the 21162 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 21163 * anything you want as the drag shadow. 21164 * </p> 21165 * <p> 21166 * You pass a DragShadowBuilder object to the system when you start the drag. The system 21167 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 21168 * size and position of the drag shadow. It uses this data to construct a 21169 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 21170 * so that your application can draw the shadow image in the Canvas. 21171 * </p> 21172 * 21173 * <div class="special reference"> 21174 * <h3>Developer Guides</h3> 21175 * <p>For a guide to implementing drag and drop features, read the 21176 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 21177 * </div> 21178 */ 21179 public static class DragShadowBuilder { 21180 private final WeakReference<View> mView; 21181 21182 /** 21183 * Constructs a shadow image builder based on a View. By default, the resulting drag 21184 * shadow will have the same appearance and dimensions as the View, with the touch point 21185 * over the center of the View. 21186 * @param view A View. Any View in scope can be used. 21187 */ 21188 public DragShadowBuilder(View view) { 21189 mView = new WeakReference<View>(view); 21190 } 21191 21192 /** 21193 * Construct a shadow builder object with no associated View. This 21194 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 21195 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 21196 * to supply the drag shadow's dimensions and appearance without 21197 * reference to any View object. If they are not overridden, then the result is an 21198 * invisible drag shadow. 21199 */ 21200 public DragShadowBuilder() { 21201 mView = new WeakReference<View>(null); 21202 } 21203 21204 /** 21205 * Returns the View object that had been passed to the 21206 * {@link #View.DragShadowBuilder(View)} 21207 * constructor. If that View parameter was {@code null} or if the 21208 * {@link #View.DragShadowBuilder()} 21209 * constructor was used to instantiate the builder object, this method will return 21210 * null. 21211 * 21212 * @return The View object associate with this builder object. 21213 */ 21214 @SuppressWarnings({"JavadocReference"}) 21215 final public View getView() { 21216 return mView.get(); 21217 } 21218 21219 /** 21220 * Provides the metrics for the shadow image. These include the dimensions of 21221 * the shadow image, and the point within that shadow that should 21222 * be centered under the touch location while dragging. 21223 * <p> 21224 * The default implementation sets the dimensions of the shadow to be the 21225 * same as the dimensions of the View itself and centers the shadow under 21226 * the touch point. 21227 * </p> 21228 * 21229 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 21230 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 21231 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 21232 * image. 21233 * 21234 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 21235 * shadow image that should be underneath the touch point during the drag and drop 21236 * operation. Your application must set {@link android.graphics.Point#x} to the 21237 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 21238 */ 21239 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 21240 final View view = mView.get(); 21241 if (view != null) { 21242 outShadowSize.set(view.getWidth(), view.getHeight()); 21243 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 21244 } else { 21245 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 21246 } 21247 } 21248 21249 /** 21250 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 21251 * based on the dimensions it received from the 21252 * {@link #onProvideShadowMetrics(Point, Point)} callback. 21253 * 21254 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 21255 */ 21256 public void onDrawShadow(Canvas canvas) { 21257 final View view = mView.get(); 21258 if (view != null) { 21259 view.draw(canvas); 21260 } else { 21261 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 21262 } 21263 } 21264 } 21265 21266 /** 21267 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 21268 * startDragAndDrop()} for newer platform versions. 21269 */ 21270 @Deprecated 21271 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 21272 Object myLocalState, int flags) { 21273 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 21274 } 21275 21276 /** 21277 * Starts a drag and drop operation. When your application calls this method, it passes a 21278 * {@link android.view.View.DragShadowBuilder} object to the system. The 21279 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 21280 * to get metrics for the drag shadow, and then calls the object's 21281 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 21282 * <p> 21283 * Once the system has the drag shadow, it begins the drag and drop operation by sending 21284 * drag events to all the View objects in your application that are currently visible. It does 21285 * this either by calling the View object's drag listener (an implementation of 21286 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 21287 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 21288 * Both are passed a {@link android.view.DragEvent} object that has a 21289 * {@link android.view.DragEvent#getAction()} value of 21290 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 21291 * </p> 21292 * <p> 21293 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 21294 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 21295 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 21296 * to the View the user selected for dragging. 21297 * </p> 21298 * @param data A {@link android.content.ClipData} object pointing to the data to be 21299 * transferred by the drag and drop operation. 21300 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21301 * drag shadow. 21302 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 21303 * drop operation. When dispatching drag events to views in the same activity this object 21304 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 21305 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 21306 * will return null). 21307 * <p> 21308 * myLocalState is a lightweight mechanism for the sending information from the dragged View 21309 * to the target Views. For example, it can contain flags that differentiate between a 21310 * a copy operation and a move operation. 21311 * </p> 21312 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 21313 * flags, or any combination of the following: 21314 * <ul> 21315 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 21316 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 21317 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 21318 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 21319 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 21320 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 21321 * </ul> 21322 * @return {@code true} if the method completes successfully, or 21323 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 21324 * do a drag, and so no drag operation is in progress. 21325 */ 21326 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 21327 Object myLocalState, int flags) { 21328 if (ViewDebug.DEBUG_DRAG) { 21329 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 21330 } 21331 if (mAttachInfo == null) { 21332 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 21333 return false; 21334 } 21335 21336 if (data != null) { 21337 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 21338 } 21339 21340 boolean okay = false; 21341 21342 Point shadowSize = new Point(); 21343 Point shadowTouchPoint = new Point(); 21344 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 21345 21346 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 21347 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 21348 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 21349 } 21350 21351 if (ViewDebug.DEBUG_DRAG) { 21352 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 21353 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 21354 } 21355 if (mAttachInfo.mDragSurface != null) { 21356 mAttachInfo.mDragSurface.release(); 21357 } 21358 mAttachInfo.mDragSurface = new Surface(); 21359 try { 21360 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 21361 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 21362 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 21363 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 21364 if (mAttachInfo.mDragToken != null) { 21365 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21366 try { 21367 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21368 shadowBuilder.onDrawShadow(canvas); 21369 } finally { 21370 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21371 } 21372 21373 final ViewRootImpl root = getViewRootImpl(); 21374 21375 // Cache the local state object for delivery with DragEvents 21376 root.setLocalDragState(myLocalState); 21377 21378 // repurpose 'shadowSize' for the last touch point 21379 root.getLastTouchPoint(shadowSize); 21380 21381 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 21382 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 21383 shadowTouchPoint.x, shadowTouchPoint.y, data); 21384 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 21385 } 21386 } catch (Exception e) { 21387 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 21388 mAttachInfo.mDragSurface.destroy(); 21389 mAttachInfo.mDragSurface = null; 21390 } 21391 21392 return okay; 21393 } 21394 21395 /** 21396 * Cancels an ongoing drag and drop operation. 21397 * <p> 21398 * A {@link android.view.DragEvent} object with 21399 * {@link android.view.DragEvent#getAction()} value of 21400 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 21401 * {@link android.view.DragEvent#getResult()} value of {@code false} 21402 * will be sent to every 21403 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 21404 * even if they are not currently visible. 21405 * </p> 21406 * <p> 21407 * This method can be called on any View in the same window as the View on which 21408 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 21409 * was called. 21410 * </p> 21411 */ 21412 public final void cancelDragAndDrop() { 21413 if (ViewDebug.DEBUG_DRAG) { 21414 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 21415 } 21416 if (mAttachInfo == null) { 21417 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 21418 return; 21419 } 21420 if (mAttachInfo.mDragToken != null) { 21421 try { 21422 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 21423 } catch (Exception e) { 21424 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 21425 } 21426 mAttachInfo.mDragToken = null; 21427 } else { 21428 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 21429 } 21430 } 21431 21432 /** 21433 * Updates the drag shadow for the ongoing drag and drop operation. 21434 * 21435 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21436 * new drag shadow. 21437 */ 21438 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 21439 if (ViewDebug.DEBUG_DRAG) { 21440 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 21441 } 21442 if (mAttachInfo == null) { 21443 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 21444 return; 21445 } 21446 if (mAttachInfo.mDragToken != null) { 21447 try { 21448 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21449 try { 21450 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21451 shadowBuilder.onDrawShadow(canvas); 21452 } finally { 21453 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21454 } 21455 } catch (Exception e) { 21456 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 21457 } 21458 } else { 21459 Log.e(VIEW_LOG_TAG, "No active drag"); 21460 } 21461 } 21462 21463 /** 21464 * Starts a move from {startX, startY}, the amount of the movement will be the offset 21465 * between {startX, startY} and the new cursor positon. 21466 * @param startX horizontal coordinate where the move started. 21467 * @param startY vertical coordinate where the move started. 21468 * @return whether moving was started successfully. 21469 * @hide 21470 */ 21471 public final boolean startMovingTask(float startX, float startY) { 21472 if (ViewDebug.DEBUG_POSITIONING) { 21473 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 21474 } 21475 try { 21476 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 21477 } catch (RemoteException e) { 21478 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 21479 } 21480 return false; 21481 } 21482 21483 /** 21484 * Handles drag events sent by the system following a call to 21485 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 21486 * startDragAndDrop()}. 21487 *<p> 21488 * When the system calls this method, it passes a 21489 * {@link android.view.DragEvent} object. A call to 21490 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 21491 * in DragEvent. The method uses these to determine what is happening in the drag and drop 21492 * operation. 21493 * @param event The {@link android.view.DragEvent} sent by the system. 21494 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 21495 * in DragEvent, indicating the type of drag event represented by this object. 21496 * @return {@code true} if the method was successful, otherwise {@code false}. 21497 * <p> 21498 * The method should return {@code true} in response to an action type of 21499 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 21500 * operation. 21501 * </p> 21502 * <p> 21503 * The method should also return {@code true} in response to an action type of 21504 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 21505 * {@code false} if it didn't. 21506 * </p> 21507 * <p> 21508 * For all other events, the return value is ignored. 21509 * </p> 21510 */ 21511 public boolean onDragEvent(DragEvent event) { 21512 return false; 21513 } 21514 21515 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 21516 boolean dispatchDragEnterExitInPreN(DragEvent event) { 21517 return callDragEventHandler(event); 21518 } 21519 21520 /** 21521 * Detects if this View is enabled and has a drag event listener. 21522 * If both are true, then it calls the drag event listener with the 21523 * {@link android.view.DragEvent} it received. If the drag event listener returns 21524 * {@code true}, then dispatchDragEvent() returns {@code true}. 21525 * <p> 21526 * For all other cases, the method calls the 21527 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 21528 * method and returns its result. 21529 * </p> 21530 * <p> 21531 * This ensures that a drag event is always consumed, even if the View does not have a drag 21532 * event listener. However, if the View has a listener and the listener returns true, then 21533 * onDragEvent() is not called. 21534 * </p> 21535 */ 21536 public boolean dispatchDragEvent(DragEvent event) { 21537 event.mEventHandlerWasCalled = true; 21538 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 21539 event.mAction == DragEvent.ACTION_DROP) { 21540 // About to deliver an event with coordinates to this view. Notify that now this view 21541 // has drag focus. This will send exit/enter events as needed. 21542 getViewRootImpl().setDragFocus(this, event); 21543 } 21544 return callDragEventHandler(event); 21545 } 21546 21547 final boolean callDragEventHandler(DragEvent event) { 21548 final boolean result; 21549 21550 ListenerInfo li = mListenerInfo; 21551 //noinspection SimplifiableIfStatement 21552 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 21553 && li.mOnDragListener.onDrag(this, event)) { 21554 result = true; 21555 } else { 21556 result = onDragEvent(event); 21557 } 21558 21559 switch (event.mAction) { 21560 case DragEvent.ACTION_DRAG_ENTERED: { 21561 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 21562 refreshDrawableState(); 21563 } break; 21564 case DragEvent.ACTION_DRAG_EXITED: { 21565 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 21566 refreshDrawableState(); 21567 } break; 21568 case DragEvent.ACTION_DRAG_ENDED: { 21569 mPrivateFlags2 &= ~View.DRAG_MASK; 21570 refreshDrawableState(); 21571 } break; 21572 } 21573 21574 return result; 21575 } 21576 21577 boolean canAcceptDrag() { 21578 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 21579 } 21580 21581 /** 21582 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 21583 * it is ever exposed at all. 21584 * @hide 21585 */ 21586 public void onCloseSystemDialogs(String reason) { 21587 } 21588 21589 /** 21590 * Given a Drawable whose bounds have been set to draw into this view, 21591 * update a Region being computed for 21592 * {@link #gatherTransparentRegion(android.graphics.Region)} so 21593 * that any non-transparent parts of the Drawable are removed from the 21594 * given transparent region. 21595 * 21596 * @param dr The Drawable whose transparency is to be applied to the region. 21597 * @param region A Region holding the current transparency information, 21598 * where any parts of the region that are set are considered to be 21599 * transparent. On return, this region will be modified to have the 21600 * transparency information reduced by the corresponding parts of the 21601 * Drawable that are not transparent. 21602 * {@hide} 21603 */ 21604 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 21605 if (DBG) { 21606 Log.i("View", "Getting transparent region for: " + this); 21607 } 21608 final Region r = dr.getTransparentRegion(); 21609 final Rect db = dr.getBounds(); 21610 final AttachInfo attachInfo = mAttachInfo; 21611 if (r != null && attachInfo != null) { 21612 final int w = getRight()-getLeft(); 21613 final int h = getBottom()-getTop(); 21614 if (db.left > 0) { 21615 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 21616 r.op(0, 0, db.left, h, Region.Op.UNION); 21617 } 21618 if (db.right < w) { 21619 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 21620 r.op(db.right, 0, w, h, Region.Op.UNION); 21621 } 21622 if (db.top > 0) { 21623 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 21624 r.op(0, 0, w, db.top, Region.Op.UNION); 21625 } 21626 if (db.bottom < h) { 21627 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 21628 r.op(0, db.bottom, w, h, Region.Op.UNION); 21629 } 21630 final int[] location = attachInfo.mTransparentLocation; 21631 getLocationInWindow(location); 21632 r.translate(location[0], location[1]); 21633 region.op(r, Region.Op.INTERSECT); 21634 } else { 21635 region.op(db, Region.Op.DIFFERENCE); 21636 } 21637 } 21638 21639 private void checkForLongClick(int delayOffset, float x, float y) { 21640 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 21641 mHasPerformedLongPress = false; 21642 21643 if (mPendingCheckForLongPress == null) { 21644 mPendingCheckForLongPress = new CheckForLongPress(); 21645 } 21646 mPendingCheckForLongPress.setAnchor(x, y); 21647 mPendingCheckForLongPress.rememberWindowAttachCount(); 21648 mPendingCheckForLongPress.rememberPressedState(); 21649 postDelayed(mPendingCheckForLongPress, 21650 ViewConfiguration.getLongPressTimeout() - delayOffset); 21651 } 21652 } 21653 21654 /** 21655 * Inflate a view from an XML resource. This convenience method wraps the {@link 21656 * LayoutInflater} class, which provides a full range of options for view inflation. 21657 * 21658 * @param context The Context object for your activity or application. 21659 * @param resource The resource ID to inflate 21660 * @param root A view group that will be the parent. Used to properly inflate the 21661 * layout_* parameters. 21662 * @see LayoutInflater 21663 */ 21664 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 21665 LayoutInflater factory = LayoutInflater.from(context); 21666 return factory.inflate(resource, root); 21667 } 21668 21669 /** 21670 * Scroll the view with standard behavior for scrolling beyond the normal 21671 * content boundaries. Views that call this method should override 21672 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 21673 * results of an over-scroll operation. 21674 * 21675 * Views can use this method to handle any touch or fling-based scrolling. 21676 * 21677 * @param deltaX Change in X in pixels 21678 * @param deltaY Change in Y in pixels 21679 * @param scrollX Current X scroll value in pixels before applying deltaX 21680 * @param scrollY Current Y scroll value in pixels before applying deltaY 21681 * @param scrollRangeX Maximum content scroll range along the X axis 21682 * @param scrollRangeY Maximum content scroll range along the Y axis 21683 * @param maxOverScrollX Number of pixels to overscroll by in either direction 21684 * along the X axis. 21685 * @param maxOverScrollY Number of pixels to overscroll by in either direction 21686 * along the Y axis. 21687 * @param isTouchEvent true if this scroll operation is the result of a touch event. 21688 * @return true if scrolling was clamped to an over-scroll boundary along either 21689 * axis, false otherwise. 21690 */ 21691 @SuppressWarnings({"UnusedParameters"}) 21692 protected boolean overScrollBy(int deltaX, int deltaY, 21693 int scrollX, int scrollY, 21694 int scrollRangeX, int scrollRangeY, 21695 int maxOverScrollX, int maxOverScrollY, 21696 boolean isTouchEvent) { 21697 final int overScrollMode = mOverScrollMode; 21698 final boolean canScrollHorizontal = 21699 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 21700 final boolean canScrollVertical = 21701 computeVerticalScrollRange() > computeVerticalScrollExtent(); 21702 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 21703 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 21704 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 21705 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 21706 21707 int newScrollX = scrollX + deltaX; 21708 if (!overScrollHorizontal) { 21709 maxOverScrollX = 0; 21710 } 21711 21712 int newScrollY = scrollY + deltaY; 21713 if (!overScrollVertical) { 21714 maxOverScrollY = 0; 21715 } 21716 21717 // Clamp values if at the limits and record 21718 final int left = -maxOverScrollX; 21719 final int right = maxOverScrollX + scrollRangeX; 21720 final int top = -maxOverScrollY; 21721 final int bottom = maxOverScrollY + scrollRangeY; 21722 21723 boolean clampedX = false; 21724 if (newScrollX > right) { 21725 newScrollX = right; 21726 clampedX = true; 21727 } else if (newScrollX < left) { 21728 newScrollX = left; 21729 clampedX = true; 21730 } 21731 21732 boolean clampedY = false; 21733 if (newScrollY > bottom) { 21734 newScrollY = bottom; 21735 clampedY = true; 21736 } else if (newScrollY < top) { 21737 newScrollY = top; 21738 clampedY = true; 21739 } 21740 21741 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 21742 21743 return clampedX || clampedY; 21744 } 21745 21746 /** 21747 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 21748 * respond to the results of an over-scroll operation. 21749 * 21750 * @param scrollX New X scroll value in pixels 21751 * @param scrollY New Y scroll value in pixels 21752 * @param clampedX True if scrollX was clamped to an over-scroll boundary 21753 * @param clampedY True if scrollY was clamped to an over-scroll boundary 21754 */ 21755 protected void onOverScrolled(int scrollX, int scrollY, 21756 boolean clampedX, boolean clampedY) { 21757 // Intentionally empty. 21758 } 21759 21760 /** 21761 * Returns the over-scroll mode for this view. The result will be 21762 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21763 * (allow over-scrolling only if the view content is larger than the container), 21764 * or {@link #OVER_SCROLL_NEVER}. 21765 * 21766 * @return This view's over-scroll mode. 21767 */ 21768 public int getOverScrollMode() { 21769 return mOverScrollMode; 21770 } 21771 21772 /** 21773 * Set the over-scroll mode for this view. Valid over-scroll modes are 21774 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21775 * (allow over-scrolling only if the view content is larger than the container), 21776 * or {@link #OVER_SCROLL_NEVER}. 21777 * 21778 * Setting the over-scroll mode of a view will have an effect only if the 21779 * view is capable of scrolling. 21780 * 21781 * @param overScrollMode The new over-scroll mode for this view. 21782 */ 21783 public void setOverScrollMode(int overScrollMode) { 21784 if (overScrollMode != OVER_SCROLL_ALWAYS && 21785 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 21786 overScrollMode != OVER_SCROLL_NEVER) { 21787 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 21788 } 21789 mOverScrollMode = overScrollMode; 21790 } 21791 21792 /** 21793 * Enable or disable nested scrolling for this view. 21794 * 21795 * <p>If this property is set to true the view will be permitted to initiate nested 21796 * scrolling operations with a compatible parent view in the current hierarchy. If this 21797 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 21798 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 21799 * the nested scroll.</p> 21800 * 21801 * @param enabled true to enable nested scrolling, false to disable 21802 * 21803 * @see #isNestedScrollingEnabled() 21804 */ 21805 public void setNestedScrollingEnabled(boolean enabled) { 21806 if (enabled) { 21807 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 21808 } else { 21809 stopNestedScroll(); 21810 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 21811 } 21812 } 21813 21814 /** 21815 * Returns true if nested scrolling is enabled for this view. 21816 * 21817 * <p>If nested scrolling is enabled and this View class implementation supports it, 21818 * this view will act as a nested scrolling child view when applicable, forwarding data 21819 * about the scroll operation in progress to a compatible and cooperating nested scrolling 21820 * parent.</p> 21821 * 21822 * @return true if nested scrolling is enabled 21823 * 21824 * @see #setNestedScrollingEnabled(boolean) 21825 */ 21826 public boolean isNestedScrollingEnabled() { 21827 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 21828 PFLAG3_NESTED_SCROLLING_ENABLED; 21829 } 21830 21831 /** 21832 * Begin a nestable scroll operation along the given axes. 21833 * 21834 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 21835 * 21836 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 21837 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 21838 * In the case of touch scrolling the nested scroll will be terminated automatically in 21839 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 21840 * In the event of programmatic scrolling the caller must explicitly call 21841 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 21842 * 21843 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 21844 * If it returns false the caller may ignore the rest of this contract until the next scroll. 21845 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 21846 * 21847 * <p>At each incremental step of the scroll the caller should invoke 21848 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 21849 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 21850 * parent at least partially consumed the scroll and the caller should adjust the amount it 21851 * scrolls by.</p> 21852 * 21853 * <p>After applying the remainder of the scroll delta the caller should invoke 21854 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 21855 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 21856 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 21857 * </p> 21858 * 21859 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 21860 * {@link #SCROLL_AXIS_VERTICAL}. 21861 * @return true if a cooperative parent was found and nested scrolling has been enabled for 21862 * the current gesture. 21863 * 21864 * @see #stopNestedScroll() 21865 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21866 * @see #dispatchNestedScroll(int, int, int, int, int[]) 21867 */ 21868 public boolean startNestedScroll(int axes) { 21869 if (hasNestedScrollingParent()) { 21870 // Already in progress 21871 return true; 21872 } 21873 if (isNestedScrollingEnabled()) { 21874 ViewParent p = getParent(); 21875 View child = this; 21876 while (p != null) { 21877 try { 21878 if (p.onStartNestedScroll(child, this, axes)) { 21879 mNestedScrollingParent = p; 21880 p.onNestedScrollAccepted(child, this, axes); 21881 return true; 21882 } 21883 } catch (AbstractMethodError e) { 21884 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 21885 "method onStartNestedScroll", e); 21886 // Allow the search upward to continue 21887 } 21888 if (p instanceof View) { 21889 child = (View) p; 21890 } 21891 p = p.getParent(); 21892 } 21893 } 21894 return false; 21895 } 21896 21897 /** 21898 * Stop a nested scroll in progress. 21899 * 21900 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 21901 * 21902 * @see #startNestedScroll(int) 21903 */ 21904 public void stopNestedScroll() { 21905 if (mNestedScrollingParent != null) { 21906 mNestedScrollingParent.onStopNestedScroll(this); 21907 mNestedScrollingParent = null; 21908 } 21909 } 21910 21911 /** 21912 * Returns true if this view has a nested scrolling parent. 21913 * 21914 * <p>The presence of a nested scrolling parent indicates that this view has initiated 21915 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 21916 * 21917 * @return whether this view has a nested scrolling parent 21918 */ 21919 public boolean hasNestedScrollingParent() { 21920 return mNestedScrollingParent != null; 21921 } 21922 21923 /** 21924 * Dispatch one step of a nested scroll in progress. 21925 * 21926 * <p>Implementations of views that support nested scrolling should call this to report 21927 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 21928 * is not currently in progress or nested scrolling is not 21929 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 21930 * 21931 * <p>Compatible View implementations should also call 21932 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 21933 * consuming a component of the scroll event themselves.</p> 21934 * 21935 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 21936 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 21937 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 21938 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 21939 * @param offsetInWindow Optional. If not null, on return this will contain the offset 21940 * in local view coordinates of this view from before this operation 21941 * to after it completes. View implementations may use this to adjust 21942 * expected input coordinate tracking. 21943 * @return true if the event was dispatched, false if it could not be dispatched. 21944 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21945 */ 21946 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 21947 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 21948 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21949 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 21950 int startX = 0; 21951 int startY = 0; 21952 if (offsetInWindow != null) { 21953 getLocationInWindow(offsetInWindow); 21954 startX = offsetInWindow[0]; 21955 startY = offsetInWindow[1]; 21956 } 21957 21958 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 21959 dxUnconsumed, dyUnconsumed); 21960 21961 if (offsetInWindow != null) { 21962 getLocationInWindow(offsetInWindow); 21963 offsetInWindow[0] -= startX; 21964 offsetInWindow[1] -= startY; 21965 } 21966 return true; 21967 } else if (offsetInWindow != null) { 21968 // No motion, no dispatch. Keep offsetInWindow up to date. 21969 offsetInWindow[0] = 0; 21970 offsetInWindow[1] = 0; 21971 } 21972 } 21973 return false; 21974 } 21975 21976 /** 21977 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 21978 * 21979 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 21980 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 21981 * scrolling operation to consume some or all of the scroll operation before the child view 21982 * consumes it.</p> 21983 * 21984 * @param dx Horizontal scroll distance in pixels 21985 * @param dy Vertical scroll distance in pixels 21986 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 21987 * and consumed[1] the consumed dy. 21988 * @param offsetInWindow Optional. If not null, on return this will contain the offset 21989 * in local view coordinates of this view from before this operation 21990 * to after it completes. View implementations may use this to adjust 21991 * expected input coordinate tracking. 21992 * @return true if the parent consumed some or all of the scroll delta 21993 * @see #dispatchNestedScroll(int, int, int, int, int[]) 21994 */ 21995 public boolean dispatchNestedPreScroll(int dx, int dy, 21996 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 21997 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21998 if (dx != 0 || dy != 0) { 21999 int startX = 0; 22000 int startY = 0; 22001 if (offsetInWindow != null) { 22002 getLocationInWindow(offsetInWindow); 22003 startX = offsetInWindow[0]; 22004 startY = offsetInWindow[1]; 22005 } 22006 22007 if (consumed == null) { 22008 if (mTempNestedScrollConsumed == null) { 22009 mTempNestedScrollConsumed = new int[2]; 22010 } 22011 consumed = mTempNestedScrollConsumed; 22012 } 22013 consumed[0] = 0; 22014 consumed[1] = 0; 22015 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 22016 22017 if (offsetInWindow != null) { 22018 getLocationInWindow(offsetInWindow); 22019 offsetInWindow[0] -= startX; 22020 offsetInWindow[1] -= startY; 22021 } 22022 return consumed[0] != 0 || consumed[1] != 0; 22023 } else if (offsetInWindow != null) { 22024 offsetInWindow[0] = 0; 22025 offsetInWindow[1] = 0; 22026 } 22027 } 22028 return false; 22029 } 22030 22031 /** 22032 * Dispatch a fling to a nested scrolling parent. 22033 * 22034 * <p>This method should be used to indicate that a nested scrolling child has detected 22035 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 22036 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 22037 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 22038 * along a scrollable axis.</p> 22039 * 22040 * <p>If a nested scrolling child view would normally fling but it is at the edge of 22041 * its own content, it can use this method to delegate the fling to its nested scrolling 22042 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 22043 * 22044 * @param velocityX Horizontal fling velocity in pixels per second 22045 * @param velocityY Vertical fling velocity in pixels per second 22046 * @param consumed true if the child consumed the fling, false otherwise 22047 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 22048 */ 22049 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 22050 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22051 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 22052 } 22053 return false; 22054 } 22055 22056 /** 22057 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 22058 * 22059 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 22060 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 22061 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 22062 * before the child view consumes it. If this method returns <code>true</code>, a nested 22063 * parent view consumed the fling and this view should not scroll as a result.</p> 22064 * 22065 * <p>For a better user experience, only one view in a nested scrolling chain should consume 22066 * the fling at a time. If a parent view consumed the fling this method will return false. 22067 * Custom view implementations should account for this in two ways:</p> 22068 * 22069 * <ul> 22070 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 22071 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 22072 * position regardless.</li> 22073 * <li>If a nested parent does consume the fling, this view should not scroll at all, 22074 * even to settle back to a valid idle position.</li> 22075 * </ul> 22076 * 22077 * <p>Views should also not offer fling velocities to nested parent views along an axis 22078 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 22079 * should not offer a horizontal fling velocity to its parents since scrolling along that 22080 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 22081 * 22082 * @param velocityX Horizontal fling velocity in pixels per second 22083 * @param velocityY Vertical fling velocity in pixels per second 22084 * @return true if a nested scrolling parent consumed the fling 22085 */ 22086 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 22087 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22088 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 22089 } 22090 return false; 22091 } 22092 22093 /** 22094 * Gets a scale factor that determines the distance the view should scroll 22095 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 22096 * @return The vertical scroll scale factor. 22097 * @hide 22098 */ 22099 protected float getVerticalScrollFactor() { 22100 if (mVerticalScrollFactor == 0) { 22101 TypedValue outValue = new TypedValue(); 22102 if (!mContext.getTheme().resolveAttribute( 22103 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 22104 throw new IllegalStateException( 22105 "Expected theme to define listPreferredItemHeight."); 22106 } 22107 mVerticalScrollFactor = outValue.getDimension( 22108 mContext.getResources().getDisplayMetrics()); 22109 } 22110 return mVerticalScrollFactor; 22111 } 22112 22113 /** 22114 * Gets a scale factor that determines the distance the view should scroll 22115 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 22116 * @return The horizontal scroll scale factor. 22117 * @hide 22118 */ 22119 protected float getHorizontalScrollFactor() { 22120 // TODO: Should use something else. 22121 return getVerticalScrollFactor(); 22122 } 22123 22124 /** 22125 * Return the value specifying the text direction or policy that was set with 22126 * {@link #setTextDirection(int)}. 22127 * 22128 * @return the defined text direction. It can be one of: 22129 * 22130 * {@link #TEXT_DIRECTION_INHERIT}, 22131 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22132 * {@link #TEXT_DIRECTION_ANY_RTL}, 22133 * {@link #TEXT_DIRECTION_LTR}, 22134 * {@link #TEXT_DIRECTION_RTL}, 22135 * {@link #TEXT_DIRECTION_LOCALE}, 22136 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22137 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22138 * 22139 * @attr ref android.R.styleable#View_textDirection 22140 * 22141 * @hide 22142 */ 22143 @ViewDebug.ExportedProperty(category = "text", mapping = { 22144 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22145 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22146 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22147 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22148 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22149 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22150 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22151 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22152 }) 22153 public int getRawTextDirection() { 22154 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 22155 } 22156 22157 /** 22158 * Set the text direction. 22159 * 22160 * @param textDirection the direction to set. Should be one of: 22161 * 22162 * {@link #TEXT_DIRECTION_INHERIT}, 22163 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22164 * {@link #TEXT_DIRECTION_ANY_RTL}, 22165 * {@link #TEXT_DIRECTION_LTR}, 22166 * {@link #TEXT_DIRECTION_RTL}, 22167 * {@link #TEXT_DIRECTION_LOCALE} 22168 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22169 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 22170 * 22171 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 22172 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 22173 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 22174 * 22175 * @attr ref android.R.styleable#View_textDirection 22176 */ 22177 public void setTextDirection(int textDirection) { 22178 if (getRawTextDirection() != textDirection) { 22179 // Reset the current text direction and the resolved one 22180 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 22181 resetResolvedTextDirection(); 22182 // Set the new text direction 22183 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 22184 // Do resolution 22185 resolveTextDirection(); 22186 // Notify change 22187 onRtlPropertiesChanged(getLayoutDirection()); 22188 // Refresh 22189 requestLayout(); 22190 invalidate(true); 22191 } 22192 } 22193 22194 /** 22195 * Return the resolved text direction. 22196 * 22197 * @return the resolved text direction. Returns one of: 22198 * 22199 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22200 * {@link #TEXT_DIRECTION_ANY_RTL}, 22201 * {@link #TEXT_DIRECTION_LTR}, 22202 * {@link #TEXT_DIRECTION_RTL}, 22203 * {@link #TEXT_DIRECTION_LOCALE}, 22204 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22205 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22206 * 22207 * @attr ref android.R.styleable#View_textDirection 22208 */ 22209 @ViewDebug.ExportedProperty(category = "text", mapping = { 22210 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22211 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22212 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22213 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22214 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22215 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22216 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22217 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22218 }) 22219 public int getTextDirection() { 22220 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 22221 } 22222 22223 /** 22224 * Resolve the text direction. 22225 * 22226 * @return true if resolution has been done, false otherwise. 22227 * 22228 * @hide 22229 */ 22230 public boolean resolveTextDirection() { 22231 // Reset any previous text direction resolution 22232 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22233 22234 if (hasRtlSupport()) { 22235 // Set resolved text direction flag depending on text direction flag 22236 final int textDirection = getRawTextDirection(); 22237 switch(textDirection) { 22238 case TEXT_DIRECTION_INHERIT: 22239 if (!canResolveTextDirection()) { 22240 // We cannot do the resolution if there is no parent, so use the default one 22241 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22242 // Resolution will need to happen again later 22243 return false; 22244 } 22245 22246 // Parent has not yet resolved, so we still return the default 22247 try { 22248 if (!mParent.isTextDirectionResolved()) { 22249 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22250 // Resolution will need to happen again later 22251 return false; 22252 } 22253 } catch (AbstractMethodError e) { 22254 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22255 " does not fully implement ViewParent", e); 22256 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 22257 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22258 return true; 22259 } 22260 22261 // Set current resolved direction to the same value as the parent's one 22262 int parentResolvedDirection; 22263 try { 22264 parentResolvedDirection = mParent.getTextDirection(); 22265 } catch (AbstractMethodError e) { 22266 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22267 " does not fully implement ViewParent", e); 22268 parentResolvedDirection = TEXT_DIRECTION_LTR; 22269 } 22270 switch (parentResolvedDirection) { 22271 case TEXT_DIRECTION_FIRST_STRONG: 22272 case TEXT_DIRECTION_ANY_RTL: 22273 case TEXT_DIRECTION_LTR: 22274 case TEXT_DIRECTION_RTL: 22275 case TEXT_DIRECTION_LOCALE: 22276 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22277 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22278 mPrivateFlags2 |= 22279 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22280 break; 22281 default: 22282 // Default resolved direction is "first strong" heuristic 22283 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22284 } 22285 break; 22286 case TEXT_DIRECTION_FIRST_STRONG: 22287 case TEXT_DIRECTION_ANY_RTL: 22288 case TEXT_DIRECTION_LTR: 22289 case TEXT_DIRECTION_RTL: 22290 case TEXT_DIRECTION_LOCALE: 22291 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22292 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22293 // Resolved direction is the same as text direction 22294 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22295 break; 22296 default: 22297 // Default resolved direction is "first strong" heuristic 22298 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22299 } 22300 } else { 22301 // Default resolved direction is "first strong" heuristic 22302 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22303 } 22304 22305 // Set to resolved 22306 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 22307 return true; 22308 } 22309 22310 /** 22311 * Check if text direction resolution can be done. 22312 * 22313 * @return true if text direction resolution can be done otherwise return false. 22314 */ 22315 public boolean canResolveTextDirection() { 22316 switch (getRawTextDirection()) { 22317 case TEXT_DIRECTION_INHERIT: 22318 if (mParent != null) { 22319 try { 22320 return mParent.canResolveTextDirection(); 22321 } catch (AbstractMethodError e) { 22322 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22323 " does not fully implement ViewParent", e); 22324 } 22325 } 22326 return false; 22327 22328 default: 22329 return true; 22330 } 22331 } 22332 22333 /** 22334 * Reset resolved text direction. Text direction will be resolved during a call to 22335 * {@link #onMeasure(int, int)}. 22336 * 22337 * @hide 22338 */ 22339 public void resetResolvedTextDirection() { 22340 // Reset any previous text direction resolution 22341 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22342 // Set to default value 22343 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22344 } 22345 22346 /** 22347 * @return true if text direction is inherited. 22348 * 22349 * @hide 22350 */ 22351 public boolean isTextDirectionInherited() { 22352 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 22353 } 22354 22355 /** 22356 * @return true if text direction is resolved. 22357 */ 22358 public boolean isTextDirectionResolved() { 22359 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 22360 } 22361 22362 /** 22363 * Return the value specifying the text alignment or policy that was set with 22364 * {@link #setTextAlignment(int)}. 22365 * 22366 * @return the defined text alignment. It can be one of: 22367 * 22368 * {@link #TEXT_ALIGNMENT_INHERIT}, 22369 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22370 * {@link #TEXT_ALIGNMENT_CENTER}, 22371 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22372 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22373 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22374 * {@link #TEXT_ALIGNMENT_VIEW_END} 22375 * 22376 * @attr ref android.R.styleable#View_textAlignment 22377 * 22378 * @hide 22379 */ 22380 @ViewDebug.ExportedProperty(category = "text", mapping = { 22381 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22382 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22383 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22384 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22385 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22386 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22387 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22388 }) 22389 @TextAlignment 22390 public int getRawTextAlignment() { 22391 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 22392 } 22393 22394 /** 22395 * Set the text alignment. 22396 * 22397 * @param textAlignment The text alignment to set. Should be one of 22398 * 22399 * {@link #TEXT_ALIGNMENT_INHERIT}, 22400 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22401 * {@link #TEXT_ALIGNMENT_CENTER}, 22402 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22403 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22404 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22405 * {@link #TEXT_ALIGNMENT_VIEW_END} 22406 * 22407 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 22408 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 22409 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 22410 * 22411 * @attr ref android.R.styleable#View_textAlignment 22412 */ 22413 public void setTextAlignment(@TextAlignment int textAlignment) { 22414 if (textAlignment != getRawTextAlignment()) { 22415 // Reset the current and resolved text alignment 22416 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 22417 resetResolvedTextAlignment(); 22418 // Set the new text alignment 22419 mPrivateFlags2 |= 22420 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 22421 // Do resolution 22422 resolveTextAlignment(); 22423 // Notify change 22424 onRtlPropertiesChanged(getLayoutDirection()); 22425 // Refresh 22426 requestLayout(); 22427 invalidate(true); 22428 } 22429 } 22430 22431 /** 22432 * Return the resolved text alignment. 22433 * 22434 * @return the resolved text alignment. Returns one of: 22435 * 22436 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22437 * {@link #TEXT_ALIGNMENT_CENTER}, 22438 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22439 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22440 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22441 * {@link #TEXT_ALIGNMENT_VIEW_END} 22442 * 22443 * @attr ref android.R.styleable#View_textAlignment 22444 */ 22445 @ViewDebug.ExportedProperty(category = "text", mapping = { 22446 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22447 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22448 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22449 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22450 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22451 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22452 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22453 }) 22454 @TextAlignment 22455 public int getTextAlignment() { 22456 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 22457 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 22458 } 22459 22460 /** 22461 * Resolve the text alignment. 22462 * 22463 * @return true if resolution has been done, false otherwise. 22464 * 22465 * @hide 22466 */ 22467 public boolean resolveTextAlignment() { 22468 // Reset any previous text alignment resolution 22469 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22470 22471 if (hasRtlSupport()) { 22472 // Set resolved text alignment flag depending on text alignment flag 22473 final int textAlignment = getRawTextAlignment(); 22474 switch (textAlignment) { 22475 case TEXT_ALIGNMENT_INHERIT: 22476 // Check if we can resolve the text alignment 22477 if (!canResolveTextAlignment()) { 22478 // We cannot do the resolution if there is no parent so use the default 22479 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22480 // Resolution will need to happen again later 22481 return false; 22482 } 22483 22484 // Parent has not yet resolved, so we still return the default 22485 try { 22486 if (!mParent.isTextAlignmentResolved()) { 22487 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22488 // Resolution will need to happen again later 22489 return false; 22490 } 22491 } catch (AbstractMethodError e) { 22492 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22493 " does not fully implement ViewParent", e); 22494 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 22495 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22496 return true; 22497 } 22498 22499 int parentResolvedTextAlignment; 22500 try { 22501 parentResolvedTextAlignment = mParent.getTextAlignment(); 22502 } catch (AbstractMethodError e) { 22503 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22504 " does not fully implement ViewParent", e); 22505 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 22506 } 22507 switch (parentResolvedTextAlignment) { 22508 case TEXT_ALIGNMENT_GRAVITY: 22509 case TEXT_ALIGNMENT_TEXT_START: 22510 case TEXT_ALIGNMENT_TEXT_END: 22511 case TEXT_ALIGNMENT_CENTER: 22512 case TEXT_ALIGNMENT_VIEW_START: 22513 case TEXT_ALIGNMENT_VIEW_END: 22514 // Resolved text alignment is the same as the parent resolved 22515 // text alignment 22516 mPrivateFlags2 |= 22517 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22518 break; 22519 default: 22520 // Use default resolved text alignment 22521 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22522 } 22523 break; 22524 case TEXT_ALIGNMENT_GRAVITY: 22525 case TEXT_ALIGNMENT_TEXT_START: 22526 case TEXT_ALIGNMENT_TEXT_END: 22527 case TEXT_ALIGNMENT_CENTER: 22528 case TEXT_ALIGNMENT_VIEW_START: 22529 case TEXT_ALIGNMENT_VIEW_END: 22530 // Resolved text alignment is the same as text alignment 22531 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22532 break; 22533 default: 22534 // Use default resolved text alignment 22535 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22536 } 22537 } else { 22538 // Use default resolved text alignment 22539 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22540 } 22541 22542 // Set the resolved 22543 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22544 return true; 22545 } 22546 22547 /** 22548 * Check if text alignment resolution can be done. 22549 * 22550 * @return true if text alignment resolution can be done otherwise return false. 22551 */ 22552 public boolean canResolveTextAlignment() { 22553 switch (getRawTextAlignment()) { 22554 case TEXT_DIRECTION_INHERIT: 22555 if (mParent != null) { 22556 try { 22557 return mParent.canResolveTextAlignment(); 22558 } catch (AbstractMethodError e) { 22559 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22560 " does not fully implement ViewParent", e); 22561 } 22562 } 22563 return false; 22564 22565 default: 22566 return true; 22567 } 22568 } 22569 22570 /** 22571 * Reset resolved text alignment. Text alignment will be resolved during a call to 22572 * {@link #onMeasure(int, int)}. 22573 * 22574 * @hide 22575 */ 22576 public void resetResolvedTextAlignment() { 22577 // Reset any previous text alignment resolution 22578 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22579 // Set to default 22580 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22581 } 22582 22583 /** 22584 * @return true if text alignment is inherited. 22585 * 22586 * @hide 22587 */ 22588 public boolean isTextAlignmentInherited() { 22589 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 22590 } 22591 22592 /** 22593 * @return true if text alignment is resolved. 22594 */ 22595 public boolean isTextAlignmentResolved() { 22596 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22597 } 22598 22599 /** 22600 * Generate a value suitable for use in {@link #setId(int)}. 22601 * This value will not collide with ID values generated at build time by aapt for R.id. 22602 * 22603 * @return a generated ID value 22604 */ 22605 public static int generateViewId() { 22606 for (;;) { 22607 final int result = sNextGeneratedId.get(); 22608 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 22609 int newValue = result + 1; 22610 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 22611 if (sNextGeneratedId.compareAndSet(result, newValue)) { 22612 return result; 22613 } 22614 } 22615 } 22616 22617 private static boolean isViewIdGenerated(int id) { 22618 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 22619 } 22620 22621 /** 22622 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 22623 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 22624 * a normal View or a ViewGroup with 22625 * {@link android.view.ViewGroup#isTransitionGroup()} true. 22626 * @hide 22627 */ 22628 public void captureTransitioningViews(List<View> transitioningViews) { 22629 if (getVisibility() == View.VISIBLE) { 22630 transitioningViews.add(this); 22631 } 22632 } 22633 22634 /** 22635 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 22636 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 22637 * @hide 22638 */ 22639 public void findNamedViews(Map<String, View> namedElements) { 22640 if (getVisibility() == VISIBLE || mGhostView != null) { 22641 String transitionName = getTransitionName(); 22642 if (transitionName != null) { 22643 namedElements.put(transitionName, this); 22644 } 22645 } 22646 } 22647 22648 /** 22649 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 22650 * The default implementation does not care the location or event types, but some subclasses 22651 * may use it (such as WebViews). 22652 * @param event The MotionEvent from a mouse 22653 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 22654 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 22655 * @see PointerIcon 22656 */ 22657 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 22658 final float x = event.getX(pointerIndex); 22659 final float y = event.getY(pointerIndex); 22660 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 22661 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 22662 } 22663 return mPointerIcon; 22664 } 22665 22666 /** 22667 * Set the pointer icon for the current view. 22668 * Passing {@code null} will restore the pointer icon to its default value. 22669 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 22670 */ 22671 public void setPointerIcon(PointerIcon pointerIcon) { 22672 mPointerIcon = pointerIcon; 22673 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 22674 return; 22675 } 22676 try { 22677 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 22678 } catch (RemoteException e) { 22679 } 22680 } 22681 22682 /** 22683 * Gets the pointer icon for the current view. 22684 */ 22685 public PointerIcon getPointerIcon() { 22686 return mPointerIcon; 22687 } 22688 22689 // 22690 // Properties 22691 // 22692 /** 22693 * A Property wrapper around the <code>alpha</code> functionality handled by the 22694 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 22695 */ 22696 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 22697 @Override 22698 public void setValue(View object, float value) { 22699 object.setAlpha(value); 22700 } 22701 22702 @Override 22703 public Float get(View object) { 22704 return object.getAlpha(); 22705 } 22706 }; 22707 22708 /** 22709 * A Property wrapper around the <code>translationX</code> functionality handled by the 22710 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 22711 */ 22712 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 22713 @Override 22714 public void setValue(View object, float value) { 22715 object.setTranslationX(value); 22716 } 22717 22718 @Override 22719 public Float get(View object) { 22720 return object.getTranslationX(); 22721 } 22722 }; 22723 22724 /** 22725 * A Property wrapper around the <code>translationY</code> functionality handled by the 22726 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 22727 */ 22728 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 22729 @Override 22730 public void setValue(View object, float value) { 22731 object.setTranslationY(value); 22732 } 22733 22734 @Override 22735 public Float get(View object) { 22736 return object.getTranslationY(); 22737 } 22738 }; 22739 22740 /** 22741 * A Property wrapper around the <code>translationZ</code> functionality handled by the 22742 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 22743 */ 22744 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 22745 @Override 22746 public void setValue(View object, float value) { 22747 object.setTranslationZ(value); 22748 } 22749 22750 @Override 22751 public Float get(View object) { 22752 return object.getTranslationZ(); 22753 } 22754 }; 22755 22756 /** 22757 * A Property wrapper around the <code>x</code> functionality handled by the 22758 * {@link View#setX(float)} and {@link View#getX()} methods. 22759 */ 22760 public static final Property<View, Float> X = new FloatProperty<View>("x") { 22761 @Override 22762 public void setValue(View object, float value) { 22763 object.setX(value); 22764 } 22765 22766 @Override 22767 public Float get(View object) { 22768 return object.getX(); 22769 } 22770 }; 22771 22772 /** 22773 * A Property wrapper around the <code>y</code> functionality handled by the 22774 * {@link View#setY(float)} and {@link View#getY()} methods. 22775 */ 22776 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 22777 @Override 22778 public void setValue(View object, float value) { 22779 object.setY(value); 22780 } 22781 22782 @Override 22783 public Float get(View object) { 22784 return object.getY(); 22785 } 22786 }; 22787 22788 /** 22789 * A Property wrapper around the <code>z</code> functionality handled by the 22790 * {@link View#setZ(float)} and {@link View#getZ()} methods. 22791 */ 22792 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 22793 @Override 22794 public void setValue(View object, float value) { 22795 object.setZ(value); 22796 } 22797 22798 @Override 22799 public Float get(View object) { 22800 return object.getZ(); 22801 } 22802 }; 22803 22804 /** 22805 * A Property wrapper around the <code>rotation</code> functionality handled by the 22806 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 22807 */ 22808 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 22809 @Override 22810 public void setValue(View object, float value) { 22811 object.setRotation(value); 22812 } 22813 22814 @Override 22815 public Float get(View object) { 22816 return object.getRotation(); 22817 } 22818 }; 22819 22820 /** 22821 * A Property wrapper around the <code>rotationX</code> functionality handled by the 22822 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 22823 */ 22824 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 22825 @Override 22826 public void setValue(View object, float value) { 22827 object.setRotationX(value); 22828 } 22829 22830 @Override 22831 public Float get(View object) { 22832 return object.getRotationX(); 22833 } 22834 }; 22835 22836 /** 22837 * A Property wrapper around the <code>rotationY</code> functionality handled by the 22838 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 22839 */ 22840 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 22841 @Override 22842 public void setValue(View object, float value) { 22843 object.setRotationY(value); 22844 } 22845 22846 @Override 22847 public Float get(View object) { 22848 return object.getRotationY(); 22849 } 22850 }; 22851 22852 /** 22853 * A Property wrapper around the <code>scaleX</code> functionality handled by the 22854 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 22855 */ 22856 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 22857 @Override 22858 public void setValue(View object, float value) { 22859 object.setScaleX(value); 22860 } 22861 22862 @Override 22863 public Float get(View object) { 22864 return object.getScaleX(); 22865 } 22866 }; 22867 22868 /** 22869 * A Property wrapper around the <code>scaleY</code> functionality handled by the 22870 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 22871 */ 22872 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 22873 @Override 22874 public void setValue(View object, float value) { 22875 object.setScaleY(value); 22876 } 22877 22878 @Override 22879 public Float get(View object) { 22880 return object.getScaleY(); 22881 } 22882 }; 22883 22884 /** 22885 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 22886 * Each MeasureSpec represents a requirement for either the width or the height. 22887 * A MeasureSpec is comprised of a size and a mode. There are three possible 22888 * modes: 22889 * <dl> 22890 * <dt>UNSPECIFIED</dt> 22891 * <dd> 22892 * The parent has not imposed any constraint on the child. It can be whatever size 22893 * it wants. 22894 * </dd> 22895 * 22896 * <dt>EXACTLY</dt> 22897 * <dd> 22898 * The parent has determined an exact size for the child. The child is going to be 22899 * given those bounds regardless of how big it wants to be. 22900 * </dd> 22901 * 22902 * <dt>AT_MOST</dt> 22903 * <dd> 22904 * The child can be as large as it wants up to the specified size. 22905 * </dd> 22906 * </dl> 22907 * 22908 * MeasureSpecs are implemented as ints to reduce object allocation. This class 22909 * is provided to pack and unpack the <size, mode> tuple into the int. 22910 */ 22911 public static class MeasureSpec { 22912 private static final int MODE_SHIFT = 30; 22913 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 22914 22915 /** @hide */ 22916 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 22917 @Retention(RetentionPolicy.SOURCE) 22918 public @interface MeasureSpecMode {} 22919 22920 /** 22921 * Measure specification mode: The parent has not imposed any constraint 22922 * on the child. It can be whatever size it wants. 22923 */ 22924 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 22925 22926 /** 22927 * Measure specification mode: The parent has determined an exact size 22928 * for the child. The child is going to be given those bounds regardless 22929 * of how big it wants to be. 22930 */ 22931 public static final int EXACTLY = 1 << MODE_SHIFT; 22932 22933 /** 22934 * Measure specification mode: The child can be as large as it wants up 22935 * to the specified size. 22936 */ 22937 public static final int AT_MOST = 2 << MODE_SHIFT; 22938 22939 /** 22940 * Creates a measure specification based on the supplied size and mode. 22941 * 22942 * The mode must always be one of the following: 22943 * <ul> 22944 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 22945 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 22946 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 22947 * </ul> 22948 * 22949 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 22950 * implementation was such that the order of arguments did not matter 22951 * and overflow in either value could impact the resulting MeasureSpec. 22952 * {@link android.widget.RelativeLayout} was affected by this bug. 22953 * Apps targeting API levels greater than 17 will get the fixed, more strict 22954 * behavior.</p> 22955 * 22956 * @param size the size of the measure specification 22957 * @param mode the mode of the measure specification 22958 * @return the measure specification based on size and mode 22959 */ 22960 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 22961 @MeasureSpecMode int mode) { 22962 if (sUseBrokenMakeMeasureSpec) { 22963 return size + mode; 22964 } else { 22965 return (size & ~MODE_MASK) | (mode & MODE_MASK); 22966 } 22967 } 22968 22969 /** 22970 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 22971 * will automatically get a size of 0. Older apps expect this. 22972 * 22973 * @hide internal use only for compatibility with system widgets and older apps 22974 */ 22975 public static int makeSafeMeasureSpec(int size, int mode) { 22976 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 22977 return 0; 22978 } 22979 return makeMeasureSpec(size, mode); 22980 } 22981 22982 /** 22983 * Extracts the mode from the supplied measure specification. 22984 * 22985 * @param measureSpec the measure specification to extract the mode from 22986 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 22987 * {@link android.view.View.MeasureSpec#AT_MOST} or 22988 * {@link android.view.View.MeasureSpec#EXACTLY} 22989 */ 22990 @MeasureSpecMode 22991 public static int getMode(int measureSpec) { 22992 //noinspection ResourceType 22993 return (measureSpec & MODE_MASK); 22994 } 22995 22996 /** 22997 * Extracts the size from the supplied measure specification. 22998 * 22999 * @param measureSpec the measure specification to extract the size from 23000 * @return the size in pixels defined in the supplied measure specification 23001 */ 23002 public static int getSize(int measureSpec) { 23003 return (measureSpec & ~MODE_MASK); 23004 } 23005 23006 static int adjust(int measureSpec, int delta) { 23007 final int mode = getMode(measureSpec); 23008 int size = getSize(measureSpec); 23009 if (mode == UNSPECIFIED) { 23010 // No need to adjust size for UNSPECIFIED mode. 23011 return makeMeasureSpec(size, UNSPECIFIED); 23012 } 23013 size += delta; 23014 if (size < 0) { 23015 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 23016 ") spec: " + toString(measureSpec) + " delta: " + delta); 23017 size = 0; 23018 } 23019 return makeMeasureSpec(size, mode); 23020 } 23021 23022 /** 23023 * Returns a String representation of the specified measure 23024 * specification. 23025 * 23026 * @param measureSpec the measure specification to convert to a String 23027 * @return a String with the following format: "MeasureSpec: MODE SIZE" 23028 */ 23029 public static String toString(int measureSpec) { 23030 int mode = getMode(measureSpec); 23031 int size = getSize(measureSpec); 23032 23033 StringBuilder sb = new StringBuilder("MeasureSpec: "); 23034 23035 if (mode == UNSPECIFIED) 23036 sb.append("UNSPECIFIED "); 23037 else if (mode == EXACTLY) 23038 sb.append("EXACTLY "); 23039 else if (mode == AT_MOST) 23040 sb.append("AT_MOST "); 23041 else 23042 sb.append(mode).append(" "); 23043 23044 sb.append(size); 23045 return sb.toString(); 23046 } 23047 } 23048 23049 private final class CheckForLongPress implements Runnable { 23050 private int mOriginalWindowAttachCount; 23051 private float mX; 23052 private float mY; 23053 private boolean mOriginalPressedState; 23054 23055 @Override 23056 public void run() { 23057 if ((mOriginalPressedState == isPressed()) && (mParent != null) 23058 && mOriginalWindowAttachCount == mWindowAttachCount) { 23059 if (performLongClick(mX, mY)) { 23060 mHasPerformedLongPress = true; 23061 } 23062 } 23063 } 23064 23065 public void setAnchor(float x, float y) { 23066 mX = x; 23067 mY = y; 23068 } 23069 23070 public void rememberWindowAttachCount() { 23071 mOriginalWindowAttachCount = mWindowAttachCount; 23072 } 23073 23074 public void rememberPressedState() { 23075 mOriginalPressedState = isPressed(); 23076 } 23077 } 23078 23079 private final class CheckForTap implements Runnable { 23080 public float x; 23081 public float y; 23082 23083 @Override 23084 public void run() { 23085 mPrivateFlags &= ~PFLAG_PREPRESSED; 23086 setPressed(true, x, y); 23087 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 23088 } 23089 } 23090 23091 private final class PerformClick implements Runnable { 23092 @Override 23093 public void run() { 23094 performClick(); 23095 } 23096 } 23097 23098 /** 23099 * This method returns a ViewPropertyAnimator object, which can be used to animate 23100 * specific properties on this View. 23101 * 23102 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 23103 */ 23104 public ViewPropertyAnimator animate() { 23105 if (mAnimator == null) { 23106 mAnimator = new ViewPropertyAnimator(this); 23107 } 23108 return mAnimator; 23109 } 23110 23111 /** 23112 * Sets the name of the View to be used to identify Views in Transitions. 23113 * Names should be unique in the View hierarchy. 23114 * 23115 * @param transitionName The name of the View to uniquely identify it for Transitions. 23116 */ 23117 public final void setTransitionName(String transitionName) { 23118 mTransitionName = transitionName; 23119 } 23120 23121 /** 23122 * Returns the name of the View to be used to identify Views in Transitions. 23123 * Names should be unique in the View hierarchy. 23124 * 23125 * <p>This returns null if the View has not been given a name.</p> 23126 * 23127 * @return The name used of the View to be used to identify Views in Transitions or null 23128 * if no name has been given. 23129 */ 23130 @ViewDebug.ExportedProperty 23131 public String getTransitionName() { 23132 return mTransitionName; 23133 } 23134 23135 /** 23136 * @hide 23137 */ 23138 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 23139 // Do nothing. 23140 } 23141 23142 /** 23143 * Interface definition for a callback to be invoked when a hardware key event is 23144 * dispatched to this view. The callback will be invoked before the key event is 23145 * given to the view. This is only useful for hardware keyboards; a software input 23146 * method has no obligation to trigger this listener. 23147 */ 23148 public interface OnKeyListener { 23149 /** 23150 * Called when a hardware key is dispatched to a view. This allows listeners to 23151 * get a chance to respond before the target view. 23152 * <p>Key presses in software keyboards will generally NOT trigger this method, 23153 * although some may elect to do so in some situations. Do not assume a 23154 * software input method has to be key-based; even if it is, it may use key presses 23155 * in a different way than you expect, so there is no way to reliably catch soft 23156 * input key presses. 23157 * 23158 * @param v The view the key has been dispatched to. 23159 * @param keyCode The code for the physical key that was pressed 23160 * @param event The KeyEvent object containing full information about 23161 * the event. 23162 * @return True if the listener has consumed the event, false otherwise. 23163 */ 23164 boolean onKey(View v, int keyCode, KeyEvent event); 23165 } 23166 23167 /** 23168 * Interface definition for a callback to be invoked when a touch event is 23169 * dispatched to this view. The callback will be invoked before the touch 23170 * event is given to the view. 23171 */ 23172 public interface OnTouchListener { 23173 /** 23174 * Called when a touch event is dispatched to a view. This allows listeners to 23175 * get a chance to respond before the target view. 23176 * 23177 * @param v The view the touch event has been dispatched to. 23178 * @param event The MotionEvent object containing full information about 23179 * the event. 23180 * @return True if the listener has consumed the event, false otherwise. 23181 */ 23182 boolean onTouch(View v, MotionEvent event); 23183 } 23184 23185 /** 23186 * Interface definition for a callback to be invoked when a hover event is 23187 * dispatched to this view. The callback will be invoked before the hover 23188 * event is given to the view. 23189 */ 23190 public interface OnHoverListener { 23191 /** 23192 * Called when a hover event is dispatched to a view. This allows listeners to 23193 * get a chance to respond before the target view. 23194 * 23195 * @param v The view the hover event has been dispatched to. 23196 * @param event The MotionEvent object containing full information about 23197 * the event. 23198 * @return True if the listener has consumed the event, false otherwise. 23199 */ 23200 boolean onHover(View v, MotionEvent event); 23201 } 23202 23203 /** 23204 * Interface definition for a callback to be invoked when a generic motion event is 23205 * dispatched to this view. The callback will be invoked before the generic motion 23206 * event is given to the view. 23207 */ 23208 public interface OnGenericMotionListener { 23209 /** 23210 * Called when a generic motion event is dispatched to a view. This allows listeners to 23211 * get a chance to respond before the target view. 23212 * 23213 * @param v The view the generic motion event has been dispatched to. 23214 * @param event The MotionEvent object containing full information about 23215 * the event. 23216 * @return True if the listener has consumed the event, false otherwise. 23217 */ 23218 boolean onGenericMotion(View v, MotionEvent event); 23219 } 23220 23221 /** 23222 * Interface definition for a callback to be invoked when a view has been clicked and held. 23223 */ 23224 public interface OnLongClickListener { 23225 /** 23226 * Called when a view has been clicked and held. 23227 * 23228 * @param v The view that was clicked and held. 23229 * 23230 * @return true if the callback consumed the long click, false otherwise. 23231 */ 23232 boolean onLongClick(View v); 23233 } 23234 23235 /** 23236 * Interface definition for a callback to be invoked when a drag is being dispatched 23237 * to this view. The callback will be invoked before the hosting view's own 23238 * onDrag(event) method. If the listener wants to fall back to the hosting view's 23239 * onDrag(event) behavior, it should return 'false' from this callback. 23240 * 23241 * <div class="special reference"> 23242 * <h3>Developer Guides</h3> 23243 * <p>For a guide to implementing drag and drop features, read the 23244 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 23245 * </div> 23246 */ 23247 public interface OnDragListener { 23248 /** 23249 * Called when a drag event is dispatched to a view. This allows listeners 23250 * to get a chance to override base View behavior. 23251 * 23252 * @param v The View that received the drag event. 23253 * @param event The {@link android.view.DragEvent} object for the drag event. 23254 * @return {@code true} if the drag event was handled successfully, or {@code false} 23255 * if the drag event was not handled. Note that {@code false} will trigger the View 23256 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 23257 */ 23258 boolean onDrag(View v, DragEvent event); 23259 } 23260 23261 /** 23262 * Interface definition for a callback to be invoked when the focus state of 23263 * a view changed. 23264 */ 23265 public interface OnFocusChangeListener { 23266 /** 23267 * Called when the focus state of a view has changed. 23268 * 23269 * @param v The view whose state has changed. 23270 * @param hasFocus The new focus state of v. 23271 */ 23272 void onFocusChange(View v, boolean hasFocus); 23273 } 23274 23275 /** 23276 * Interface definition for a callback to be invoked when a view is clicked. 23277 */ 23278 public interface OnClickListener { 23279 /** 23280 * Called when a view has been clicked. 23281 * 23282 * @param v The view that was clicked. 23283 */ 23284 void onClick(View v); 23285 } 23286 23287 /** 23288 * Interface definition for a callback to be invoked when a view is context clicked. 23289 */ 23290 public interface OnContextClickListener { 23291 /** 23292 * Called when a view is context clicked. 23293 * 23294 * @param v The view that has been context clicked. 23295 * @return true if the callback consumed the context click, false otherwise. 23296 */ 23297 boolean onContextClick(View v); 23298 } 23299 23300 /** 23301 * Interface definition for a callback to be invoked when the context menu 23302 * for this view is being built. 23303 */ 23304 public interface OnCreateContextMenuListener { 23305 /** 23306 * Called when the context menu for this view is being built. It is not 23307 * safe to hold onto the menu after this method returns. 23308 * 23309 * @param menu The context menu that is being built 23310 * @param v The view for which the context menu is being built 23311 * @param menuInfo Extra information about the item for which the 23312 * context menu should be shown. This information will vary 23313 * depending on the class of v. 23314 */ 23315 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 23316 } 23317 23318 /** 23319 * Interface definition for a callback to be invoked when the status bar changes 23320 * visibility. This reports <strong>global</strong> changes to the system UI 23321 * state, not what the application is requesting. 23322 * 23323 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 23324 */ 23325 public interface OnSystemUiVisibilityChangeListener { 23326 /** 23327 * Called when the status bar changes visibility because of a call to 23328 * {@link View#setSystemUiVisibility(int)}. 23329 * 23330 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 23331 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 23332 * This tells you the <strong>global</strong> state of these UI visibility 23333 * flags, not what your app is currently applying. 23334 */ 23335 public void onSystemUiVisibilityChange(int visibility); 23336 } 23337 23338 /** 23339 * Interface definition for a callback to be invoked when this view is attached 23340 * or detached from its window. 23341 */ 23342 public interface OnAttachStateChangeListener { 23343 /** 23344 * Called when the view is attached to a window. 23345 * @param v The view that was attached 23346 */ 23347 public void onViewAttachedToWindow(View v); 23348 /** 23349 * Called when the view is detached from a window. 23350 * @param v The view that was detached 23351 */ 23352 public void onViewDetachedFromWindow(View v); 23353 } 23354 23355 /** 23356 * Listener for applying window insets on a view in a custom way. 23357 * 23358 * <p>Apps may choose to implement this interface if they want to apply custom policy 23359 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 23360 * is set, its 23361 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 23362 * method will be called instead of the View's own 23363 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 23364 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 23365 * the View's normal behavior as part of its own.</p> 23366 */ 23367 public interface OnApplyWindowInsetsListener { 23368 /** 23369 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 23370 * on a View, this listener method will be called instead of the view's own 23371 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 23372 * 23373 * @param v The view applying window insets 23374 * @param insets The insets to apply 23375 * @return The insets supplied, minus any insets that were consumed 23376 */ 23377 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 23378 } 23379 23380 private final class UnsetPressedState implements Runnable { 23381 @Override 23382 public void run() { 23383 setPressed(false); 23384 } 23385 } 23386 23387 /** 23388 * Base class for derived classes that want to save and restore their own 23389 * state in {@link android.view.View#onSaveInstanceState()}. 23390 */ 23391 public static class BaseSavedState extends AbsSavedState { 23392 String mStartActivityRequestWhoSaved; 23393 23394 /** 23395 * Constructor used when reading from a parcel. Reads the state of the superclass. 23396 * 23397 * @param source parcel to read from 23398 */ 23399 public BaseSavedState(Parcel source) { 23400 this(source, null); 23401 } 23402 23403 /** 23404 * Constructor used when reading from a parcel using a given class loader. 23405 * Reads the state of the superclass. 23406 * 23407 * @param source parcel to read from 23408 * @param loader ClassLoader to use for reading 23409 */ 23410 public BaseSavedState(Parcel source, ClassLoader loader) { 23411 super(source, loader); 23412 mStartActivityRequestWhoSaved = source.readString(); 23413 } 23414 23415 /** 23416 * Constructor called by derived classes when creating their SavedState objects 23417 * 23418 * @param superState The state of the superclass of this view 23419 */ 23420 public BaseSavedState(Parcelable superState) { 23421 super(superState); 23422 } 23423 23424 @Override 23425 public void writeToParcel(Parcel out, int flags) { 23426 super.writeToParcel(out, flags); 23427 out.writeString(mStartActivityRequestWhoSaved); 23428 } 23429 23430 public static final Parcelable.Creator<BaseSavedState> CREATOR 23431 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 23432 @Override 23433 public BaseSavedState createFromParcel(Parcel in) { 23434 return new BaseSavedState(in); 23435 } 23436 23437 @Override 23438 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 23439 return new BaseSavedState(in, loader); 23440 } 23441 23442 @Override 23443 public BaseSavedState[] newArray(int size) { 23444 return new BaseSavedState[size]; 23445 } 23446 }; 23447 } 23448 23449 /** 23450 * A set of information given to a view when it is attached to its parent 23451 * window. 23452 */ 23453 final static class AttachInfo { 23454 interface Callbacks { 23455 void playSoundEffect(int effectId); 23456 boolean performHapticFeedback(int effectId, boolean always); 23457 } 23458 23459 /** 23460 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 23461 * to a Handler. This class contains the target (View) to invalidate and 23462 * the coordinates of the dirty rectangle. 23463 * 23464 * For performance purposes, this class also implements a pool of up to 23465 * POOL_LIMIT objects that get reused. This reduces memory allocations 23466 * whenever possible. 23467 */ 23468 static class InvalidateInfo { 23469 private static final int POOL_LIMIT = 10; 23470 23471 private static final SynchronizedPool<InvalidateInfo> sPool = 23472 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 23473 23474 View target; 23475 23476 int left; 23477 int top; 23478 int right; 23479 int bottom; 23480 23481 public static InvalidateInfo obtain() { 23482 InvalidateInfo instance = sPool.acquire(); 23483 return (instance != null) ? instance : new InvalidateInfo(); 23484 } 23485 23486 public void recycle() { 23487 target = null; 23488 sPool.release(this); 23489 } 23490 } 23491 23492 final IWindowSession mSession; 23493 23494 final IWindow mWindow; 23495 23496 final IBinder mWindowToken; 23497 23498 final Display mDisplay; 23499 23500 final Callbacks mRootCallbacks; 23501 23502 IWindowId mIWindowId; 23503 WindowId mWindowId; 23504 23505 /** 23506 * The top view of the hierarchy. 23507 */ 23508 View mRootView; 23509 23510 IBinder mPanelParentWindowToken; 23511 23512 boolean mHardwareAccelerated; 23513 boolean mHardwareAccelerationRequested; 23514 ThreadedRenderer mThreadedRenderer; 23515 List<RenderNode> mPendingAnimatingRenderNodes; 23516 23517 /** 23518 * The state of the display to which the window is attached, as reported 23519 * by {@link Display#getState()}. Note that the display state constants 23520 * declared by {@link Display} do not exactly line up with the screen state 23521 * constants declared by {@link View} (there are more display states than 23522 * screen states). 23523 */ 23524 int mDisplayState = Display.STATE_UNKNOWN; 23525 23526 /** 23527 * Scale factor used by the compatibility mode 23528 */ 23529 float mApplicationScale; 23530 23531 /** 23532 * Indicates whether the application is in compatibility mode 23533 */ 23534 boolean mScalingRequired; 23535 23536 /** 23537 * Left position of this view's window 23538 */ 23539 int mWindowLeft; 23540 23541 /** 23542 * Top position of this view's window 23543 */ 23544 int mWindowTop; 23545 23546 /** 23547 * Indicates whether views need to use 32-bit drawing caches 23548 */ 23549 boolean mUse32BitDrawingCache; 23550 23551 /** 23552 * For windows that are full-screen but using insets to layout inside 23553 * of the screen areas, these are the current insets to appear inside 23554 * the overscan area of the display. 23555 */ 23556 final Rect mOverscanInsets = new Rect(); 23557 23558 /** 23559 * For windows that are full-screen but using insets to layout inside 23560 * of the screen decorations, these are the current insets for the 23561 * content of the window. 23562 */ 23563 final Rect mContentInsets = new Rect(); 23564 23565 /** 23566 * For windows that are full-screen but using insets to layout inside 23567 * of the screen decorations, these are the current insets for the 23568 * actual visible parts of the window. 23569 */ 23570 final Rect mVisibleInsets = new Rect(); 23571 23572 /** 23573 * For windows that are full-screen but using insets to layout inside 23574 * of the screen decorations, these are the current insets for the 23575 * stable system windows. 23576 */ 23577 final Rect mStableInsets = new Rect(); 23578 23579 /** 23580 * For windows that include areas that are not covered by real surface these are the outsets 23581 * for real surface. 23582 */ 23583 final Rect mOutsets = new Rect(); 23584 23585 /** 23586 * In multi-window we force show the navigation bar. Because we don't want that the surface 23587 * size changes in this mode, we instead have a flag whether the navigation bar size should 23588 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 23589 */ 23590 boolean mAlwaysConsumeNavBar; 23591 23592 /** 23593 * The internal insets given by this window. This value is 23594 * supplied by the client (through 23595 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 23596 * be given to the window manager when changed to be used in laying 23597 * out windows behind it. 23598 */ 23599 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 23600 = new ViewTreeObserver.InternalInsetsInfo(); 23601 23602 /** 23603 * Set to true when mGivenInternalInsets is non-empty. 23604 */ 23605 boolean mHasNonEmptyGivenInternalInsets; 23606 23607 /** 23608 * All views in the window's hierarchy that serve as scroll containers, 23609 * used to determine if the window can be resized or must be panned 23610 * to adjust for a soft input area. 23611 */ 23612 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 23613 23614 final KeyEvent.DispatcherState mKeyDispatchState 23615 = new KeyEvent.DispatcherState(); 23616 23617 /** 23618 * Indicates whether the view's window currently has the focus. 23619 */ 23620 boolean mHasWindowFocus; 23621 23622 /** 23623 * The current visibility of the window. 23624 */ 23625 int mWindowVisibility; 23626 23627 /** 23628 * Indicates the time at which drawing started to occur. 23629 */ 23630 long mDrawingTime; 23631 23632 /** 23633 * Indicates whether or not ignoring the DIRTY_MASK flags. 23634 */ 23635 boolean mIgnoreDirtyState; 23636 23637 /** 23638 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 23639 * to avoid clearing that flag prematurely. 23640 */ 23641 boolean mSetIgnoreDirtyState = false; 23642 23643 /** 23644 * Indicates whether the view's window is currently in touch mode. 23645 */ 23646 boolean mInTouchMode; 23647 23648 /** 23649 * Indicates whether the view has requested unbuffered input dispatching for the current 23650 * event stream. 23651 */ 23652 boolean mUnbufferedDispatchRequested; 23653 23654 /** 23655 * Indicates that ViewAncestor should trigger a global layout change 23656 * the next time it performs a traversal 23657 */ 23658 boolean mRecomputeGlobalAttributes; 23659 23660 /** 23661 * Always report new attributes at next traversal. 23662 */ 23663 boolean mForceReportNewAttributes; 23664 23665 /** 23666 * Set during a traveral if any views want to keep the screen on. 23667 */ 23668 boolean mKeepScreenOn; 23669 23670 /** 23671 * Set during a traveral if the light center needs to be updated. 23672 */ 23673 boolean mNeedsUpdateLightCenter; 23674 23675 /** 23676 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 23677 */ 23678 int mSystemUiVisibility; 23679 23680 /** 23681 * Hack to force certain system UI visibility flags to be cleared. 23682 */ 23683 int mDisabledSystemUiVisibility; 23684 23685 /** 23686 * Last global system UI visibility reported by the window manager. 23687 */ 23688 int mGlobalSystemUiVisibility = -1; 23689 23690 /** 23691 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 23692 * attached. 23693 */ 23694 boolean mHasSystemUiListeners; 23695 23696 /** 23697 * Set if the window has requested to extend into the overscan region 23698 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 23699 */ 23700 boolean mOverscanRequested; 23701 23702 /** 23703 * Set if the visibility of any views has changed. 23704 */ 23705 boolean mViewVisibilityChanged; 23706 23707 /** 23708 * Set to true if a view has been scrolled. 23709 */ 23710 boolean mViewScrollChanged; 23711 23712 /** 23713 * Set to true if high contrast mode enabled 23714 */ 23715 boolean mHighContrastText; 23716 23717 /** 23718 * Set to true if a pointer event is currently being handled. 23719 */ 23720 boolean mHandlingPointerEvent; 23721 23722 /** 23723 * Global to the view hierarchy used as a temporary for dealing with 23724 * x/y points in the transparent region computations. 23725 */ 23726 final int[] mTransparentLocation = new int[2]; 23727 23728 /** 23729 * Global to the view hierarchy used as a temporary for dealing with 23730 * x/y points in the ViewGroup.invalidateChild implementation. 23731 */ 23732 final int[] mInvalidateChildLocation = new int[2]; 23733 23734 /** 23735 * Global to the view hierarchy used as a temporary for dealing with 23736 * computing absolute on-screen location. 23737 */ 23738 final int[] mTmpLocation = new int[2]; 23739 23740 /** 23741 * Global to the view hierarchy used as a temporary for dealing with 23742 * x/y location when view is transformed. 23743 */ 23744 final float[] mTmpTransformLocation = new float[2]; 23745 23746 /** 23747 * The view tree observer used to dispatch global events like 23748 * layout, pre-draw, touch mode change, etc. 23749 */ 23750 final ViewTreeObserver mTreeObserver; 23751 23752 /** 23753 * A Canvas used by the view hierarchy to perform bitmap caching. 23754 */ 23755 Canvas mCanvas; 23756 23757 /** 23758 * The view root impl. 23759 */ 23760 final ViewRootImpl mViewRootImpl; 23761 23762 /** 23763 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 23764 * handler can be used to pump events in the UI events queue. 23765 */ 23766 final Handler mHandler; 23767 23768 /** 23769 * Temporary for use in computing invalidate rectangles while 23770 * calling up the hierarchy. 23771 */ 23772 final Rect mTmpInvalRect = new Rect(); 23773 23774 /** 23775 * Temporary for use in computing hit areas with transformed views 23776 */ 23777 final RectF mTmpTransformRect = new RectF(); 23778 23779 /** 23780 * Temporary for use in computing hit areas with transformed views 23781 */ 23782 final RectF mTmpTransformRect1 = new RectF(); 23783 23784 /** 23785 * Temporary list of rectanges. 23786 */ 23787 final List<RectF> mTmpRectList = new ArrayList<>(); 23788 23789 /** 23790 * Temporary for use in transforming invalidation rect 23791 */ 23792 final Matrix mTmpMatrix = new Matrix(); 23793 23794 /** 23795 * Temporary for use in transforming invalidation rect 23796 */ 23797 final Transformation mTmpTransformation = new Transformation(); 23798 23799 /** 23800 * Temporary for use in querying outlines from OutlineProviders 23801 */ 23802 final Outline mTmpOutline = new Outline(); 23803 23804 /** 23805 * Temporary list for use in collecting focusable descendents of a view. 23806 */ 23807 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 23808 23809 /** 23810 * The id of the window for accessibility purposes. 23811 */ 23812 int mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 23813 23814 /** 23815 * Flags related to accessibility processing. 23816 * 23817 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 23818 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 23819 */ 23820 int mAccessibilityFetchFlags; 23821 23822 /** 23823 * The drawable for highlighting accessibility focus. 23824 */ 23825 Drawable mAccessibilityFocusDrawable; 23826 23827 /** 23828 * Show where the margins, bounds and layout bounds are for each view. 23829 */ 23830 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 23831 23832 /** 23833 * Point used to compute visible regions. 23834 */ 23835 final Point mPoint = new Point(); 23836 23837 /** 23838 * Used to track which View originated a requestLayout() call, used when 23839 * requestLayout() is called during layout. 23840 */ 23841 View mViewRequestingLayout; 23842 23843 /** 23844 * Used to track views that need (at least) a partial relayout at their current size 23845 * during the next traversal. 23846 */ 23847 List<View> mPartialLayoutViews = new ArrayList<>(); 23848 23849 /** 23850 * Swapped with mPartialLayoutViews during layout to avoid concurrent 23851 * modification. Lazily assigned during ViewRootImpl layout. 23852 */ 23853 List<View> mEmptyPartialLayoutViews; 23854 23855 /** 23856 * Used to track the identity of the current drag operation. 23857 */ 23858 IBinder mDragToken; 23859 23860 /** 23861 * The drag shadow surface for the current drag operation. 23862 */ 23863 public Surface mDragSurface; 23864 23865 23866 /** 23867 * The view that currently has a tooltip displayed. 23868 */ 23869 View mTooltipHost; 23870 23871 /** 23872 * Creates a new set of attachment information with the specified 23873 * events handler and thread. 23874 * 23875 * @param handler the events handler the view must use 23876 */ 23877 AttachInfo(IWindowSession session, IWindow window, Display display, 23878 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 23879 Context context) { 23880 mSession = session; 23881 mWindow = window; 23882 mWindowToken = window.asBinder(); 23883 mDisplay = display; 23884 mViewRootImpl = viewRootImpl; 23885 mHandler = handler; 23886 mRootCallbacks = effectPlayer; 23887 mTreeObserver = new ViewTreeObserver(context); 23888 } 23889 } 23890 23891 /** 23892 * <p>ScrollabilityCache holds various fields used by a View when scrolling 23893 * is supported. This avoids keeping too many unused fields in most 23894 * instances of View.</p> 23895 */ 23896 private static class ScrollabilityCache implements Runnable { 23897 23898 /** 23899 * Scrollbars are not visible 23900 */ 23901 public static final int OFF = 0; 23902 23903 /** 23904 * Scrollbars are visible 23905 */ 23906 public static final int ON = 1; 23907 23908 /** 23909 * Scrollbars are fading away 23910 */ 23911 public static final int FADING = 2; 23912 23913 public boolean fadeScrollBars; 23914 23915 public int fadingEdgeLength; 23916 public int scrollBarDefaultDelayBeforeFade; 23917 public int scrollBarFadeDuration; 23918 23919 public int scrollBarSize; 23920 public ScrollBarDrawable scrollBar; 23921 public float[] interpolatorValues; 23922 public View host; 23923 23924 public final Paint paint; 23925 public final Matrix matrix; 23926 public Shader shader; 23927 23928 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 23929 23930 private static final float[] OPAQUE = { 255 }; 23931 private static final float[] TRANSPARENT = { 0.0f }; 23932 23933 /** 23934 * When fading should start. This time moves into the future every time 23935 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 23936 */ 23937 public long fadeStartTime; 23938 23939 23940 /** 23941 * The current state of the scrollbars: ON, OFF, or FADING 23942 */ 23943 public int state = OFF; 23944 23945 private int mLastColor; 23946 23947 public final Rect mScrollBarBounds = new Rect(); 23948 23949 public static final int NOT_DRAGGING = 0; 23950 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 23951 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 23952 public int mScrollBarDraggingState = NOT_DRAGGING; 23953 23954 public float mScrollBarDraggingPos = 0; 23955 23956 public ScrollabilityCache(ViewConfiguration configuration, View host) { 23957 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 23958 scrollBarSize = configuration.getScaledScrollBarSize(); 23959 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 23960 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 23961 23962 paint = new Paint(); 23963 matrix = new Matrix(); 23964 // use use a height of 1, and then wack the matrix each time we 23965 // actually use it. 23966 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 23967 paint.setShader(shader); 23968 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 23969 23970 this.host = host; 23971 } 23972 23973 public void setFadeColor(int color) { 23974 if (color != mLastColor) { 23975 mLastColor = color; 23976 23977 if (color != 0) { 23978 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 23979 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 23980 paint.setShader(shader); 23981 // Restore the default transfer mode (src_over) 23982 paint.setXfermode(null); 23983 } else { 23984 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 23985 paint.setShader(shader); 23986 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 23987 } 23988 } 23989 } 23990 23991 public void run() { 23992 long now = AnimationUtils.currentAnimationTimeMillis(); 23993 if (now >= fadeStartTime) { 23994 23995 // the animation fades the scrollbars out by changing 23996 // the opacity (alpha) from fully opaque to fully 23997 // transparent 23998 int nextFrame = (int) now; 23999 int framesCount = 0; 24000 24001 Interpolator interpolator = scrollBarInterpolator; 24002 24003 // Start opaque 24004 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 24005 24006 // End transparent 24007 nextFrame += scrollBarFadeDuration; 24008 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 24009 24010 state = FADING; 24011 24012 // Kick off the fade animation 24013 host.invalidate(true); 24014 } 24015 } 24016 } 24017 24018 /** 24019 * Resuable callback for sending 24020 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 24021 */ 24022 private class SendViewScrolledAccessibilityEvent implements Runnable { 24023 public volatile boolean mIsPending; 24024 24025 public void run() { 24026 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 24027 mIsPending = false; 24028 } 24029 } 24030 24031 /** 24032 * <p> 24033 * This class represents a delegate that can be registered in a {@link View} 24034 * to enhance accessibility support via composition rather via inheritance. 24035 * It is specifically targeted to widget developers that extend basic View 24036 * classes i.e. classes in package android.view, that would like their 24037 * applications to be backwards compatible. 24038 * </p> 24039 * <div class="special reference"> 24040 * <h3>Developer Guides</h3> 24041 * <p>For more information about making applications accessible, read the 24042 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 24043 * developer guide.</p> 24044 * </div> 24045 * <p> 24046 * A scenario in which a developer would like to use an accessibility delegate 24047 * is overriding a method introduced in a later API version than the minimal API 24048 * version supported by the application. For example, the method 24049 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 24050 * in API version 4 when the accessibility APIs were first introduced. If a 24051 * developer would like his application to run on API version 4 devices (assuming 24052 * all other APIs used by the application are version 4 or lower) and take advantage 24053 * of this method, instead of overriding the method which would break the application's 24054 * backwards compatibility, he can override the corresponding method in this 24055 * delegate and register the delegate in the target View if the API version of 24056 * the system is high enough, i.e. the API version is the same as or higher than the API 24057 * version that introduced 24058 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 24059 * </p> 24060 * <p> 24061 * Here is an example implementation: 24062 * </p> 24063 * <code><pre><p> 24064 * if (Build.VERSION.SDK_INT >= 14) { 24065 * // If the API version is equal of higher than the version in 24066 * // which onInitializeAccessibilityNodeInfo was introduced we 24067 * // register a delegate with a customized implementation. 24068 * View view = findViewById(R.id.view_id); 24069 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 24070 * public void onInitializeAccessibilityNodeInfo(View host, 24071 * AccessibilityNodeInfo info) { 24072 * // Let the default implementation populate the info. 24073 * super.onInitializeAccessibilityNodeInfo(host, info); 24074 * // Set some other information. 24075 * info.setEnabled(host.isEnabled()); 24076 * } 24077 * }); 24078 * } 24079 * </code></pre></p> 24080 * <p> 24081 * This delegate contains methods that correspond to the accessibility methods 24082 * in View. If a delegate has been specified the implementation in View hands 24083 * off handling to the corresponding method in this delegate. The default 24084 * implementation the delegate methods behaves exactly as the corresponding 24085 * method in View for the case of no accessibility delegate been set. Hence, 24086 * to customize the behavior of a View method, clients can override only the 24087 * corresponding delegate method without altering the behavior of the rest 24088 * accessibility related methods of the host view. 24089 * </p> 24090 * <p> 24091 * <strong>Note:</strong> On platform versions prior to 24092 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 24093 * views in the {@code android.widget.*} package are called <i>before</i> 24094 * host methods. This prevents certain properties such as class name from 24095 * being modified by overriding 24096 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 24097 * as any changes will be overwritten by the host class. 24098 * <p> 24099 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 24100 * methods are called <i>after</i> host methods, which all properties to be 24101 * modified without being overwritten by the host class. 24102 */ 24103 public static class AccessibilityDelegate { 24104 24105 /** 24106 * Sends an accessibility event of the given type. If accessibility is not 24107 * enabled this method has no effect. 24108 * <p> 24109 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 24110 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 24111 * been set. 24112 * </p> 24113 * 24114 * @param host The View hosting the delegate. 24115 * @param eventType The type of the event to send. 24116 * 24117 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 24118 */ 24119 public void sendAccessibilityEvent(View host, int eventType) { 24120 host.sendAccessibilityEventInternal(eventType); 24121 } 24122 24123 /** 24124 * Performs the specified accessibility action on the view. For 24125 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 24126 * <p> 24127 * The default implementation behaves as 24128 * {@link View#performAccessibilityAction(int, Bundle) 24129 * View#performAccessibilityAction(int, Bundle)} for the case of 24130 * no accessibility delegate been set. 24131 * </p> 24132 * 24133 * @param action The action to perform. 24134 * @return Whether the action was performed. 24135 * 24136 * @see View#performAccessibilityAction(int, Bundle) 24137 * View#performAccessibilityAction(int, Bundle) 24138 */ 24139 public boolean performAccessibilityAction(View host, int action, Bundle args) { 24140 return host.performAccessibilityActionInternal(action, args); 24141 } 24142 24143 /** 24144 * Sends an accessibility event. This method behaves exactly as 24145 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 24146 * empty {@link AccessibilityEvent} and does not perform a check whether 24147 * accessibility is enabled. 24148 * <p> 24149 * The default implementation behaves as 24150 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24151 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 24152 * the case of no accessibility delegate been set. 24153 * </p> 24154 * 24155 * @param host The View hosting the delegate. 24156 * @param event The event to send. 24157 * 24158 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24159 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24160 */ 24161 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 24162 host.sendAccessibilityEventUncheckedInternal(event); 24163 } 24164 24165 /** 24166 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 24167 * to its children for adding their text content to the event. 24168 * <p> 24169 * The default implementation behaves as 24170 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24171 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 24172 * the case of no accessibility delegate been set. 24173 * </p> 24174 * 24175 * @param host The View hosting the delegate. 24176 * @param event The event. 24177 * @return True if the event population was completed. 24178 * 24179 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24180 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24181 */ 24182 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 24183 return host.dispatchPopulateAccessibilityEventInternal(event); 24184 } 24185 24186 /** 24187 * Gives a chance to the host View to populate the accessibility event with its 24188 * text content. 24189 * <p> 24190 * The default implementation behaves as 24191 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 24192 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 24193 * the case of no accessibility delegate been set. 24194 * </p> 24195 * 24196 * @param host The View hosting the delegate. 24197 * @param event The accessibility event which to populate. 24198 * 24199 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 24200 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 24201 */ 24202 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 24203 host.onPopulateAccessibilityEventInternal(event); 24204 } 24205 24206 /** 24207 * Initializes an {@link AccessibilityEvent} with information about the 24208 * the host View which is the event source. 24209 * <p> 24210 * The default implementation behaves as 24211 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 24212 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 24213 * the case of no accessibility delegate been set. 24214 * </p> 24215 * 24216 * @param host The View hosting the delegate. 24217 * @param event The event to initialize. 24218 * 24219 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 24220 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 24221 */ 24222 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 24223 host.onInitializeAccessibilityEventInternal(event); 24224 } 24225 24226 /** 24227 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 24228 * <p> 24229 * The default implementation behaves as 24230 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24231 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 24232 * the case of no accessibility delegate been set. 24233 * </p> 24234 * 24235 * @param host The View hosting the delegate. 24236 * @param info The instance to initialize. 24237 * 24238 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24239 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24240 */ 24241 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 24242 host.onInitializeAccessibilityNodeInfoInternal(info); 24243 } 24244 24245 /** 24246 * Called when a child of the host View has requested sending an 24247 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 24248 * to augment the event. 24249 * <p> 24250 * The default implementation behaves as 24251 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24252 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 24253 * the case of no accessibility delegate been set. 24254 * </p> 24255 * 24256 * @param host The View hosting the delegate. 24257 * @param child The child which requests sending the event. 24258 * @param event The event to be sent. 24259 * @return True if the event should be sent 24260 * 24261 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24262 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24263 */ 24264 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 24265 AccessibilityEvent event) { 24266 return host.onRequestSendAccessibilityEventInternal(child, event); 24267 } 24268 24269 /** 24270 * Gets the provider for managing a virtual view hierarchy rooted at this View 24271 * and reported to {@link android.accessibilityservice.AccessibilityService}s 24272 * that explore the window content. 24273 * <p> 24274 * The default implementation behaves as 24275 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 24276 * the case of no accessibility delegate been set. 24277 * </p> 24278 * 24279 * @return The provider. 24280 * 24281 * @see AccessibilityNodeProvider 24282 */ 24283 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 24284 return null; 24285 } 24286 24287 /** 24288 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 24289 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 24290 * This method is responsible for obtaining an accessibility node info from a 24291 * pool of reusable instances and calling 24292 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 24293 * view to initialize the former. 24294 * <p> 24295 * <strong>Note:</strong> The client is responsible for recycling the obtained 24296 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 24297 * creation. 24298 * </p> 24299 * <p> 24300 * The default implementation behaves as 24301 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 24302 * the case of no accessibility delegate been set. 24303 * </p> 24304 * @return A populated {@link AccessibilityNodeInfo}. 24305 * 24306 * @see AccessibilityNodeInfo 24307 * 24308 * @hide 24309 */ 24310 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 24311 return host.createAccessibilityNodeInfoInternal(); 24312 } 24313 } 24314 24315 private class MatchIdPredicate implements Predicate<View> { 24316 public int mId; 24317 24318 @Override 24319 public boolean apply(View view) { 24320 return (view.mID == mId); 24321 } 24322 } 24323 24324 private class MatchLabelForPredicate implements Predicate<View> { 24325 private int mLabeledId; 24326 24327 @Override 24328 public boolean apply(View view) { 24329 return (view.mLabelForId == mLabeledId); 24330 } 24331 } 24332 24333 private class SendViewStateChangedAccessibilityEvent implements Runnable { 24334 private int mChangeTypes = 0; 24335 private boolean mPosted; 24336 private boolean mPostedWithDelay; 24337 private long mLastEventTimeMillis; 24338 24339 @Override 24340 public void run() { 24341 mPosted = false; 24342 mPostedWithDelay = false; 24343 mLastEventTimeMillis = SystemClock.uptimeMillis(); 24344 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 24345 final AccessibilityEvent event = AccessibilityEvent.obtain(); 24346 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 24347 event.setContentChangeTypes(mChangeTypes); 24348 sendAccessibilityEventUnchecked(event); 24349 } 24350 mChangeTypes = 0; 24351 } 24352 24353 public void runOrPost(int changeType) { 24354 mChangeTypes |= changeType; 24355 24356 // If this is a live region or the child of a live region, collect 24357 // all events from this frame and send them on the next frame. 24358 if (inLiveRegion()) { 24359 // If we're already posted with a delay, remove that. 24360 if (mPostedWithDelay) { 24361 removeCallbacks(this); 24362 mPostedWithDelay = false; 24363 } 24364 // Only post if we're not already posted. 24365 if (!mPosted) { 24366 post(this); 24367 mPosted = true; 24368 } 24369 return; 24370 } 24371 24372 if (mPosted) { 24373 return; 24374 } 24375 24376 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 24377 final long minEventIntevalMillis = 24378 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 24379 if (timeSinceLastMillis >= minEventIntevalMillis) { 24380 removeCallbacks(this); 24381 run(); 24382 } else { 24383 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 24384 mPostedWithDelay = true; 24385 } 24386 } 24387 } 24388 24389 private boolean inLiveRegion() { 24390 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24391 return true; 24392 } 24393 24394 ViewParent parent = getParent(); 24395 while (parent instanceof View) { 24396 if (((View) parent).getAccessibilityLiveRegion() 24397 != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24398 return true; 24399 } 24400 parent = parent.getParent(); 24401 } 24402 24403 return false; 24404 } 24405 24406 /** 24407 * Dump all private flags in readable format, useful for documentation and 24408 * sanity checking. 24409 */ 24410 private static void dumpFlags() { 24411 final HashMap<String, String> found = Maps.newHashMap(); 24412 try { 24413 for (Field field : View.class.getDeclaredFields()) { 24414 final int modifiers = field.getModifiers(); 24415 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 24416 if (field.getType().equals(int.class)) { 24417 final int value = field.getInt(null); 24418 dumpFlag(found, field.getName(), value); 24419 } else if (field.getType().equals(int[].class)) { 24420 final int[] values = (int[]) field.get(null); 24421 for (int i = 0; i < values.length; i++) { 24422 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 24423 } 24424 } 24425 } 24426 } 24427 } catch (IllegalAccessException e) { 24428 throw new RuntimeException(e); 24429 } 24430 24431 final ArrayList<String> keys = Lists.newArrayList(); 24432 keys.addAll(found.keySet()); 24433 Collections.sort(keys); 24434 for (String key : keys) { 24435 Log.d(VIEW_LOG_TAG, found.get(key)); 24436 } 24437 } 24438 24439 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 24440 // Sort flags by prefix, then by bits, always keeping unique keys 24441 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 24442 final int prefix = name.indexOf('_'); 24443 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 24444 final String output = bits + " " + name; 24445 found.put(key, output); 24446 } 24447 24448 /** {@hide} */ 24449 public void encode(@NonNull ViewHierarchyEncoder stream) { 24450 stream.beginObject(this); 24451 encodeProperties(stream); 24452 stream.endObject(); 24453 } 24454 24455 /** {@hide} */ 24456 @CallSuper 24457 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 24458 Object resolveId = ViewDebug.resolveId(getContext(), mID); 24459 if (resolveId instanceof String) { 24460 stream.addProperty("id", (String) resolveId); 24461 } else { 24462 stream.addProperty("id", mID); 24463 } 24464 24465 stream.addProperty("misc:transformation.alpha", 24466 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 24467 stream.addProperty("misc:transitionName", getTransitionName()); 24468 24469 // layout 24470 stream.addProperty("layout:left", mLeft); 24471 stream.addProperty("layout:right", mRight); 24472 stream.addProperty("layout:top", mTop); 24473 stream.addProperty("layout:bottom", mBottom); 24474 stream.addProperty("layout:width", getWidth()); 24475 stream.addProperty("layout:height", getHeight()); 24476 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 24477 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 24478 stream.addProperty("layout:hasTransientState", hasTransientState()); 24479 stream.addProperty("layout:baseline", getBaseline()); 24480 24481 // layout params 24482 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 24483 if (layoutParams != null) { 24484 stream.addPropertyKey("layoutParams"); 24485 layoutParams.encode(stream); 24486 } 24487 24488 // scrolling 24489 stream.addProperty("scrolling:scrollX", mScrollX); 24490 stream.addProperty("scrolling:scrollY", mScrollY); 24491 24492 // padding 24493 stream.addProperty("padding:paddingLeft", mPaddingLeft); 24494 stream.addProperty("padding:paddingRight", mPaddingRight); 24495 stream.addProperty("padding:paddingTop", mPaddingTop); 24496 stream.addProperty("padding:paddingBottom", mPaddingBottom); 24497 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 24498 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 24499 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 24500 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 24501 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 24502 24503 // measurement 24504 stream.addProperty("measurement:minHeight", mMinHeight); 24505 stream.addProperty("measurement:minWidth", mMinWidth); 24506 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 24507 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 24508 24509 // drawing 24510 stream.addProperty("drawing:elevation", getElevation()); 24511 stream.addProperty("drawing:translationX", getTranslationX()); 24512 stream.addProperty("drawing:translationY", getTranslationY()); 24513 stream.addProperty("drawing:translationZ", getTranslationZ()); 24514 stream.addProperty("drawing:rotation", getRotation()); 24515 stream.addProperty("drawing:rotationX", getRotationX()); 24516 stream.addProperty("drawing:rotationY", getRotationY()); 24517 stream.addProperty("drawing:scaleX", getScaleX()); 24518 stream.addProperty("drawing:scaleY", getScaleY()); 24519 stream.addProperty("drawing:pivotX", getPivotX()); 24520 stream.addProperty("drawing:pivotY", getPivotY()); 24521 stream.addProperty("drawing:opaque", isOpaque()); 24522 stream.addProperty("drawing:alpha", getAlpha()); 24523 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 24524 stream.addProperty("drawing:shadow", hasShadow()); 24525 stream.addProperty("drawing:solidColor", getSolidColor()); 24526 stream.addProperty("drawing:layerType", mLayerType); 24527 stream.addProperty("drawing:willNotDraw", willNotDraw()); 24528 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 24529 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 24530 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 24531 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 24532 24533 // focus 24534 stream.addProperty("focus:hasFocus", hasFocus()); 24535 stream.addProperty("focus:isFocused", isFocused()); 24536 stream.addProperty("focus:isFocusable", isFocusable()); 24537 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 24538 24539 stream.addProperty("misc:clickable", isClickable()); 24540 stream.addProperty("misc:pressed", isPressed()); 24541 stream.addProperty("misc:selected", isSelected()); 24542 stream.addProperty("misc:touchMode", isInTouchMode()); 24543 stream.addProperty("misc:hovered", isHovered()); 24544 stream.addProperty("misc:activated", isActivated()); 24545 24546 stream.addProperty("misc:visibility", getVisibility()); 24547 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 24548 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 24549 24550 stream.addProperty("misc:enabled", isEnabled()); 24551 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 24552 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 24553 24554 // theme attributes 24555 Resources.Theme theme = getContext().getTheme(); 24556 if (theme != null) { 24557 stream.addPropertyKey("theme"); 24558 theme.encode(stream); 24559 } 24560 24561 // view attribute information 24562 int n = mAttributes != null ? mAttributes.length : 0; 24563 stream.addProperty("meta:__attrCount__", n/2); 24564 for (int i = 0; i < n; i += 2) { 24565 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 24566 } 24567 24568 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 24569 24570 // text 24571 stream.addProperty("text:textDirection", getTextDirection()); 24572 stream.addProperty("text:textAlignment", getTextAlignment()); 24573 24574 // accessibility 24575 CharSequence contentDescription = getContentDescription(); 24576 stream.addProperty("accessibility:contentDescription", 24577 contentDescription == null ? "" : contentDescription.toString()); 24578 stream.addProperty("accessibility:labelFor", getLabelFor()); 24579 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 24580 } 24581 24582 /** 24583 * Determine if this view is rendered on a round wearable device and is the main view 24584 * on the screen. 24585 */ 24586 private boolean shouldDrawRoundScrollbar() { 24587 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 24588 return false; 24589 } 24590 24591 final View rootView = getRootView(); 24592 final WindowInsets insets = getRootWindowInsets(); 24593 24594 int height = getHeight(); 24595 int width = getWidth(); 24596 int displayHeight = rootView.getHeight(); 24597 int displayWidth = rootView.getWidth(); 24598 24599 if (height != displayHeight || width != displayWidth) { 24600 return false; 24601 } 24602 24603 getLocationOnScreen(mAttachInfo.mTmpLocation); 24604 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 24605 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 24606 } 24607 24608 /** 24609 * Sets the tooltip text which will be displayed in a small popup next to the view. 24610 * <p> 24611 * The tooltip will be displayed: 24612 * <li>On long click, unless is not handled otherwise (by OnLongClickListener or a context 24613 * menu). </li> 24614 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 24615 * 24616 * @param tooltipText the tooltip text, or null if no tooltip is required 24617 */ 24618 public final void setTooltipText(@Nullable CharSequence tooltipText) { 24619 if (TextUtils.isEmpty(tooltipText)) { 24620 setFlags(0, TOOLTIP); 24621 hideTooltip(); 24622 mTooltipInfo = null; 24623 } else { 24624 setFlags(TOOLTIP, TOOLTIP); 24625 if (mTooltipInfo == null) { 24626 mTooltipInfo = new TooltipInfo(); 24627 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 24628 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 24629 } 24630 mTooltipInfo.mTooltipText = tooltipText; 24631 if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) { 24632 mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText); 24633 } 24634 } 24635 } 24636 24637 /** 24638 * To be removed once the support library has stopped using it. 24639 * 24640 * @deprecated use {@link #setTooltipText} instead 24641 */ 24642 @Deprecated 24643 public final void setTooltip(@Nullable CharSequence tooltipText) { 24644 setTooltipText(tooltipText); 24645 } 24646 24647 /** 24648 * Returns the view's tooltip text. 24649 * 24650 * @return the tooltip text 24651 */ 24652 @Nullable 24653 public final CharSequence getTooltipText() { 24654 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 24655 } 24656 24657 /** 24658 * To be removed once the support library has stopped using it. 24659 * 24660 * @deprecated use {@link #getTooltipText} instead 24661 */ 24662 @Deprecated 24663 @Nullable 24664 public final CharSequence getTooltip() { 24665 return getTooltipText(); 24666 } 24667 24668 private boolean showTooltip(int x, int y, boolean fromLongClick) { 24669 if (mAttachInfo == null) { 24670 return false; 24671 } 24672 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 24673 return false; 24674 } 24675 final CharSequence tooltipText = getTooltipText(); 24676 if (TextUtils.isEmpty(tooltipText)) { 24677 return false; 24678 } 24679 hideTooltip(); 24680 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 24681 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 24682 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 24683 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, tooltipText); 24684 mAttachInfo.mTooltipHost = this; 24685 return true; 24686 } 24687 24688 void hideTooltip() { 24689 if (mTooltipInfo == null) { 24690 return; 24691 } 24692 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24693 if (mTooltipInfo.mTooltipPopup == null) { 24694 return; 24695 } 24696 mTooltipInfo.mTooltipPopup.hide(); 24697 mTooltipInfo.mTooltipPopup = null; 24698 mTooltipInfo.mTooltipFromLongClick = false; 24699 if (mAttachInfo != null) { 24700 mAttachInfo.mTooltipHost = null; 24701 } 24702 } 24703 24704 private boolean showLongClickTooltip(int x, int y) { 24705 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24706 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24707 return showTooltip(x, y, true); 24708 } 24709 24710 private void showHoverTooltip() { 24711 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 24712 } 24713 24714 boolean dispatchTooltipHoverEvent(MotionEvent event) { 24715 if (mTooltipInfo == null) { 24716 return false; 24717 } 24718 switch(event.getAction()) { 24719 case MotionEvent.ACTION_HOVER_MOVE: 24720 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 24721 break; 24722 } 24723 if (!mTooltipInfo.mTooltipFromLongClick) { 24724 if (mTooltipInfo.mTooltipPopup == null) { 24725 // Schedule showing the tooltip after a timeout. 24726 mTooltipInfo.mAnchorX = (int) event.getX(); 24727 mTooltipInfo.mAnchorY = (int) event.getY(); 24728 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24729 postDelayed(mTooltipInfo.mShowTooltipRunnable, 24730 ViewConfiguration.getHoverTooltipShowTimeout()); 24731 } 24732 24733 // Hide hover-triggered tooltip after a period of inactivity. 24734 // Match the timeout used by NativeInputManager to hide the mouse pointer 24735 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 24736 final int timeout; 24737 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 24738 == SYSTEM_UI_FLAG_LOW_PROFILE) { 24739 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 24740 } else { 24741 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 24742 } 24743 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24744 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 24745 } 24746 return true; 24747 24748 case MotionEvent.ACTION_HOVER_EXIT: 24749 if (!mTooltipInfo.mTooltipFromLongClick) { 24750 hideTooltip(); 24751 } 24752 break; 24753 } 24754 return false; 24755 } 24756 24757 void handleTooltipKey(KeyEvent event) { 24758 switch (event.getAction()) { 24759 case KeyEvent.ACTION_DOWN: 24760 if (event.getRepeatCount() == 0) { 24761 hideTooltip(); 24762 } 24763 break; 24764 24765 case KeyEvent.ACTION_UP: 24766 handleTooltipUp(); 24767 break; 24768 } 24769 } 24770 24771 private void handleTooltipUp() { 24772 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 24773 return; 24774 } 24775 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24776 postDelayed(mTooltipInfo.mHideTooltipRunnable, 24777 ViewConfiguration.getLongPressTooltipHideTimeout()); 24778 } 24779 24780 private int getFocusableAttribute(TypedArray attributes) { 24781 TypedValue val = new TypedValue(); 24782 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 24783 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 24784 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 24785 } else { 24786 return val.data; 24787 } 24788 } else { 24789 return FOCUSABLE_AUTO; 24790 } 24791 } 24792 24793 /** 24794 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 24795 * is not showing. 24796 * @hide 24797 */ 24798 @TestApi 24799 public View getTooltipView() { 24800 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 24801 return null; 24802 } 24803 return mTooltipInfo.mTooltipPopup.getContentView(); 24804 } 24805} 24806