View.java revision 6a944ca17547e520ed4988125ee4c1f172c87946
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 /** 861 * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when 862 * calling setFlags. 863 */ 864 private static final int NOT_FOCUSABLE = 0x00000000; 865 866 /** 867 * This view wants keystrokes. Use with TAKES_FOCUS_MASK when calling 868 * setFlags. 869 */ 870 private static final int FOCUSABLE = 0x00000001; 871 872 /** 873 * Mask for use with setFlags indicating bits used for focus. 874 */ 875 private static final int FOCUSABLE_MASK = 0x00000001; 876 877 /** 878 * This view will adjust its padding to fit sytem windows (e.g. status bar) 879 */ 880 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 881 882 /** @hide */ 883 @IntDef({VISIBLE, INVISIBLE, GONE}) 884 @Retention(RetentionPolicy.SOURCE) 885 public @interface Visibility {} 886 887 /** 888 * This view is visible. 889 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 890 * android:visibility}. 891 */ 892 public static final int VISIBLE = 0x00000000; 893 894 /** 895 * This view is invisible, but it still takes up space for layout purposes. 896 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 897 * android:visibility}. 898 */ 899 public static final int INVISIBLE = 0x00000004; 900 901 /** 902 * This view is invisible, and it doesn't take any space for layout 903 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 904 * android:visibility}. 905 */ 906 public static final int GONE = 0x00000008; 907 908 /** 909 * Mask for use with setFlags indicating bits used for visibility. 910 * {@hide} 911 */ 912 static final int VISIBILITY_MASK = 0x0000000C; 913 914 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 915 916 /** 917 * This view is enabled. Interpretation varies by subclass. 918 * Use with ENABLED_MASK when calling setFlags. 919 * {@hide} 920 */ 921 static final int ENABLED = 0x00000000; 922 923 /** 924 * This view is disabled. Interpretation varies by subclass. 925 * Use with ENABLED_MASK when calling setFlags. 926 * {@hide} 927 */ 928 static final int DISABLED = 0x00000020; 929 930 /** 931 * Mask for use with setFlags indicating bits used for indicating whether 932 * this view is enabled 933 * {@hide} 934 */ 935 static final int ENABLED_MASK = 0x00000020; 936 937 /** 938 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 939 * called and further optimizations will be performed. It is okay to have 940 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 941 * {@hide} 942 */ 943 static final int WILL_NOT_DRAW = 0x00000080; 944 945 /** 946 * Mask for use with setFlags indicating bits used for indicating whether 947 * this view is will draw 948 * {@hide} 949 */ 950 static final int DRAW_MASK = 0x00000080; 951 952 /** 953 * <p>This view doesn't show scrollbars.</p> 954 * {@hide} 955 */ 956 static final int SCROLLBARS_NONE = 0x00000000; 957 958 /** 959 * <p>This view shows horizontal scrollbars.</p> 960 * {@hide} 961 */ 962 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 963 964 /** 965 * <p>This view shows vertical scrollbars.</p> 966 * {@hide} 967 */ 968 static final int SCROLLBARS_VERTICAL = 0x00000200; 969 970 /** 971 * <p>Mask for use with setFlags indicating bits used for indicating which 972 * scrollbars are enabled.</p> 973 * {@hide} 974 */ 975 static final int SCROLLBARS_MASK = 0x00000300; 976 977 /** 978 * Indicates that the view should filter touches when its window is obscured. 979 * Refer to the class comments for more information about this security feature. 980 * {@hide} 981 */ 982 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 983 984 /** 985 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 986 * that they are optional and should be skipped if the window has 987 * requested system UI flags that ignore those insets for layout. 988 */ 989 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 990 991 /** 992 * <p>This view doesn't show fading edges.</p> 993 * {@hide} 994 */ 995 static final int FADING_EDGE_NONE = 0x00000000; 996 997 /** 998 * <p>This view shows horizontal fading edges.</p> 999 * {@hide} 1000 */ 1001 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1002 1003 /** 1004 * <p>This view shows vertical fading edges.</p> 1005 * {@hide} 1006 */ 1007 static final int FADING_EDGE_VERTICAL = 0x00002000; 1008 1009 /** 1010 * <p>Mask for use with setFlags indicating bits used for indicating which 1011 * fading edges are enabled.</p> 1012 * {@hide} 1013 */ 1014 static final int FADING_EDGE_MASK = 0x00003000; 1015 1016 /** 1017 * <p>Indicates this view can be clicked. When clickable, a View reacts 1018 * to clicks by notifying the OnClickListener.<p> 1019 * {@hide} 1020 */ 1021 static final int CLICKABLE = 0x00004000; 1022 1023 /** 1024 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1025 * {@hide} 1026 */ 1027 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1028 1029 /** 1030 * <p>Indicates that no icicle should be saved for this view.<p> 1031 * {@hide} 1032 */ 1033 static final int SAVE_DISABLED = 0x000010000; 1034 1035 /** 1036 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1037 * property.</p> 1038 * {@hide} 1039 */ 1040 static final int SAVE_DISABLED_MASK = 0x000010000; 1041 1042 /** 1043 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1044 * {@hide} 1045 */ 1046 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1047 1048 /** 1049 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1050 * {@hide} 1051 */ 1052 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1053 1054 /** @hide */ 1055 @Retention(RetentionPolicy.SOURCE) 1056 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1057 public @interface DrawingCacheQuality {} 1058 1059 /** 1060 * <p>Enables low quality mode for the drawing cache.</p> 1061 */ 1062 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1063 1064 /** 1065 * <p>Enables high quality mode for the drawing cache.</p> 1066 */ 1067 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1068 1069 /** 1070 * <p>Enables automatic quality mode for the drawing cache.</p> 1071 */ 1072 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1073 1074 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1075 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1076 }; 1077 1078 /** 1079 * <p>Mask for use with setFlags indicating bits used for the cache 1080 * quality property.</p> 1081 * {@hide} 1082 */ 1083 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1084 1085 /** 1086 * <p> 1087 * Indicates this view can be long clicked. When long clickable, a View 1088 * reacts to long clicks by notifying the OnLongClickListener or showing a 1089 * context menu. 1090 * </p> 1091 * {@hide} 1092 */ 1093 static final int LONG_CLICKABLE = 0x00200000; 1094 1095 /** 1096 * <p>Indicates that this view gets its drawable states from its direct parent 1097 * and ignores its original internal states.</p> 1098 * 1099 * @hide 1100 */ 1101 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1102 1103 /** 1104 * <p> 1105 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1106 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1107 * OnContextClickListener. 1108 * </p> 1109 * {@hide} 1110 */ 1111 static final int CONTEXT_CLICKABLE = 0x00800000; 1112 1113 1114 /** @hide */ 1115 @IntDef({ 1116 SCROLLBARS_INSIDE_OVERLAY, 1117 SCROLLBARS_INSIDE_INSET, 1118 SCROLLBARS_OUTSIDE_OVERLAY, 1119 SCROLLBARS_OUTSIDE_INSET 1120 }) 1121 @Retention(RetentionPolicy.SOURCE) 1122 public @interface ScrollBarStyle {} 1123 1124 /** 1125 * The scrollbar style to display the scrollbars inside the content area, 1126 * without increasing the padding. The scrollbars will be overlaid with 1127 * translucency on the view's content. 1128 */ 1129 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1130 1131 /** 1132 * The scrollbar style to display the scrollbars inside the padded area, 1133 * increasing the padding of the view. The scrollbars will not overlap the 1134 * content area of the view. 1135 */ 1136 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1137 1138 /** 1139 * The scrollbar style to display the scrollbars at the edge of the view, 1140 * without increasing the padding. The scrollbars will be overlaid with 1141 * translucency. 1142 */ 1143 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1144 1145 /** 1146 * The scrollbar style to display the scrollbars at the edge of the view, 1147 * increasing the padding of the view. The scrollbars will only overlap the 1148 * background, if any. 1149 */ 1150 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1151 1152 /** 1153 * Mask to check if the scrollbar style is overlay or inset. 1154 * {@hide} 1155 */ 1156 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1157 1158 /** 1159 * Mask to check if the scrollbar style is inside or outside. 1160 * {@hide} 1161 */ 1162 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1163 1164 /** 1165 * Mask for scrollbar style. 1166 * {@hide} 1167 */ 1168 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1169 1170 /** 1171 * View flag indicating that the screen should remain on while the 1172 * window containing this view is visible to the user. This effectively 1173 * takes care of automatically setting the WindowManager's 1174 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1175 */ 1176 public static final int KEEP_SCREEN_ON = 0x04000000; 1177 1178 /** 1179 * View flag indicating whether this view should have sound effects enabled 1180 * for events such as clicking and touching. 1181 */ 1182 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1183 1184 /** 1185 * View flag indicating whether this view should have haptic feedback 1186 * enabled for events such as long presses. 1187 */ 1188 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1189 1190 /** 1191 * <p>Indicates that the view hierarchy should stop saving state when 1192 * it reaches this view. If state saving is initiated immediately at 1193 * the view, it will be allowed. 1194 * {@hide} 1195 */ 1196 static final int PARENT_SAVE_DISABLED = 0x20000000; 1197 1198 /** 1199 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1200 * {@hide} 1201 */ 1202 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1203 1204 private static Paint sDebugPaint; 1205 1206 /** 1207 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1208 * {@hide} 1209 */ 1210 static final int TOOLTIP = 0x40000000; 1211 1212 /** @hide */ 1213 @IntDef(flag = true, 1214 value = { 1215 FOCUSABLES_ALL, 1216 FOCUSABLES_TOUCH_MODE 1217 }) 1218 @Retention(RetentionPolicy.SOURCE) 1219 public @interface FocusableMode {} 1220 1221 /** 1222 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1223 * should add all focusable Views regardless if they are focusable in touch mode. 1224 */ 1225 public static final int FOCUSABLES_ALL = 0x00000000; 1226 1227 /** 1228 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1229 * should add only Views focusable in touch mode. 1230 */ 1231 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1232 1233 /** @hide */ 1234 @IntDef({ 1235 FOCUS_BACKWARD, 1236 FOCUS_FORWARD, 1237 FOCUS_LEFT, 1238 FOCUS_UP, 1239 FOCUS_RIGHT, 1240 FOCUS_DOWN 1241 }) 1242 @Retention(RetentionPolicy.SOURCE) 1243 public @interface FocusDirection {} 1244 1245 /** @hide */ 1246 @IntDef({ 1247 FOCUS_LEFT, 1248 FOCUS_UP, 1249 FOCUS_RIGHT, 1250 FOCUS_DOWN 1251 }) 1252 @Retention(RetentionPolicy.SOURCE) 1253 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1254 1255 /** @hide */ 1256 @IntDef({ 1257 KEYBOARD_NAVIGATION_GROUP_CLUSTER, 1258 KEYBOARD_NAVIGATION_GROUP_SECTION 1259 }) 1260 @Retention(RetentionPolicy.SOURCE) 1261 public @interface KeyboardNavigationGroupType {} 1262 1263 /** 1264 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1265 * item. 1266 */ 1267 public static final int FOCUS_BACKWARD = 0x00000001; 1268 1269 /** 1270 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1271 * item. 1272 */ 1273 public static final int FOCUS_FORWARD = 0x00000002; 1274 1275 /** 1276 * Use with {@link #focusSearch(int)}. Move focus to the left. 1277 */ 1278 public static final int FOCUS_LEFT = 0x00000011; 1279 1280 /** 1281 * Use with {@link #focusSearch(int)}. Move focus up. 1282 */ 1283 public static final int FOCUS_UP = 0x00000021; 1284 1285 /** 1286 * Use with {@link #focusSearch(int)}. Move focus to the right. 1287 */ 1288 public static final int FOCUS_RIGHT = 0x00000042; 1289 1290 /** 1291 * Use with {@link #focusSearch(int)}. Move focus down. 1292 */ 1293 public static final int FOCUS_DOWN = 0x00000082; 1294 1295 /** 1296 * Use with {@link #keyboardNavigationGroupSearch(int, View, int)}. Search for a keyboard 1297 * navigation cluster. 1298 */ 1299 public static final int KEYBOARD_NAVIGATION_GROUP_CLUSTER = 1; 1300 1301 /** 1302 * Use with {@link #keyboardNavigationGroupSearch(int, View, int)}. Search for a keyboard 1303 * navigation section. 1304 */ 1305 public static final int KEYBOARD_NAVIGATION_GROUP_SECTION = 2; 1306 1307 /** 1308 * Bits of {@link #getMeasuredWidthAndState()} and 1309 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1310 */ 1311 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1312 1313 /** 1314 * Bits of {@link #getMeasuredWidthAndState()} and 1315 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1316 */ 1317 public static final int MEASURED_STATE_MASK = 0xff000000; 1318 1319 /** 1320 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1321 * for functions that combine both width and height into a single int, 1322 * such as {@link #getMeasuredState()} and the childState argument of 1323 * {@link #resolveSizeAndState(int, int, int)}. 1324 */ 1325 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1326 1327 /** 1328 * Bit of {@link #getMeasuredWidthAndState()} and 1329 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1330 * is smaller that the space the view would like to have. 1331 */ 1332 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1333 1334 /** 1335 * Base View state sets 1336 */ 1337 // Singles 1338 /** 1339 * Indicates the view has no states set. States are used with 1340 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1341 * view depending on its state. 1342 * 1343 * @see android.graphics.drawable.Drawable 1344 * @see #getDrawableState() 1345 */ 1346 protected static final int[] EMPTY_STATE_SET; 1347 /** 1348 * Indicates the view is enabled. States are used with 1349 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1350 * view depending on its state. 1351 * 1352 * @see android.graphics.drawable.Drawable 1353 * @see #getDrawableState() 1354 */ 1355 protected static final int[] ENABLED_STATE_SET; 1356 /** 1357 * Indicates the view is focused. States are used with 1358 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1359 * view depending on its state. 1360 * 1361 * @see android.graphics.drawable.Drawable 1362 * @see #getDrawableState() 1363 */ 1364 protected static final int[] FOCUSED_STATE_SET; 1365 /** 1366 * Indicates the view is selected. States are used with 1367 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1368 * view depending on its state. 1369 * 1370 * @see android.graphics.drawable.Drawable 1371 * @see #getDrawableState() 1372 */ 1373 protected static final int[] SELECTED_STATE_SET; 1374 /** 1375 * Indicates the view is pressed. States are used with 1376 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1377 * view depending on its state. 1378 * 1379 * @see android.graphics.drawable.Drawable 1380 * @see #getDrawableState() 1381 */ 1382 protected static final int[] PRESSED_STATE_SET; 1383 /** 1384 * Indicates the view's window has focus. States are used with 1385 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1386 * view depending on its state. 1387 * 1388 * @see android.graphics.drawable.Drawable 1389 * @see #getDrawableState() 1390 */ 1391 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1392 // Doubles 1393 /** 1394 * Indicates the view is enabled and has the focus. 1395 * 1396 * @see #ENABLED_STATE_SET 1397 * @see #FOCUSED_STATE_SET 1398 */ 1399 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1400 /** 1401 * Indicates the view is enabled and selected. 1402 * 1403 * @see #ENABLED_STATE_SET 1404 * @see #SELECTED_STATE_SET 1405 */ 1406 protected static final int[] ENABLED_SELECTED_STATE_SET; 1407 /** 1408 * Indicates the view is enabled and that its window has focus. 1409 * 1410 * @see #ENABLED_STATE_SET 1411 * @see #WINDOW_FOCUSED_STATE_SET 1412 */ 1413 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1414 /** 1415 * Indicates the view is focused and selected. 1416 * 1417 * @see #FOCUSED_STATE_SET 1418 * @see #SELECTED_STATE_SET 1419 */ 1420 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1421 /** 1422 * Indicates the view has the focus and that its window has the focus. 1423 * 1424 * @see #FOCUSED_STATE_SET 1425 * @see #WINDOW_FOCUSED_STATE_SET 1426 */ 1427 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1428 /** 1429 * Indicates the view is selected and that its window has the focus. 1430 * 1431 * @see #SELECTED_STATE_SET 1432 * @see #WINDOW_FOCUSED_STATE_SET 1433 */ 1434 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1435 // Triples 1436 /** 1437 * Indicates the view is enabled, focused and selected. 1438 * 1439 * @see #ENABLED_STATE_SET 1440 * @see #FOCUSED_STATE_SET 1441 * @see #SELECTED_STATE_SET 1442 */ 1443 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1444 /** 1445 * Indicates the view is enabled, focused and its window has the focus. 1446 * 1447 * @see #ENABLED_STATE_SET 1448 * @see #FOCUSED_STATE_SET 1449 * @see #WINDOW_FOCUSED_STATE_SET 1450 */ 1451 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1452 /** 1453 * Indicates the view is enabled, selected and its window has the focus. 1454 * 1455 * @see #ENABLED_STATE_SET 1456 * @see #SELECTED_STATE_SET 1457 * @see #WINDOW_FOCUSED_STATE_SET 1458 */ 1459 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1460 /** 1461 * Indicates the view is focused, selected and its window has the focus. 1462 * 1463 * @see #FOCUSED_STATE_SET 1464 * @see #SELECTED_STATE_SET 1465 * @see #WINDOW_FOCUSED_STATE_SET 1466 */ 1467 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1468 /** 1469 * Indicates the view is enabled, focused, selected and its window 1470 * has the focus. 1471 * 1472 * @see #ENABLED_STATE_SET 1473 * @see #FOCUSED_STATE_SET 1474 * @see #SELECTED_STATE_SET 1475 * @see #WINDOW_FOCUSED_STATE_SET 1476 */ 1477 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1478 /** 1479 * Indicates the view is pressed and its window has the focus. 1480 * 1481 * @see #PRESSED_STATE_SET 1482 * @see #WINDOW_FOCUSED_STATE_SET 1483 */ 1484 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1485 /** 1486 * Indicates the view is pressed and selected. 1487 * 1488 * @see #PRESSED_STATE_SET 1489 * @see #SELECTED_STATE_SET 1490 */ 1491 protected static final int[] PRESSED_SELECTED_STATE_SET; 1492 /** 1493 * Indicates the view is pressed, selected and its window has the focus. 1494 * 1495 * @see #PRESSED_STATE_SET 1496 * @see #SELECTED_STATE_SET 1497 * @see #WINDOW_FOCUSED_STATE_SET 1498 */ 1499 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1500 /** 1501 * Indicates the view is pressed and focused. 1502 * 1503 * @see #PRESSED_STATE_SET 1504 * @see #FOCUSED_STATE_SET 1505 */ 1506 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1507 /** 1508 * Indicates the view is pressed, focused and its window has the focus. 1509 * 1510 * @see #PRESSED_STATE_SET 1511 * @see #FOCUSED_STATE_SET 1512 * @see #WINDOW_FOCUSED_STATE_SET 1513 */ 1514 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1515 /** 1516 * Indicates the view is pressed, focused and selected. 1517 * 1518 * @see #PRESSED_STATE_SET 1519 * @see #SELECTED_STATE_SET 1520 * @see #FOCUSED_STATE_SET 1521 */ 1522 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1523 /** 1524 * Indicates the view is pressed, focused, selected and its window has the focus. 1525 * 1526 * @see #PRESSED_STATE_SET 1527 * @see #FOCUSED_STATE_SET 1528 * @see #SELECTED_STATE_SET 1529 * @see #WINDOW_FOCUSED_STATE_SET 1530 */ 1531 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1532 /** 1533 * Indicates the view is pressed and enabled. 1534 * 1535 * @see #PRESSED_STATE_SET 1536 * @see #ENABLED_STATE_SET 1537 */ 1538 protected static final int[] PRESSED_ENABLED_STATE_SET; 1539 /** 1540 * Indicates the view is pressed, enabled and its window has the focus. 1541 * 1542 * @see #PRESSED_STATE_SET 1543 * @see #ENABLED_STATE_SET 1544 * @see #WINDOW_FOCUSED_STATE_SET 1545 */ 1546 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1547 /** 1548 * Indicates the view is pressed, enabled and selected. 1549 * 1550 * @see #PRESSED_STATE_SET 1551 * @see #ENABLED_STATE_SET 1552 * @see #SELECTED_STATE_SET 1553 */ 1554 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1555 /** 1556 * Indicates the view is pressed, enabled, selected and its window has the 1557 * focus. 1558 * 1559 * @see #PRESSED_STATE_SET 1560 * @see #ENABLED_STATE_SET 1561 * @see #SELECTED_STATE_SET 1562 * @see #WINDOW_FOCUSED_STATE_SET 1563 */ 1564 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1565 /** 1566 * Indicates the view is pressed, enabled and focused. 1567 * 1568 * @see #PRESSED_STATE_SET 1569 * @see #ENABLED_STATE_SET 1570 * @see #FOCUSED_STATE_SET 1571 */ 1572 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1573 /** 1574 * Indicates the view is pressed, enabled, focused and its window has the 1575 * focus. 1576 * 1577 * @see #PRESSED_STATE_SET 1578 * @see #ENABLED_STATE_SET 1579 * @see #FOCUSED_STATE_SET 1580 * @see #WINDOW_FOCUSED_STATE_SET 1581 */ 1582 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1583 /** 1584 * Indicates the view is pressed, enabled, focused and selected. 1585 * 1586 * @see #PRESSED_STATE_SET 1587 * @see #ENABLED_STATE_SET 1588 * @see #SELECTED_STATE_SET 1589 * @see #FOCUSED_STATE_SET 1590 */ 1591 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1592 /** 1593 * Indicates the view is pressed, enabled, focused, selected and its window 1594 * has the focus. 1595 * 1596 * @see #PRESSED_STATE_SET 1597 * @see #ENABLED_STATE_SET 1598 * @see #SELECTED_STATE_SET 1599 * @see #FOCUSED_STATE_SET 1600 * @see #WINDOW_FOCUSED_STATE_SET 1601 */ 1602 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1603 1604 static { 1605 EMPTY_STATE_SET = StateSet.get(0); 1606 1607 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1608 1609 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1610 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1611 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1612 1613 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1614 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1615 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1616 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1617 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1618 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1619 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1620 | StateSet.VIEW_STATE_FOCUSED); 1621 1622 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1623 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1624 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1625 ENABLED_SELECTED_STATE_SET = StateSet.get( 1626 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1627 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1628 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1629 | StateSet.VIEW_STATE_ENABLED); 1630 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1631 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1632 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1633 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1634 | StateSet.VIEW_STATE_ENABLED); 1635 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1636 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1637 | StateSet.VIEW_STATE_ENABLED); 1638 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1639 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1640 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1641 1642 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1643 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1644 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1645 PRESSED_SELECTED_STATE_SET = StateSet.get( 1646 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1647 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1648 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1649 | StateSet.VIEW_STATE_PRESSED); 1650 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1651 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1652 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1653 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1654 | StateSet.VIEW_STATE_PRESSED); 1655 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1656 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1657 | StateSet.VIEW_STATE_PRESSED); 1658 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1659 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1660 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1661 PRESSED_ENABLED_STATE_SET = StateSet.get( 1662 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1663 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1664 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1665 | StateSet.VIEW_STATE_PRESSED); 1666 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1667 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1668 | StateSet.VIEW_STATE_PRESSED); 1669 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1670 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1671 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1672 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 1673 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 1674 | StateSet.VIEW_STATE_PRESSED); 1675 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1676 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1677 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1678 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1679 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1680 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1681 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1682 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1683 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 1684 | StateSet.VIEW_STATE_PRESSED); 1685 } 1686 1687 /** 1688 * Accessibility event types that are dispatched for text population. 1689 */ 1690 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 1691 AccessibilityEvent.TYPE_VIEW_CLICKED 1692 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 1693 | AccessibilityEvent.TYPE_VIEW_SELECTED 1694 | AccessibilityEvent.TYPE_VIEW_FOCUSED 1695 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 1696 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 1697 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 1698 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 1699 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 1700 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 1701 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 1702 1703 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 1704 1705 static final int DEBUG_CORNERS_SIZE_DIP = 8; 1706 1707 /** 1708 * Temporary Rect currently for use in setBackground(). This will probably 1709 * be extended in the future to hold our own class with more than just 1710 * a Rect. :) 1711 */ 1712 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 1713 1714 /** 1715 * Map used to store views' tags. 1716 */ 1717 private SparseArray<Object> mKeyedTags; 1718 1719 /** 1720 * The next available accessibility id. 1721 */ 1722 private static int sNextAccessibilityViewId; 1723 1724 /** 1725 * The animation currently associated with this view. 1726 * @hide 1727 */ 1728 protected Animation mCurrentAnimation = null; 1729 1730 /** 1731 * Width as measured during measure pass. 1732 * {@hide} 1733 */ 1734 @ViewDebug.ExportedProperty(category = "measurement") 1735 int mMeasuredWidth; 1736 1737 /** 1738 * Height as measured during measure pass. 1739 * {@hide} 1740 */ 1741 @ViewDebug.ExportedProperty(category = "measurement") 1742 int mMeasuredHeight; 1743 1744 /** 1745 * Flag to indicate that this view was marked INVALIDATED, or had its display list 1746 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 1747 * its display list. This flag, used only when hw accelerated, allows us to clear the 1748 * flag while retaining this information until it's needed (at getDisplayList() time and 1749 * in drawChild(), when we decide to draw a view's children's display lists into our own). 1750 * 1751 * {@hide} 1752 */ 1753 boolean mRecreateDisplayList = false; 1754 1755 /** 1756 * The view's identifier. 1757 * {@hide} 1758 * 1759 * @see #setId(int) 1760 * @see #getId() 1761 */ 1762 @IdRes 1763 @ViewDebug.ExportedProperty(resolveId = true) 1764 int mID = NO_ID; 1765 1766 /** 1767 * The stable ID of this view for accessibility purposes. 1768 */ 1769 int mAccessibilityViewId = NO_ID; 1770 1771 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 1772 1773 SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent; 1774 1775 /** 1776 * The view's tag. 1777 * {@hide} 1778 * 1779 * @see #setTag(Object) 1780 * @see #getTag() 1781 */ 1782 protected Object mTag = null; 1783 1784 // for mPrivateFlags: 1785 /** {@hide} */ 1786 static final int PFLAG_WANTS_FOCUS = 0x00000001; 1787 /** {@hide} */ 1788 static final int PFLAG_FOCUSED = 0x00000002; 1789 /** {@hide} */ 1790 static final int PFLAG_SELECTED = 0x00000004; 1791 /** {@hide} */ 1792 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 1793 /** {@hide} */ 1794 static final int PFLAG_HAS_BOUNDS = 0x00000010; 1795 /** {@hide} */ 1796 static final int PFLAG_DRAWN = 0x00000020; 1797 /** 1798 * When this flag is set, this view is running an animation on behalf of its 1799 * children and should therefore not cancel invalidate requests, even if they 1800 * lie outside of this view's bounds. 1801 * 1802 * {@hide} 1803 */ 1804 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 1805 /** {@hide} */ 1806 static final int PFLAG_SKIP_DRAW = 0x00000080; 1807 /** {@hide} */ 1808 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 1809 /** {@hide} */ 1810 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 1811 /** {@hide} */ 1812 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 1813 /** {@hide} */ 1814 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 1815 /** {@hide} */ 1816 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 1817 1818 private static final int PFLAG_PRESSED = 0x00004000; 1819 1820 /** {@hide} */ 1821 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 1822 /** 1823 * Flag used to indicate that this view should be drawn once more (and only once 1824 * more) after its animation has completed. 1825 * {@hide} 1826 */ 1827 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 1828 1829 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 1830 1831 /** 1832 * Indicates that the View returned true when onSetAlpha() was called and that 1833 * the alpha must be restored. 1834 * {@hide} 1835 */ 1836 static final int PFLAG_ALPHA_SET = 0x00040000; 1837 1838 /** 1839 * Set by {@link #setScrollContainer(boolean)}. 1840 */ 1841 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 1842 1843 /** 1844 * Set by {@link #setScrollContainer(boolean)}. 1845 */ 1846 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 1847 1848 /** 1849 * View flag indicating whether this view was invalidated (fully or partially.) 1850 * 1851 * @hide 1852 */ 1853 static final int PFLAG_DIRTY = 0x00200000; 1854 1855 /** 1856 * View flag indicating whether this view was invalidated by an opaque 1857 * invalidate request. 1858 * 1859 * @hide 1860 */ 1861 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 1862 1863 /** 1864 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 1865 * 1866 * @hide 1867 */ 1868 static final int PFLAG_DIRTY_MASK = 0x00600000; 1869 1870 /** 1871 * Indicates whether the background is opaque. 1872 * 1873 * @hide 1874 */ 1875 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 1876 1877 /** 1878 * Indicates whether the scrollbars are opaque. 1879 * 1880 * @hide 1881 */ 1882 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 1883 1884 /** 1885 * Indicates whether the view is opaque. 1886 * 1887 * @hide 1888 */ 1889 static final int PFLAG_OPAQUE_MASK = 0x01800000; 1890 1891 /** 1892 * Indicates a prepressed state; 1893 * the short time between ACTION_DOWN and recognizing 1894 * a 'real' press. Prepressed is used to recognize quick taps 1895 * even when they are shorter than ViewConfiguration.getTapTimeout(). 1896 * 1897 * @hide 1898 */ 1899 private static final int PFLAG_PREPRESSED = 0x02000000; 1900 1901 /** 1902 * Indicates whether the view is temporarily detached. 1903 * 1904 * @hide 1905 */ 1906 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 1907 1908 /** 1909 * Indicates that we should awaken scroll bars once attached 1910 * 1911 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 1912 * during window attachment and it is no longer needed. Feel free to repurpose it. 1913 * 1914 * @hide 1915 */ 1916 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 1917 1918 /** 1919 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 1920 * @hide 1921 */ 1922 private static final int PFLAG_HOVERED = 0x10000000; 1923 1924 /** 1925 * no longer needed, should be reused 1926 */ 1927 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 1928 1929 /** {@hide} */ 1930 static final int PFLAG_ACTIVATED = 0x40000000; 1931 1932 /** 1933 * Indicates that this view was specifically invalidated, not just dirtied because some 1934 * child view was invalidated. The flag is used to determine when we need to recreate 1935 * a view's display list (as opposed to just returning a reference to its existing 1936 * display list). 1937 * 1938 * @hide 1939 */ 1940 static final int PFLAG_INVALIDATED = 0x80000000; 1941 1942 /** 1943 * Masks for mPrivateFlags2, as generated by dumpFlags(): 1944 * 1945 * |-------|-------|-------|-------| 1946 * 1 PFLAG2_DRAG_CAN_ACCEPT 1947 * 1 PFLAG2_DRAG_HOVERED 1948 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 1949 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 1950 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 1951 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 1952 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 1953 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 1954 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 1955 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 1956 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 1957 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 1958 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 1959 * 111 PFLAG2_TEXT_DIRECTION_MASK 1960 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 1961 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 1962 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 1963 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 1964 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 1965 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 1966 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 1967 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 1968 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 1969 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 1970 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 1971 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 1972 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 1973 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 1974 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 1975 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 1976 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 1977 * 1 PFLAG2_VIEW_QUICK_REJECTED 1978 * 1 PFLAG2_PADDING_RESOLVED 1979 * 1 PFLAG2_DRAWABLE_RESOLVED 1980 * 1 PFLAG2_HAS_TRANSIENT_STATE 1981 * |-------|-------|-------|-------| 1982 */ 1983 1984 /** 1985 * Indicates that this view has reported that it can accept the current drag's content. 1986 * Cleared when the drag operation concludes. 1987 * @hide 1988 */ 1989 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 1990 1991 /** 1992 * Indicates that this view is currently directly under the drag location in a 1993 * drag-and-drop operation involving content that it can accept. Cleared when 1994 * the drag exits the view, or when the drag operation concludes. 1995 * @hide 1996 */ 1997 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 1998 1999 /** @hide */ 2000 @IntDef({ 2001 LAYOUT_DIRECTION_LTR, 2002 LAYOUT_DIRECTION_RTL, 2003 LAYOUT_DIRECTION_INHERIT, 2004 LAYOUT_DIRECTION_LOCALE 2005 }) 2006 @Retention(RetentionPolicy.SOURCE) 2007 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2008 public @interface LayoutDir {} 2009 2010 /** @hide */ 2011 @IntDef({ 2012 LAYOUT_DIRECTION_LTR, 2013 LAYOUT_DIRECTION_RTL 2014 }) 2015 @Retention(RetentionPolicy.SOURCE) 2016 public @interface ResolvedLayoutDir {} 2017 2018 /** 2019 * A flag to indicate that the layout direction of this view has not been defined yet. 2020 * @hide 2021 */ 2022 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2023 2024 /** 2025 * Horizontal layout direction of this view is from Left to Right. 2026 * Use with {@link #setLayoutDirection}. 2027 */ 2028 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2029 2030 /** 2031 * Horizontal layout direction of this view is from Right to Left. 2032 * Use with {@link #setLayoutDirection}. 2033 */ 2034 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2035 2036 /** 2037 * Horizontal layout direction of this view is inherited from its parent. 2038 * Use with {@link #setLayoutDirection}. 2039 */ 2040 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2041 2042 /** 2043 * Horizontal layout direction of this view is from deduced from the default language 2044 * script for the locale. Use with {@link #setLayoutDirection}. 2045 */ 2046 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2047 2048 /** 2049 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2050 * @hide 2051 */ 2052 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2053 2054 /** 2055 * Mask for use with private flags indicating bits used for horizontal layout direction. 2056 * @hide 2057 */ 2058 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2059 2060 /** 2061 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2062 * right-to-left direction. 2063 * @hide 2064 */ 2065 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2066 2067 /** 2068 * Indicates whether the view horizontal layout direction has been resolved. 2069 * @hide 2070 */ 2071 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2072 2073 /** 2074 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2075 * @hide 2076 */ 2077 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2078 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2079 2080 /* 2081 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2082 * flag value. 2083 * @hide 2084 */ 2085 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2086 LAYOUT_DIRECTION_LTR, 2087 LAYOUT_DIRECTION_RTL, 2088 LAYOUT_DIRECTION_INHERIT, 2089 LAYOUT_DIRECTION_LOCALE 2090 }; 2091 2092 /** 2093 * Default horizontal layout direction. 2094 */ 2095 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2096 2097 /** 2098 * Default horizontal layout direction. 2099 * @hide 2100 */ 2101 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2102 2103 /** 2104 * Text direction is inherited through {@link ViewGroup} 2105 */ 2106 public static final int TEXT_DIRECTION_INHERIT = 0; 2107 2108 /** 2109 * Text direction is using "first strong algorithm". The first strong directional character 2110 * determines the paragraph direction. If there is no strong directional character, the 2111 * paragraph direction is the view's resolved layout direction. 2112 */ 2113 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2114 2115 /** 2116 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2117 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2118 * If there are neither, the paragraph direction is the view's resolved layout direction. 2119 */ 2120 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2121 2122 /** 2123 * Text direction is forced to LTR. 2124 */ 2125 public static final int TEXT_DIRECTION_LTR = 3; 2126 2127 /** 2128 * Text direction is forced to RTL. 2129 */ 2130 public static final int TEXT_DIRECTION_RTL = 4; 2131 2132 /** 2133 * Text direction is coming from the system Locale. 2134 */ 2135 public static final int TEXT_DIRECTION_LOCALE = 5; 2136 2137 /** 2138 * Text direction is using "first strong algorithm". The first strong directional character 2139 * determines the paragraph direction. If there is no strong directional character, the 2140 * paragraph direction is LTR. 2141 */ 2142 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2143 2144 /** 2145 * Text direction is using "first strong algorithm". The first strong directional character 2146 * determines the paragraph direction. If there is no strong directional character, the 2147 * paragraph direction is RTL. 2148 */ 2149 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2150 2151 /** 2152 * Default text direction is inherited 2153 */ 2154 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2155 2156 /** 2157 * Default resolved text direction 2158 * @hide 2159 */ 2160 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2161 2162 /** 2163 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2164 * @hide 2165 */ 2166 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2167 2168 /** 2169 * Mask for use with private flags indicating bits used for text direction. 2170 * @hide 2171 */ 2172 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2173 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2174 2175 /** 2176 * Array of text direction flags for mapping attribute "textDirection" to correct 2177 * flag value. 2178 * @hide 2179 */ 2180 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2181 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2182 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2183 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2184 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2185 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2186 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2187 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2188 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2189 }; 2190 2191 /** 2192 * Indicates whether the view text direction has been resolved. 2193 * @hide 2194 */ 2195 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2196 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2197 2198 /** 2199 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2200 * @hide 2201 */ 2202 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2203 2204 /** 2205 * Mask for use with private flags indicating bits used for resolved text direction. 2206 * @hide 2207 */ 2208 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2209 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2210 2211 /** 2212 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2213 * @hide 2214 */ 2215 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2216 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2217 2218 /** @hide */ 2219 @IntDef({ 2220 TEXT_ALIGNMENT_INHERIT, 2221 TEXT_ALIGNMENT_GRAVITY, 2222 TEXT_ALIGNMENT_CENTER, 2223 TEXT_ALIGNMENT_TEXT_START, 2224 TEXT_ALIGNMENT_TEXT_END, 2225 TEXT_ALIGNMENT_VIEW_START, 2226 TEXT_ALIGNMENT_VIEW_END 2227 }) 2228 @Retention(RetentionPolicy.SOURCE) 2229 public @interface TextAlignment {} 2230 2231 /** 2232 * Default text alignment. The text alignment of this View is inherited from its parent. 2233 * Use with {@link #setTextAlignment(int)} 2234 */ 2235 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2236 2237 /** 2238 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2239 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2240 * 2241 * Use with {@link #setTextAlignment(int)} 2242 */ 2243 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2244 2245 /** 2246 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2247 * 2248 * Use with {@link #setTextAlignment(int)} 2249 */ 2250 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2251 2252 /** 2253 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2254 * 2255 * Use with {@link #setTextAlignment(int)} 2256 */ 2257 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2258 2259 /** 2260 * Center the paragraph, e.g. ALIGN_CENTER. 2261 * 2262 * Use with {@link #setTextAlignment(int)} 2263 */ 2264 public static final int TEXT_ALIGNMENT_CENTER = 4; 2265 2266 /** 2267 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2268 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2269 * 2270 * Use with {@link #setTextAlignment(int)} 2271 */ 2272 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2273 2274 /** 2275 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2276 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2277 * 2278 * Use with {@link #setTextAlignment(int)} 2279 */ 2280 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2281 2282 /** 2283 * Default text alignment is inherited 2284 */ 2285 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2286 2287 /** 2288 * Default resolved text alignment 2289 * @hide 2290 */ 2291 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2292 2293 /** 2294 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2295 * @hide 2296 */ 2297 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2298 2299 /** 2300 * Mask for use with private flags indicating bits used for text alignment. 2301 * @hide 2302 */ 2303 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2304 2305 /** 2306 * Array of text direction flags for mapping attribute "textAlignment" to correct 2307 * flag value. 2308 * @hide 2309 */ 2310 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2311 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2312 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2313 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2314 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2315 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2316 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2317 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2318 }; 2319 2320 /** 2321 * Indicates whether the view text alignment has been resolved. 2322 * @hide 2323 */ 2324 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2325 2326 /** 2327 * Bit shift to get the resolved text alignment. 2328 * @hide 2329 */ 2330 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2331 2332 /** 2333 * Mask for use with private flags indicating bits used for text alignment. 2334 * @hide 2335 */ 2336 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2337 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2338 2339 /** 2340 * Indicates whether if the view text alignment has been resolved to gravity 2341 */ 2342 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2343 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2344 2345 // Accessiblity constants for mPrivateFlags2 2346 2347 /** 2348 * Shift for the bits in {@link #mPrivateFlags2} related to the 2349 * "importantForAccessibility" attribute. 2350 */ 2351 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2352 2353 /** 2354 * Automatically determine whether a view is important for accessibility. 2355 */ 2356 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2357 2358 /** 2359 * The view is important for accessibility. 2360 */ 2361 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2362 2363 /** 2364 * The view is not important for accessibility. 2365 */ 2366 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2367 2368 /** 2369 * The view is not important for accessibility, nor are any of its 2370 * descendant views. 2371 */ 2372 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2373 2374 /** 2375 * The default whether the view is important for accessibility. 2376 */ 2377 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2378 2379 /** 2380 * Mask for obtaining the bits which specify how to determine 2381 * whether a view is important for accessibility. 2382 */ 2383 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2384 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2385 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2386 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2387 2388 /** 2389 * Shift for the bits in {@link #mPrivateFlags2} related to the 2390 * "accessibilityLiveRegion" attribute. 2391 */ 2392 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2393 2394 /** 2395 * Live region mode specifying that accessibility services should not 2396 * automatically announce changes to this view. This is the default live 2397 * region mode for most views. 2398 * <p> 2399 * Use with {@link #setAccessibilityLiveRegion(int)}. 2400 */ 2401 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2402 2403 /** 2404 * Live region mode specifying that accessibility services should announce 2405 * changes to this view. 2406 * <p> 2407 * Use with {@link #setAccessibilityLiveRegion(int)}. 2408 */ 2409 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2410 2411 /** 2412 * Live region mode specifying that accessibility services should interrupt 2413 * ongoing speech to immediately announce changes to this view. 2414 * <p> 2415 * Use with {@link #setAccessibilityLiveRegion(int)}. 2416 */ 2417 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2418 2419 /** 2420 * The default whether the view is important for accessibility. 2421 */ 2422 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2423 2424 /** 2425 * Mask for obtaining the bits which specify a view's accessibility live 2426 * region mode. 2427 */ 2428 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2429 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2430 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2431 2432 /** 2433 * Flag indicating whether a view has accessibility focus. 2434 */ 2435 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2436 2437 /** 2438 * Flag whether the accessibility state of the subtree rooted at this view changed. 2439 */ 2440 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2441 2442 /** 2443 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2444 * is used to check whether later changes to the view's transform should invalidate the 2445 * view to force the quickReject test to run again. 2446 */ 2447 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2448 2449 /** 2450 * Flag indicating that start/end padding has been resolved into left/right padding 2451 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2452 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2453 * during measurement. In some special cases this is required such as when an adapter-based 2454 * view measures prospective children without attaching them to a window. 2455 */ 2456 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2457 2458 /** 2459 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2460 */ 2461 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2462 2463 /** 2464 * Indicates that the view is tracking some sort of transient state 2465 * that the app should not need to be aware of, but that the framework 2466 * should take special care to preserve. 2467 */ 2468 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2469 2470 /** 2471 * Group of bits indicating that RTL properties resolution is done. 2472 */ 2473 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2474 PFLAG2_TEXT_DIRECTION_RESOLVED | 2475 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2476 PFLAG2_PADDING_RESOLVED | 2477 PFLAG2_DRAWABLE_RESOLVED; 2478 2479 // There are a couple of flags left in mPrivateFlags2 2480 2481 /* End of masks for mPrivateFlags2 */ 2482 2483 /** 2484 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2485 * 2486 * |-------|-------|-------|-------| 2487 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2488 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2489 * 1 PFLAG3_IS_LAID_OUT 2490 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2491 * 1 PFLAG3_CALLED_SUPER 2492 * 1 PFLAG3_APPLYING_INSETS 2493 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2494 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2495 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2496 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2497 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2498 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2499 * 1 PFLAG3_SCROLL_INDICATOR_START 2500 * 1 PFLAG3_SCROLL_INDICATOR_END 2501 * 1 PFLAG3_ASSIST_BLOCKED 2502 * 1 PFLAG3_CLUSTER 2503 * 1 PFLAG3_SECTION 2504 * 1 PFLAG3_FINGER_DOWN 2505 * 1 PFLAG3_FOCUSED_BY_DEFAULT 2506 * xxxx * NO LONGER NEEDED, SHOULD BE REUSED * 2507 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2508 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2509 * 1 PFLAG3_TEMPORARY_DETACH 2510 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2511 * |-------|-------|-------|-------| 2512 */ 2513 2514 /** 2515 * Flag indicating that view has a transform animation set on it. This is used to track whether 2516 * an animation is cleared between successive frames, in order to tell the associated 2517 * DisplayList to clear its animation matrix. 2518 */ 2519 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2520 2521 /** 2522 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2523 * animation is cleared between successive frames, in order to tell the associated 2524 * DisplayList to restore its alpha value. 2525 */ 2526 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2527 2528 /** 2529 * Flag indicating that the view has been through at least one layout since it 2530 * was last attached to a window. 2531 */ 2532 static final int PFLAG3_IS_LAID_OUT = 0x4; 2533 2534 /** 2535 * Flag indicating that a call to measure() was skipped and should be done 2536 * instead when layout() is invoked. 2537 */ 2538 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2539 2540 /** 2541 * Flag indicating that an overridden method correctly called down to 2542 * the superclass implementation as required by the API spec. 2543 */ 2544 static final int PFLAG3_CALLED_SUPER = 0x10; 2545 2546 /** 2547 * Flag indicating that we're in the process of applying window insets. 2548 */ 2549 static final int PFLAG3_APPLYING_INSETS = 0x20; 2550 2551 /** 2552 * Flag indicating that we're in the process of fitting system windows using the old method. 2553 */ 2554 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2555 2556 /** 2557 * Flag indicating that nested scrolling is enabled for this view. 2558 * The view will optionally cooperate with views up its parent chain to allow for 2559 * integrated nested scrolling along the same axis. 2560 */ 2561 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2562 2563 /** 2564 * Flag indicating that the bottom scroll indicator should be displayed 2565 * when this view can scroll up. 2566 */ 2567 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2568 2569 /** 2570 * Flag indicating that the bottom scroll indicator should be displayed 2571 * when this view can scroll down. 2572 */ 2573 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2574 2575 /** 2576 * Flag indicating that the left scroll indicator should be displayed 2577 * when this view can scroll left. 2578 */ 2579 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2580 2581 /** 2582 * Flag indicating that the right scroll indicator should be displayed 2583 * when this view can scroll right. 2584 */ 2585 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2586 2587 /** 2588 * Flag indicating that the start scroll indicator should be displayed 2589 * when this view can scroll in the start direction. 2590 */ 2591 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2592 2593 /** 2594 * Flag indicating that the end scroll indicator should be displayed 2595 * when this view can scroll in the end direction. 2596 */ 2597 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2598 2599 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2600 2601 static final int SCROLL_INDICATORS_NONE = 0x0000; 2602 2603 /** 2604 * Mask for use with setFlags indicating bits used for indicating which 2605 * scroll indicators are enabled. 2606 */ 2607 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2608 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2609 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2610 | PFLAG3_SCROLL_INDICATOR_END; 2611 2612 /** 2613 * Left-shift required to translate between public scroll indicator flags 2614 * and internal PFLAGS3 flags. When used as a right-shift, translates 2615 * PFLAGS3 flags to public flags. 2616 */ 2617 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2618 2619 /** @hide */ 2620 @Retention(RetentionPolicy.SOURCE) 2621 @IntDef(flag = true, 2622 value = { 2623 SCROLL_INDICATOR_TOP, 2624 SCROLL_INDICATOR_BOTTOM, 2625 SCROLL_INDICATOR_LEFT, 2626 SCROLL_INDICATOR_RIGHT, 2627 SCROLL_INDICATOR_START, 2628 SCROLL_INDICATOR_END, 2629 }) 2630 public @interface ScrollIndicators {} 2631 2632 /** 2633 * Scroll indicator direction for the top edge of the view. 2634 * 2635 * @see #setScrollIndicators(int) 2636 * @see #setScrollIndicators(int, int) 2637 * @see #getScrollIndicators() 2638 */ 2639 public static final int SCROLL_INDICATOR_TOP = 2640 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2641 2642 /** 2643 * Scroll indicator direction for the bottom edge of the view. 2644 * 2645 * @see #setScrollIndicators(int) 2646 * @see #setScrollIndicators(int, int) 2647 * @see #getScrollIndicators() 2648 */ 2649 public static final int SCROLL_INDICATOR_BOTTOM = 2650 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2651 2652 /** 2653 * Scroll indicator direction for the left edge of the view. 2654 * 2655 * @see #setScrollIndicators(int) 2656 * @see #setScrollIndicators(int, int) 2657 * @see #getScrollIndicators() 2658 */ 2659 public static final int SCROLL_INDICATOR_LEFT = 2660 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2661 2662 /** 2663 * Scroll indicator direction for the right edge of the view. 2664 * 2665 * @see #setScrollIndicators(int) 2666 * @see #setScrollIndicators(int, int) 2667 * @see #getScrollIndicators() 2668 */ 2669 public static final int SCROLL_INDICATOR_RIGHT = 2670 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2671 2672 /** 2673 * Scroll indicator direction for the starting edge of the view. 2674 * <p> 2675 * Resolved according to the view's layout direction, see 2676 * {@link #getLayoutDirection()} for more information. 2677 * 2678 * @see #setScrollIndicators(int) 2679 * @see #setScrollIndicators(int, int) 2680 * @see #getScrollIndicators() 2681 */ 2682 public static final int SCROLL_INDICATOR_START = 2683 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2684 2685 /** 2686 * Scroll indicator direction for the ending edge of the view. 2687 * <p> 2688 * Resolved according to the view's layout direction, see 2689 * {@link #getLayoutDirection()} for more information. 2690 * 2691 * @see #setScrollIndicators(int) 2692 * @see #setScrollIndicators(int, int) 2693 * @see #getScrollIndicators() 2694 */ 2695 public static final int SCROLL_INDICATOR_END = 2696 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2697 2698 /** 2699 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 2700 * into this view.<p> 2701 */ 2702 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 2703 2704 /** 2705 * Flag indicating that the view is a root of a keyboard navigation cluster. 2706 * 2707 * @see #isKeyboardNavigationCluster() 2708 * @see #setKeyboardNavigationCluster(boolean) 2709 */ 2710 private static final int PFLAG3_CLUSTER = 0x8000; 2711 2712 /** 2713 * Flag indicating that the view is a root of a keyboard navigation section. 2714 * 2715 * @see #isKeyboardNavigationSection() 2716 * @see #setKeyboardNavigationSection(boolean) 2717 */ 2718 private static final int PFLAG3_SECTION = 0x10000; 2719 2720 /** 2721 * Indicates that the user is currently touching the screen. 2722 * Currently used for the tooltip positioning only. 2723 */ 2724 private static final int PFLAG3_FINGER_DOWN = 0x20000; 2725 2726 /** 2727 * Flag indicating that this view is the default-focus view. 2728 * 2729 * @see #isFocusedByDefault() 2730 * @see #setFocusedByDefault(boolean) 2731 */ 2732 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 2733 2734 /** 2735 * Whether this view has rendered elements that overlap (see {@link 2736 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 2737 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 2738 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 2739 * determined by whatever {@link #hasOverlappingRendering()} returns. 2740 */ 2741 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 2742 2743 /** 2744 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 2745 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 2746 */ 2747 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 2748 2749 /** 2750 * Flag indicating that the view is temporarily detached from the parent view. 2751 * 2752 * @see #onStartTemporaryDetach() 2753 * @see #onFinishTemporaryDetach() 2754 */ 2755 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 2756 2757 /** 2758 * Flag indicating that the view does not wish to be revealed within its parent 2759 * hierarchy when it gains focus. Expressed in the negative since the historical 2760 * default behavior is to reveal on focus; this flag suppresses that behavior. 2761 * 2762 * @see #setRevealOnFocusHint(boolean) 2763 * @see #getRevealOnFocusHint() 2764 */ 2765 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 2766 2767 /* End of masks for mPrivateFlags3 */ 2768 2769 /** 2770 * Always allow a user to over-scroll this view, provided it is a 2771 * view that can scroll. 2772 * 2773 * @see #getOverScrollMode() 2774 * @see #setOverScrollMode(int) 2775 */ 2776 public static final int OVER_SCROLL_ALWAYS = 0; 2777 2778 /** 2779 * Allow a user to over-scroll this view only if the content is large 2780 * enough to meaningfully scroll, provided it is a view that can scroll. 2781 * 2782 * @see #getOverScrollMode() 2783 * @see #setOverScrollMode(int) 2784 */ 2785 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 2786 2787 /** 2788 * Never allow a user to over-scroll this view. 2789 * 2790 * @see #getOverScrollMode() 2791 * @see #setOverScrollMode(int) 2792 */ 2793 public static final int OVER_SCROLL_NEVER = 2; 2794 2795 /** 2796 * Special constant for {@link #setSystemUiVisibility(int)}: View has 2797 * requested the system UI (status bar) to be visible (the default). 2798 * 2799 * @see #setSystemUiVisibility(int) 2800 */ 2801 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 2802 2803 /** 2804 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 2805 * system UI to enter an unobtrusive "low profile" mode. 2806 * 2807 * <p>This is for use in games, book readers, video players, or any other 2808 * "immersive" application where the usual system chrome is deemed too distracting. 2809 * 2810 * <p>In low profile mode, the status bar and/or navigation icons may dim. 2811 * 2812 * @see #setSystemUiVisibility(int) 2813 */ 2814 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 2815 2816 /** 2817 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 2818 * system navigation be temporarily hidden. 2819 * 2820 * <p>This is an even less obtrusive state than that called for by 2821 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 2822 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 2823 * those to disappear. This is useful (in conjunction with the 2824 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 2825 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 2826 * window flags) for displaying content using every last pixel on the display. 2827 * 2828 * <p>There is a limitation: because navigation controls are so important, the least user 2829 * interaction will cause them to reappear immediately. When this happens, both 2830 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 2831 * so that both elements reappear at the same time. 2832 * 2833 * @see #setSystemUiVisibility(int) 2834 */ 2835 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 2836 2837 /** 2838 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 2839 * into the normal fullscreen mode so that its content can take over the screen 2840 * while still allowing the user to interact with the application. 2841 * 2842 * <p>This has the same visual effect as 2843 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 2844 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 2845 * meaning that non-critical screen decorations (such as the status bar) will be 2846 * hidden while the user is in the View's window, focusing the experience on 2847 * that content. Unlike the window flag, if you are using ActionBar in 2848 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2849 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 2850 * hide the action bar. 2851 * 2852 * <p>This approach to going fullscreen is best used over the window flag when 2853 * it is a transient state -- that is, the application does this at certain 2854 * points in its user interaction where it wants to allow the user to focus 2855 * on content, but not as a continuous state. For situations where the application 2856 * would like to simply stay full screen the entire time (such as a game that 2857 * wants to take over the screen), the 2858 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 2859 * is usually a better approach. The state set here will be removed by the system 2860 * in various situations (such as the user moving to another application) like 2861 * the other system UI states. 2862 * 2863 * <p>When using this flag, the application should provide some easy facility 2864 * for the user to go out of it. A common example would be in an e-book 2865 * reader, where tapping on the screen brings back whatever screen and UI 2866 * decorations that had been hidden while the user was immersed in reading 2867 * the book. 2868 * 2869 * @see #setSystemUiVisibility(int) 2870 */ 2871 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 2872 2873 /** 2874 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 2875 * flags, we would like a stable view of the content insets given to 2876 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 2877 * will always represent the worst case that the application can expect 2878 * as a continuous state. In the stock Android UI this is the space for 2879 * the system bar, nav bar, and status bar, but not more transient elements 2880 * such as an input method. 2881 * 2882 * The stable layout your UI sees is based on the system UI modes you can 2883 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 2884 * then you will get a stable layout for changes of the 2885 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 2886 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 2887 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 2888 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 2889 * with a stable layout. (Note that you should avoid using 2890 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 2891 * 2892 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 2893 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 2894 * then a hidden status bar will be considered a "stable" state for purposes 2895 * here. This allows your UI to continually hide the status bar, while still 2896 * using the system UI flags to hide the action bar while still retaining 2897 * a stable layout. Note that changing the window fullscreen flag will never 2898 * provide a stable layout for a clean transition. 2899 * 2900 * <p>If you are using ActionBar in 2901 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2902 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 2903 * insets it adds to those given to the application. 2904 */ 2905 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 2906 2907 /** 2908 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2909 * to be laid out as if it has requested 2910 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 2911 * allows it to avoid artifacts when switching in and out of that mode, at 2912 * the expense that some of its user interface may be covered by screen 2913 * decorations when they are shown. You can perform layout of your inner 2914 * UI elements to account for the navigation system UI through the 2915 * {@link #fitSystemWindows(Rect)} method. 2916 */ 2917 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 2918 2919 /** 2920 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2921 * to be laid out as if it has requested 2922 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 2923 * allows it to avoid artifacts when switching in and out of that mode, at 2924 * the expense that some of its user interface may be covered by screen 2925 * decorations when they are shown. You can perform layout of your inner 2926 * UI elements to account for non-fullscreen system UI through the 2927 * {@link #fitSystemWindows(Rect)} method. 2928 */ 2929 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 2930 2931 /** 2932 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2933 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 2934 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 2935 * user interaction. 2936 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 2937 * has an effect when used in combination with that flag.</p> 2938 */ 2939 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 2940 2941 /** 2942 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2943 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 2944 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 2945 * experience while also hiding the system bars. If this flag is not set, 2946 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 2947 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 2948 * if the user swipes from the top of the screen. 2949 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 2950 * system gestures, such as swiping from the top of the screen. These transient system bars 2951 * will overlay app’s content, may have some degree of transparency, and will automatically 2952 * hide after a short timeout. 2953 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 2954 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 2955 * with one or both of those flags.</p> 2956 */ 2957 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 2958 2959 /** 2960 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 2961 * is compatible with light status bar backgrounds. 2962 * 2963 * <p>For this to take effect, the window must request 2964 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2965 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2966 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 2967 * FLAG_TRANSLUCENT_STATUS}. 2968 * 2969 * @see android.R.attr#windowLightStatusBar 2970 */ 2971 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 2972 2973 /** 2974 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 2975 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 2976 */ 2977 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 2978 2979 /** 2980 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 2981 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 2982 */ 2983 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 2984 2985 /** 2986 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 2987 * that is compatible with light navigation bar backgrounds. 2988 * 2989 * <p>For this to take effect, the window must request 2990 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2991 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2992 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 2993 * FLAG_TRANSLUCENT_NAVIGATION}. 2994 */ 2995 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 2996 2997 /** 2998 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 2999 */ 3000 @Deprecated 3001 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3002 3003 /** 3004 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3005 */ 3006 @Deprecated 3007 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3008 3009 /** 3010 * @hide 3011 * 3012 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3013 * out of the public fields to keep the undefined bits out of the developer's way. 3014 * 3015 * Flag to make the status bar not expandable. Unless you also 3016 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3017 */ 3018 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3019 3020 /** 3021 * @hide 3022 * 3023 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3024 * out of the public fields to keep the undefined bits out of the developer's way. 3025 * 3026 * Flag to hide notification icons and scrolling ticker text. 3027 */ 3028 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3029 3030 /** 3031 * @hide 3032 * 3033 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3034 * out of the public fields to keep the undefined bits out of the developer's way. 3035 * 3036 * Flag to disable incoming notification alerts. This will not block 3037 * icons, but it will block sound, vibrating and other visual or aural notifications. 3038 */ 3039 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3040 3041 /** 3042 * @hide 3043 * 3044 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3045 * out of the public fields to keep the undefined bits out of the developer's way. 3046 * 3047 * Flag to hide only the scrolling ticker. Note that 3048 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3049 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3050 */ 3051 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3052 3053 /** 3054 * @hide 3055 * 3056 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3057 * out of the public fields to keep the undefined bits out of the developer's way. 3058 * 3059 * Flag to hide the center system info area. 3060 */ 3061 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3062 3063 /** 3064 * @hide 3065 * 3066 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3067 * out of the public fields to keep the undefined bits out of the developer's way. 3068 * 3069 * Flag to hide only the home button. Don't use this 3070 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3071 */ 3072 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3073 3074 /** 3075 * @hide 3076 * 3077 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3078 * out of the public fields to keep the undefined bits out of the developer's way. 3079 * 3080 * Flag to hide only the back button. Don't use this 3081 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3082 */ 3083 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3084 3085 /** 3086 * @hide 3087 * 3088 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3089 * out of the public fields to keep the undefined bits out of the developer's way. 3090 * 3091 * Flag to hide only the clock. You might use this if your activity has 3092 * its own clock making the status bar's clock redundant. 3093 */ 3094 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3095 3096 /** 3097 * @hide 3098 * 3099 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3100 * out of the public fields to keep the undefined bits out of the developer's way. 3101 * 3102 * Flag to hide only the recent apps button. Don't use this 3103 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3104 */ 3105 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3106 3107 /** 3108 * @hide 3109 * 3110 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3111 * out of the public fields to keep the undefined bits out of the developer's way. 3112 * 3113 * Flag to disable the global search gesture. Don't use this 3114 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3115 */ 3116 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3117 3118 /** 3119 * @hide 3120 * 3121 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3122 * out of the public fields to keep the undefined bits out of the developer's way. 3123 * 3124 * Flag to specify that the status bar is displayed in transient mode. 3125 */ 3126 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3127 3128 /** 3129 * @hide 3130 * 3131 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3132 * out of the public fields to keep the undefined bits out of the developer's way. 3133 * 3134 * Flag to specify that the navigation bar is displayed in transient mode. 3135 */ 3136 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3137 3138 /** 3139 * @hide 3140 * 3141 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3142 * out of the public fields to keep the undefined bits out of the developer's way. 3143 * 3144 * Flag to specify that the hidden status bar would like to be shown. 3145 */ 3146 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3147 3148 /** 3149 * @hide 3150 * 3151 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3152 * out of the public fields to keep the undefined bits out of the developer's way. 3153 * 3154 * Flag to specify that the hidden navigation bar would like to be shown. 3155 */ 3156 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3157 3158 /** 3159 * @hide 3160 * 3161 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3162 * out of the public fields to keep the undefined bits out of the developer's way. 3163 * 3164 * Flag to specify that the status bar is displayed in translucent mode. 3165 */ 3166 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3167 3168 /** 3169 * @hide 3170 * 3171 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3172 * out of the public fields to keep the undefined bits out of the developer's way. 3173 * 3174 * Flag to specify that the navigation bar is displayed in translucent mode. 3175 */ 3176 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3177 3178 /** 3179 * @hide 3180 * 3181 * Makes navigation bar transparent (but not the status bar). 3182 */ 3183 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3184 3185 /** 3186 * @hide 3187 * 3188 * Makes status bar transparent (but not the navigation bar). 3189 */ 3190 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3191 3192 /** 3193 * @hide 3194 * 3195 * Makes both status bar and navigation bar transparent. 3196 */ 3197 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3198 | STATUS_BAR_TRANSPARENT; 3199 3200 /** 3201 * @hide 3202 */ 3203 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3204 3205 /** 3206 * These are the system UI flags that can be cleared by events outside 3207 * of an application. Currently this is just the ability to tap on the 3208 * screen while hiding the navigation bar to have it return. 3209 * @hide 3210 */ 3211 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3212 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3213 | SYSTEM_UI_FLAG_FULLSCREEN; 3214 3215 /** 3216 * Flags that can impact the layout in relation to system UI. 3217 */ 3218 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3219 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3220 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3221 3222 /** @hide */ 3223 @IntDef(flag = true, 3224 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3225 @Retention(RetentionPolicy.SOURCE) 3226 public @interface FindViewFlags {} 3227 3228 /** 3229 * Find views that render the specified text. 3230 * 3231 * @see #findViewsWithText(ArrayList, CharSequence, int) 3232 */ 3233 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3234 3235 /** 3236 * Find find views that contain the specified content description. 3237 * 3238 * @see #findViewsWithText(ArrayList, CharSequence, int) 3239 */ 3240 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3241 3242 /** 3243 * Find views that contain {@link AccessibilityNodeProvider}. Such 3244 * a View is a root of virtual view hierarchy and may contain the searched 3245 * text. If this flag is set Views with providers are automatically 3246 * added and it is a responsibility of the client to call the APIs of 3247 * the provider to determine whether the virtual tree rooted at this View 3248 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3249 * representing the virtual views with this text. 3250 * 3251 * @see #findViewsWithText(ArrayList, CharSequence, int) 3252 * 3253 * @hide 3254 */ 3255 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3256 3257 /** 3258 * The undefined cursor position. 3259 * 3260 * @hide 3261 */ 3262 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3263 3264 /** 3265 * Indicates that the screen has changed state and is now off. 3266 * 3267 * @see #onScreenStateChanged(int) 3268 */ 3269 public static final int SCREEN_STATE_OFF = 0x0; 3270 3271 /** 3272 * Indicates that the screen has changed state and is now on. 3273 * 3274 * @see #onScreenStateChanged(int) 3275 */ 3276 public static final int SCREEN_STATE_ON = 0x1; 3277 3278 /** 3279 * Indicates no axis of view scrolling. 3280 */ 3281 public static final int SCROLL_AXIS_NONE = 0; 3282 3283 /** 3284 * Indicates scrolling along the horizontal axis. 3285 */ 3286 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3287 3288 /** 3289 * Indicates scrolling along the vertical axis. 3290 */ 3291 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3292 3293 /** 3294 * Controls the over-scroll mode for this view. 3295 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3296 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3297 * and {@link #OVER_SCROLL_NEVER}. 3298 */ 3299 private int mOverScrollMode; 3300 3301 /** 3302 * The parent this view is attached to. 3303 * {@hide} 3304 * 3305 * @see #getParent() 3306 */ 3307 protected ViewParent mParent; 3308 3309 /** 3310 * {@hide} 3311 */ 3312 AttachInfo mAttachInfo; 3313 3314 /** 3315 * {@hide} 3316 */ 3317 @ViewDebug.ExportedProperty(flagMapping = { 3318 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3319 name = "FORCE_LAYOUT"), 3320 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3321 name = "LAYOUT_REQUIRED"), 3322 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3323 name = "DRAWING_CACHE_INVALID", outputIf = false), 3324 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3325 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3326 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3327 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3328 }, formatToHexString = true) 3329 3330 /* @hide */ 3331 public int mPrivateFlags; 3332 int mPrivateFlags2; 3333 int mPrivateFlags3; 3334 3335 /** 3336 * This view's request for the visibility of the status bar. 3337 * @hide 3338 */ 3339 @ViewDebug.ExportedProperty(flagMapping = { 3340 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3341 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3342 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3343 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3344 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3345 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3346 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3347 equals = SYSTEM_UI_FLAG_VISIBLE, 3348 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3349 }, formatToHexString = true) 3350 int mSystemUiVisibility; 3351 3352 /** 3353 * Reference count for transient state. 3354 * @see #setHasTransientState(boolean) 3355 */ 3356 int mTransientStateCount = 0; 3357 3358 /** 3359 * Count of how many windows this view has been attached to. 3360 */ 3361 int mWindowAttachCount; 3362 3363 /** 3364 * The layout parameters associated with this view and used by the parent 3365 * {@link android.view.ViewGroup} to determine how this view should be 3366 * laid out. 3367 * {@hide} 3368 */ 3369 protected ViewGroup.LayoutParams mLayoutParams; 3370 3371 /** 3372 * The view flags hold various views states. 3373 * {@hide} 3374 */ 3375 @ViewDebug.ExportedProperty(formatToHexString = true) 3376 int mViewFlags; 3377 3378 static class TransformationInfo { 3379 /** 3380 * The transform matrix for the View. This transform is calculated internally 3381 * based on the translation, rotation, and scale properties. 3382 * 3383 * Do *not* use this variable directly; instead call getMatrix(), which will 3384 * load the value from the View's RenderNode. 3385 */ 3386 private final Matrix mMatrix = new Matrix(); 3387 3388 /** 3389 * The inverse transform matrix for the View. This transform is calculated 3390 * internally based on the translation, rotation, and scale properties. 3391 * 3392 * Do *not* use this variable directly; instead call getInverseMatrix(), 3393 * which will load the value from the View's RenderNode. 3394 */ 3395 private Matrix mInverseMatrix; 3396 3397 /** 3398 * The opacity of the View. This is a value from 0 to 1, where 0 means 3399 * completely transparent and 1 means completely opaque. 3400 */ 3401 @ViewDebug.ExportedProperty 3402 float mAlpha = 1f; 3403 3404 /** 3405 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3406 * property only used by transitions, which is composited with the other alpha 3407 * values to calculate the final visual alpha value. 3408 */ 3409 float mTransitionAlpha = 1f; 3410 } 3411 3412 /** @hide */ 3413 public TransformationInfo mTransformationInfo; 3414 3415 /** 3416 * Current clip bounds. to which all drawing of this view are constrained. 3417 */ 3418 Rect mClipBounds = null; 3419 3420 private boolean mLastIsOpaque; 3421 3422 /** 3423 * The distance in pixels from the left edge of this view's parent 3424 * to the left edge of this view. 3425 * {@hide} 3426 */ 3427 @ViewDebug.ExportedProperty(category = "layout") 3428 protected int mLeft; 3429 /** 3430 * The distance in pixels from the left edge of this view's parent 3431 * to the right edge of this view. 3432 * {@hide} 3433 */ 3434 @ViewDebug.ExportedProperty(category = "layout") 3435 protected int mRight; 3436 /** 3437 * The distance in pixels from the top edge of this view's parent 3438 * to the top edge of this view. 3439 * {@hide} 3440 */ 3441 @ViewDebug.ExportedProperty(category = "layout") 3442 protected int mTop; 3443 /** 3444 * The distance in pixels from the top edge of this view's parent 3445 * to the bottom edge of this view. 3446 * {@hide} 3447 */ 3448 @ViewDebug.ExportedProperty(category = "layout") 3449 protected int mBottom; 3450 3451 /** 3452 * The offset, in pixels, by which the content of this view is scrolled 3453 * horizontally. 3454 * {@hide} 3455 */ 3456 @ViewDebug.ExportedProperty(category = "scrolling") 3457 protected int mScrollX; 3458 /** 3459 * The offset, in pixels, by which the content of this view is scrolled 3460 * vertically. 3461 * {@hide} 3462 */ 3463 @ViewDebug.ExportedProperty(category = "scrolling") 3464 protected int mScrollY; 3465 3466 /** 3467 * The left padding in pixels, that is the distance in pixels between the 3468 * left edge of this view and the left edge of its content. 3469 * {@hide} 3470 */ 3471 @ViewDebug.ExportedProperty(category = "padding") 3472 protected int mPaddingLeft = 0; 3473 /** 3474 * The right padding in pixels, that is the distance in pixels between the 3475 * right edge of this view and the right edge of its content. 3476 * {@hide} 3477 */ 3478 @ViewDebug.ExportedProperty(category = "padding") 3479 protected int mPaddingRight = 0; 3480 /** 3481 * The top padding in pixels, that is the distance in pixels between the 3482 * top edge of this view and the top edge of its content. 3483 * {@hide} 3484 */ 3485 @ViewDebug.ExportedProperty(category = "padding") 3486 protected int mPaddingTop; 3487 /** 3488 * The bottom padding in pixels, that is the distance in pixels between the 3489 * bottom edge of this view and the bottom edge of its content. 3490 * {@hide} 3491 */ 3492 @ViewDebug.ExportedProperty(category = "padding") 3493 protected int mPaddingBottom; 3494 3495 /** 3496 * The layout insets in pixels, that is the distance in pixels between the 3497 * visible edges of this view its bounds. 3498 */ 3499 private Insets mLayoutInsets; 3500 3501 /** 3502 * Briefly describes the view and is primarily used for accessibility support. 3503 */ 3504 private CharSequence mContentDescription; 3505 3506 /** 3507 * Specifies the id of a view for which this view serves as a label for 3508 * accessibility purposes. 3509 */ 3510 private int mLabelForId = View.NO_ID; 3511 3512 /** 3513 * Predicate for matching labeled view id with its label for 3514 * accessibility purposes. 3515 */ 3516 private MatchLabelForPredicate mMatchLabelForPredicate; 3517 3518 /** 3519 * Specifies a view before which this one is visited in accessibility traversal. 3520 */ 3521 private int mAccessibilityTraversalBeforeId = NO_ID; 3522 3523 /** 3524 * Specifies a view after which this one is visited in accessibility traversal. 3525 */ 3526 private int mAccessibilityTraversalAfterId = NO_ID; 3527 3528 /** 3529 * Predicate for matching a view by its id. 3530 */ 3531 private MatchIdPredicate mMatchIdPredicate; 3532 3533 /** 3534 * Cache the paddingRight set by the user to append to the scrollbar's size. 3535 * 3536 * @hide 3537 */ 3538 @ViewDebug.ExportedProperty(category = "padding") 3539 protected int mUserPaddingRight; 3540 3541 /** 3542 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3543 * 3544 * @hide 3545 */ 3546 @ViewDebug.ExportedProperty(category = "padding") 3547 protected int mUserPaddingBottom; 3548 3549 /** 3550 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3551 * 3552 * @hide 3553 */ 3554 @ViewDebug.ExportedProperty(category = "padding") 3555 protected int mUserPaddingLeft; 3556 3557 /** 3558 * Cache the paddingStart set by the user to append to the scrollbar's size. 3559 * 3560 */ 3561 @ViewDebug.ExportedProperty(category = "padding") 3562 int mUserPaddingStart; 3563 3564 /** 3565 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3566 * 3567 */ 3568 @ViewDebug.ExportedProperty(category = "padding") 3569 int mUserPaddingEnd; 3570 3571 /** 3572 * Cache initial left padding. 3573 * 3574 * @hide 3575 */ 3576 int mUserPaddingLeftInitial; 3577 3578 /** 3579 * Cache initial right padding. 3580 * 3581 * @hide 3582 */ 3583 int mUserPaddingRightInitial; 3584 3585 /** 3586 * Default undefined padding 3587 */ 3588 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3589 3590 /** 3591 * Cache if a left padding has been defined 3592 */ 3593 private boolean mLeftPaddingDefined = false; 3594 3595 /** 3596 * Cache if a right padding has been defined 3597 */ 3598 private boolean mRightPaddingDefined = false; 3599 3600 /** 3601 * @hide 3602 */ 3603 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3604 /** 3605 * @hide 3606 */ 3607 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3608 3609 private LongSparseLongArray mMeasureCache; 3610 3611 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3612 private Drawable mBackground; 3613 private TintInfo mBackgroundTint; 3614 3615 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3616 private ForegroundInfo mForegroundInfo; 3617 3618 private Drawable mScrollIndicatorDrawable; 3619 3620 /** 3621 * RenderNode used for backgrounds. 3622 * <p> 3623 * When non-null and valid, this is expected to contain an up-to-date copy 3624 * of the background drawable. It is cleared on temporary detach, and reset 3625 * on cleanup. 3626 */ 3627 private RenderNode mBackgroundRenderNode; 3628 3629 private int mBackgroundResource; 3630 private boolean mBackgroundSizeChanged; 3631 3632 private String mTransitionName; 3633 3634 static class TintInfo { 3635 ColorStateList mTintList; 3636 PorterDuff.Mode mTintMode; 3637 boolean mHasTintMode; 3638 boolean mHasTintList; 3639 } 3640 3641 private static class ForegroundInfo { 3642 private Drawable mDrawable; 3643 private TintInfo mTintInfo; 3644 private int mGravity = Gravity.FILL; 3645 private boolean mInsidePadding = true; 3646 private boolean mBoundsChanged = true; 3647 private final Rect mSelfBounds = new Rect(); 3648 private final Rect mOverlayBounds = new Rect(); 3649 } 3650 3651 static class ListenerInfo { 3652 /** 3653 * Listener used to dispatch focus change events. 3654 * This field should be made private, so it is hidden from the SDK. 3655 * {@hide} 3656 */ 3657 protected OnFocusChangeListener mOnFocusChangeListener; 3658 3659 /** 3660 * Listeners for layout change events. 3661 */ 3662 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 3663 3664 protected OnScrollChangeListener mOnScrollChangeListener; 3665 3666 /** 3667 * Listeners for attach events. 3668 */ 3669 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 3670 3671 /** 3672 * Listener used to dispatch click events. 3673 * This field should be made private, so it is hidden from the SDK. 3674 * {@hide} 3675 */ 3676 public OnClickListener mOnClickListener; 3677 3678 /** 3679 * Listener used to dispatch long click events. 3680 * This field should be made private, so it is hidden from the SDK. 3681 * {@hide} 3682 */ 3683 protected OnLongClickListener mOnLongClickListener; 3684 3685 /** 3686 * Listener used to dispatch context click events. This field should be made private, so it 3687 * is hidden from the SDK. 3688 * {@hide} 3689 */ 3690 protected OnContextClickListener mOnContextClickListener; 3691 3692 /** 3693 * Listener used to build the context menu. 3694 * This field should be made private, so it is hidden from the SDK. 3695 * {@hide} 3696 */ 3697 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 3698 3699 private OnKeyListener mOnKeyListener; 3700 3701 private OnTouchListener mOnTouchListener; 3702 3703 private OnHoverListener mOnHoverListener; 3704 3705 private OnGenericMotionListener mOnGenericMotionListener; 3706 3707 private OnDragListener mOnDragListener; 3708 3709 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 3710 3711 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 3712 } 3713 3714 ListenerInfo mListenerInfo; 3715 3716 private static class TooltipInfo { 3717 /** 3718 * Text to be displayed in a tooltip popup. 3719 */ 3720 @Nullable 3721 CharSequence mTooltipText; 3722 3723 /** 3724 * View-relative position of the tooltip anchor point. 3725 */ 3726 int mAnchorX; 3727 int mAnchorY; 3728 3729 /** 3730 * The tooltip popup. 3731 */ 3732 @Nullable 3733 TooltipPopup mTooltipPopup; 3734 3735 /** 3736 * Set to true if the tooltip was shown as a result of a long click. 3737 */ 3738 boolean mTooltipFromLongClick; 3739 3740 /** 3741 * Keep these Runnables so that they can be used to reschedule. 3742 */ 3743 Runnable mShowTooltipRunnable; 3744 Runnable mHideTooltipRunnable; 3745 } 3746 3747 TooltipInfo mTooltipInfo; 3748 3749 // Temporary values used to hold (x,y) coordinates when delegating from the 3750 // two-arg performLongClick() method to the legacy no-arg version. 3751 private float mLongClickX = Float.NaN; 3752 private float mLongClickY = Float.NaN; 3753 3754 /** 3755 * The application environment this view lives in. 3756 * This field should be made private, so it is hidden from the SDK. 3757 * {@hide} 3758 */ 3759 @ViewDebug.ExportedProperty(deepExport = true) 3760 protected Context mContext; 3761 3762 private final Resources mResources; 3763 3764 private ScrollabilityCache mScrollCache; 3765 3766 private int[] mDrawableState = null; 3767 3768 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 3769 3770 /** 3771 * Animator that automatically runs based on state changes. 3772 */ 3773 private StateListAnimator mStateListAnimator; 3774 3775 /** 3776 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 3777 * the user may specify which view to go to next. 3778 */ 3779 private int mNextFocusLeftId = View.NO_ID; 3780 3781 /** 3782 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 3783 * the user may specify which view to go to next. 3784 */ 3785 private int mNextFocusRightId = View.NO_ID; 3786 3787 /** 3788 * When this view has focus and the next focus is {@link #FOCUS_UP}, 3789 * the user may specify which view to go to next. 3790 */ 3791 private int mNextFocusUpId = View.NO_ID; 3792 3793 /** 3794 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 3795 * the user may specify which view to go to next. 3796 */ 3797 private int mNextFocusDownId = View.NO_ID; 3798 3799 /** 3800 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 3801 * the user may specify which view to go to next. 3802 */ 3803 int mNextFocusForwardId = View.NO_ID; 3804 3805 /** 3806 * User-specified next keyboard navigation cluster. 3807 */ 3808 int mNextClusterForwardId = View.NO_ID; 3809 3810 /** 3811 * User-specified next keyboard navigation section. 3812 */ 3813 int mNextSectionForwardId = View.NO_ID; 3814 3815 private CheckForLongPress mPendingCheckForLongPress; 3816 private CheckForTap mPendingCheckForTap = null; 3817 private PerformClick mPerformClick; 3818 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 3819 3820 private UnsetPressedState mUnsetPressedState; 3821 3822 /** 3823 * Whether the long press's action has been invoked. The tap's action is invoked on the 3824 * up event while a long press is invoked as soon as the long press duration is reached, so 3825 * a long press could be performed before the tap is checked, in which case the tap's action 3826 * should not be invoked. 3827 */ 3828 private boolean mHasPerformedLongPress; 3829 3830 /** 3831 * Whether a context click button is currently pressed down. This is true when the stylus is 3832 * touching the screen and the primary button has been pressed, or if a mouse's right button is 3833 * pressed. This is false once the button is released or if the stylus has been lifted. 3834 */ 3835 private boolean mInContextButtonPress; 3836 3837 /** 3838 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 3839 * true after a stylus button press has occured, when the next up event should not be recognized 3840 * as a tap. 3841 */ 3842 private boolean mIgnoreNextUpEvent; 3843 3844 /** 3845 * The minimum height of the view. We'll try our best to have the height 3846 * of this view to at least this amount. 3847 */ 3848 @ViewDebug.ExportedProperty(category = "measurement") 3849 private int mMinHeight; 3850 3851 /** 3852 * The minimum width of the view. We'll try our best to have the width 3853 * of this view to at least this amount. 3854 */ 3855 @ViewDebug.ExportedProperty(category = "measurement") 3856 private int mMinWidth; 3857 3858 /** 3859 * The delegate to handle touch events that are physically in this view 3860 * but should be handled by another view. 3861 */ 3862 private TouchDelegate mTouchDelegate = null; 3863 3864 /** 3865 * Solid color to use as a background when creating the drawing cache. Enables 3866 * the cache to use 16 bit bitmaps instead of 32 bit. 3867 */ 3868 private int mDrawingCacheBackgroundColor = 0; 3869 3870 /** 3871 * Special tree observer used when mAttachInfo is null. 3872 */ 3873 private ViewTreeObserver mFloatingTreeObserver; 3874 3875 /** 3876 * Cache the touch slop from the context that created the view. 3877 */ 3878 private int mTouchSlop; 3879 3880 /** 3881 * Object that handles automatic animation of view properties. 3882 */ 3883 private ViewPropertyAnimator mAnimator = null; 3884 3885 /** 3886 * List of registered FrameMetricsObservers. 3887 */ 3888 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 3889 3890 /** 3891 * Flag indicating that a drag can cross window boundaries. When 3892 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3893 * with this flag set, all visible applications with targetSdkVersion >= 3894 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 3895 * in the drag operation and receive the dragged content. 3896 * 3897 * <p>If this is the only flag set, then the drag recipient will only have access to text data 3898 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 3899 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 3900 */ 3901 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 3902 3903 /** 3904 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3905 * request read access to the content URI(s) contained in the {@link ClipData} object. 3906 * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION 3907 */ 3908 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 3909 3910 /** 3911 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3912 * request write access to the content URI(s) contained in the {@link ClipData} object. 3913 * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION 3914 */ 3915 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_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 can be persisted across device 3920 * reboots until explicitly revoked with 3921 * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}. 3922 * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION 3923 */ 3924 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 3925 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 3926 3927 /** 3928 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3929 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 3930 * match against the original granted URI. 3931 * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION 3932 */ 3933 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 3934 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 3935 3936 /** 3937 * Flag indicating that the drag shadow will be opaque. When 3938 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3939 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 3940 */ 3941 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 3942 3943 /** 3944 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 3945 */ 3946 private float mVerticalScrollFactor; 3947 3948 /** 3949 * Position of the vertical scroll bar. 3950 */ 3951 private int mVerticalScrollbarPosition; 3952 3953 /** 3954 * Position the scroll bar at the default position as determined by the system. 3955 */ 3956 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 3957 3958 /** 3959 * Position the scroll bar along the left edge. 3960 */ 3961 public static final int SCROLLBAR_POSITION_LEFT = 1; 3962 3963 /** 3964 * Position the scroll bar along the right edge. 3965 */ 3966 public static final int SCROLLBAR_POSITION_RIGHT = 2; 3967 3968 /** 3969 * Indicates that the view does not have a layer. 3970 * 3971 * @see #getLayerType() 3972 * @see #setLayerType(int, android.graphics.Paint) 3973 * @see #LAYER_TYPE_SOFTWARE 3974 * @see #LAYER_TYPE_HARDWARE 3975 */ 3976 public static final int LAYER_TYPE_NONE = 0; 3977 3978 /** 3979 * <p>Indicates that the view has a software layer. A software layer is backed 3980 * by a bitmap and causes the view to be rendered using Android's software 3981 * rendering pipeline, even if hardware acceleration is enabled.</p> 3982 * 3983 * <p>Software layers have various usages:</p> 3984 * <p>When the application is not using hardware acceleration, a software layer 3985 * is useful to apply a specific color filter and/or blending mode and/or 3986 * translucency to a view and all its children.</p> 3987 * <p>When the application is using hardware acceleration, a software layer 3988 * is useful to render drawing primitives not supported by the hardware 3989 * accelerated pipeline. It can also be used to cache a complex view tree 3990 * into a texture and reduce the complexity of drawing operations. For instance, 3991 * when animating a complex view tree with a translation, a software layer can 3992 * be used to render the view tree only once.</p> 3993 * <p>Software layers should be avoided when the affected view tree updates 3994 * often. Every update will require to re-render the software layer, which can 3995 * potentially be slow (particularly when hardware acceleration is turned on 3996 * since the layer will have to be uploaded into a hardware texture after every 3997 * update.)</p> 3998 * 3999 * @see #getLayerType() 4000 * @see #setLayerType(int, android.graphics.Paint) 4001 * @see #LAYER_TYPE_NONE 4002 * @see #LAYER_TYPE_HARDWARE 4003 */ 4004 public static final int LAYER_TYPE_SOFTWARE = 1; 4005 4006 /** 4007 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4008 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4009 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4010 * rendering pipeline, but only if hardware acceleration is turned on for the 4011 * view hierarchy. When hardware acceleration is turned off, hardware layers 4012 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4013 * 4014 * <p>A hardware layer is useful to apply a specific color filter and/or 4015 * blending mode and/or translucency to a view and all its children.</p> 4016 * <p>A hardware layer can be used to cache a complex view tree into a 4017 * texture and reduce the complexity of drawing operations. For instance, 4018 * when animating a complex view tree with a translation, a hardware layer can 4019 * be used to render the view tree only once.</p> 4020 * <p>A hardware layer can also be used to increase the rendering quality when 4021 * rotation transformations are applied on a view. It can also be used to 4022 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4023 * 4024 * @see #getLayerType() 4025 * @see #setLayerType(int, android.graphics.Paint) 4026 * @see #LAYER_TYPE_NONE 4027 * @see #LAYER_TYPE_SOFTWARE 4028 */ 4029 public static final int LAYER_TYPE_HARDWARE = 2; 4030 4031 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4032 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4033 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4034 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4035 }) 4036 int mLayerType = LAYER_TYPE_NONE; 4037 Paint mLayerPaint; 4038 4039 4040 /** 4041 * Set when a request was made to decide if views in an {@link android.app.Activity} can be 4042 * auto-filled by an {@link android.service.autofill.AutoFillService}. 4043 * 4044 * <p>Since this request is made without a explicit user consent, the resulting 4045 * {@link android.app.assist.AssistStructure} should not contain any PII 4046 * (Personally Identifiable Information). 4047 * 4048 * <p>Examples: 4049 * <ul> 4050 * <li>{@link android.widget.TextView} texts should only be included when they were set by 4051 * static resources. 4052 * <li>{@link android.webkit.WebView} virtual children should be restricted to a subset of 4053 * input fields and tags (like {@code id}). 4054 * </ul> 4055 */ 4056 // TODO(b/33197203) (b/34078930): improve documentation: mention all cases, show examples, etc. 4057 // In particular, be more specific about webview restrictions 4058 public static final int AUTO_FILL_FLAG_TYPE_FILL = 0x1; 4059 4060 /** 4061 * Set when the user explicitly asked a {@link android.service.autofill.AutoFillService} to save 4062 * the value of the {@link View}s in an {@link android.app.Activity}. 4063 * 4064 * <p>The resulting {@link android.app.assist.AssistStructure} can contain any kind of PII 4065 * (Personally Identifiable Information). For example, the text of password fields should be 4066 * included since that's what's typically saved. 4067 */ 4068 public static final int AUTO_FILL_FLAG_TYPE_SAVE = 0x2; 4069 4070 /** 4071 * Set to true when drawing cache is enabled and cannot be created. 4072 * 4073 * @hide 4074 */ 4075 public boolean mCachingFailed; 4076 private Bitmap mDrawingCache; 4077 private Bitmap mUnscaledDrawingCache; 4078 4079 /** 4080 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4081 * <p> 4082 * When non-null and valid, this is expected to contain an up-to-date copy 4083 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4084 * cleanup. 4085 */ 4086 final RenderNode mRenderNode; 4087 4088 /** 4089 * Set to true when the view is sending hover accessibility events because it 4090 * is the innermost hovered view. 4091 */ 4092 private boolean mSendingHoverAccessibilityEvents; 4093 4094 /** 4095 * Delegate for injecting accessibility functionality. 4096 */ 4097 AccessibilityDelegate mAccessibilityDelegate; 4098 4099 /** 4100 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4101 * and add/remove objects to/from the overlay directly through the Overlay methods. 4102 */ 4103 ViewOverlay mOverlay; 4104 4105 /** 4106 * The currently active parent view for receiving delegated nested scrolling events. 4107 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4108 * by {@link #stopNestedScroll()} at the same point where we clear 4109 * requestDisallowInterceptTouchEvent. 4110 */ 4111 private ViewParent mNestedScrollingParent; 4112 4113 /** 4114 * Consistency verifier for debugging purposes. 4115 * @hide 4116 */ 4117 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4118 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4119 new InputEventConsistencyVerifier(this, 0) : null; 4120 4121 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4122 4123 private int[] mTempNestedScrollConsumed; 4124 4125 /** 4126 * An overlay is going to draw this View instead of being drawn as part of this 4127 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4128 * when this view is invalidated. 4129 */ 4130 GhostView mGhostView; 4131 4132 /** 4133 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4134 * @hide 4135 */ 4136 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4137 public String[] mAttributes; 4138 4139 /** 4140 * Maps a Resource id to its name. 4141 */ 4142 private static SparseArray<String> mAttributeMap; 4143 4144 /** 4145 * Queue of pending runnables. Used to postpone calls to post() until this 4146 * view is attached and has a handler. 4147 */ 4148 private HandlerActionQueue mRunQueue; 4149 4150 /** 4151 * The pointer icon when the mouse hovers on this view. The default is null. 4152 */ 4153 private PointerIcon mPointerIcon; 4154 4155 /** 4156 * @hide 4157 */ 4158 String mStartActivityRequestWho; 4159 4160 @Nullable 4161 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4162 4163 /** 4164 * Simple constructor to use when creating a view from code. 4165 * 4166 * @param context The Context the view is running in, through which it can 4167 * access the current theme, resources, etc. 4168 */ 4169 public View(Context context) { 4170 mContext = context; 4171 mResources = context != null ? context.getResources() : null; 4172 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED; 4173 // Set some flags defaults 4174 mPrivateFlags2 = 4175 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4176 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4177 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4178 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4179 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4180 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4181 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4182 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4183 mUserPaddingStart = UNDEFINED_PADDING; 4184 mUserPaddingEnd = UNDEFINED_PADDING; 4185 mRenderNode = RenderNode.create(getClass().getName(), this); 4186 4187 if (!sCompatibilityDone && context != null) { 4188 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4189 4190 // Older apps may need this compatibility hack for measurement. 4191 sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1; 4192 4193 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4194 // of whether a layout was requested on that View. 4195 sIgnoreMeasureCache = targetSdkVersion < KITKAT; 4196 4197 Canvas.sCompatibilityRestore = targetSdkVersion < M; 4198 4199 // In M and newer, our widgets can pass a "hint" value in the size 4200 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4201 // know what the expected parent size is going to be, so e.g. list items can size 4202 // themselves at 1/3 the size of their container. It breaks older apps though, 4203 // specifically apps that use some popular open source libraries. 4204 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < M; 4205 4206 // Old versions of the platform would give different results from 4207 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4208 // modes, so we always need to run an additional EXACTLY pass. 4209 sAlwaysRemeasureExactly = targetSdkVersion <= M; 4210 4211 // Prior to N, layout params could change without requiring a 4212 // subsequent call to setLayoutParams() and they would usually 4213 // work. Partial layout breaks this assumption. 4214 sLayoutParamsAlwaysChanged = targetSdkVersion <= M; 4215 4216 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4217 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4218 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M; 4219 4220 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4221 // in apps so we target check it to avoid breaking existing apps. 4222 sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N; 4223 4224 sCascadedDragDrop = targetSdkVersion < N; 4225 4226 sCompatibilityDone = true; 4227 } 4228 } 4229 4230 /** 4231 * Constructor that is called when inflating a view from XML. This is called 4232 * when a view is being constructed from an XML file, supplying attributes 4233 * that were specified in the XML file. This version uses a default style of 4234 * 0, so the only attribute values applied are those in the Context's Theme 4235 * and the given AttributeSet. 4236 * 4237 * <p> 4238 * The method onFinishInflate() will be called after all children have been 4239 * added. 4240 * 4241 * @param context The Context the view is running in, through which it can 4242 * access the current theme, resources, etc. 4243 * @param attrs The attributes of the XML tag that is inflating the view. 4244 * @see #View(Context, AttributeSet, int) 4245 */ 4246 public View(Context context, @Nullable AttributeSet attrs) { 4247 this(context, attrs, 0); 4248 } 4249 4250 /** 4251 * Perform inflation from XML and apply a class-specific base style from a 4252 * theme attribute. This constructor of View allows subclasses to use their 4253 * own base style when they are inflating. For example, a Button class's 4254 * constructor would call this version of the super class constructor and 4255 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4256 * allows the theme's button style to modify all of the base view attributes 4257 * (in particular its background) as well as the Button class's attributes. 4258 * 4259 * @param context The Context the view is running in, through which it can 4260 * access the current theme, resources, etc. 4261 * @param attrs The attributes of the XML tag that is inflating the view. 4262 * @param defStyleAttr An attribute in the current theme that contains a 4263 * reference to a style resource that supplies default values for 4264 * the view. Can be 0 to not look for defaults. 4265 * @see #View(Context, AttributeSet) 4266 */ 4267 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4268 this(context, attrs, defStyleAttr, 0); 4269 } 4270 4271 /** 4272 * Perform inflation from XML and apply a class-specific base style from a 4273 * theme attribute or style resource. This constructor of View allows 4274 * subclasses to use their own base style when they are inflating. 4275 * <p> 4276 * When determining the final value of a particular attribute, there are 4277 * four inputs that come into play: 4278 * <ol> 4279 * <li>Any attribute values in the given AttributeSet. 4280 * <li>The style resource specified in the AttributeSet (named "style"). 4281 * <li>The default style specified by <var>defStyleAttr</var>. 4282 * <li>The default style specified by <var>defStyleRes</var>. 4283 * <li>The base values in this theme. 4284 * </ol> 4285 * <p> 4286 * Each of these inputs is considered in-order, with the first listed taking 4287 * precedence over the following ones. In other words, if in the 4288 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4289 * , then the button's text will <em>always</em> be black, regardless of 4290 * what is specified in any of the styles. 4291 * 4292 * @param context The Context the view is running in, through which it can 4293 * access the current theme, resources, etc. 4294 * @param attrs The attributes of the XML tag that is inflating the view. 4295 * @param defStyleAttr An attribute in the current theme that contains a 4296 * reference to a style resource that supplies default values for 4297 * the view. Can be 0 to not look for defaults. 4298 * @param defStyleRes A resource identifier of a style resource that 4299 * supplies default values for the view, used only if 4300 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4301 * to not look for defaults. 4302 * @see #View(Context, AttributeSet, int) 4303 */ 4304 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4305 this(context); 4306 4307 final TypedArray a = context.obtainStyledAttributes( 4308 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4309 4310 if (mDebugViewAttributes) { 4311 saveAttributeData(attrs, a); 4312 } 4313 4314 Drawable background = null; 4315 4316 int leftPadding = -1; 4317 int topPadding = -1; 4318 int rightPadding = -1; 4319 int bottomPadding = -1; 4320 int startPadding = UNDEFINED_PADDING; 4321 int endPadding = UNDEFINED_PADDING; 4322 4323 int padding = -1; 4324 int paddingHorizontal = -1; 4325 int paddingVertical = -1; 4326 4327 int viewFlagValues = 0; 4328 int viewFlagMasks = 0; 4329 4330 boolean setScrollContainer = false; 4331 4332 int x = 0; 4333 int y = 0; 4334 4335 float tx = 0; 4336 float ty = 0; 4337 float tz = 0; 4338 float elevation = 0; 4339 float rotation = 0; 4340 float rotationX = 0; 4341 float rotationY = 0; 4342 float sx = 1f; 4343 float sy = 1f; 4344 boolean transformSet = false; 4345 4346 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4347 int overScrollMode = mOverScrollMode; 4348 boolean initializeScrollbars = false; 4349 boolean initializeScrollIndicators = false; 4350 4351 boolean startPaddingDefined = false; 4352 boolean endPaddingDefined = false; 4353 boolean leftPaddingDefined = false; 4354 boolean rightPaddingDefined = false; 4355 4356 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4357 4358 final int N = a.getIndexCount(); 4359 for (int i = 0; i < N; i++) { 4360 int attr = a.getIndex(i); 4361 switch (attr) { 4362 case com.android.internal.R.styleable.View_background: 4363 background = a.getDrawable(attr); 4364 break; 4365 case com.android.internal.R.styleable.View_padding: 4366 padding = a.getDimensionPixelSize(attr, -1); 4367 mUserPaddingLeftInitial = padding; 4368 mUserPaddingRightInitial = padding; 4369 leftPaddingDefined = true; 4370 rightPaddingDefined = true; 4371 break; 4372 case com.android.internal.R.styleable.View_paddingHorizontal: 4373 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4374 mUserPaddingLeftInitial = paddingHorizontal; 4375 mUserPaddingRightInitial = paddingHorizontal; 4376 leftPaddingDefined = true; 4377 rightPaddingDefined = true; 4378 break; 4379 case com.android.internal.R.styleable.View_paddingVertical: 4380 paddingVertical = a.getDimensionPixelSize(attr, -1); 4381 break; 4382 case com.android.internal.R.styleable.View_paddingLeft: 4383 leftPadding = a.getDimensionPixelSize(attr, -1); 4384 mUserPaddingLeftInitial = leftPadding; 4385 leftPaddingDefined = true; 4386 break; 4387 case com.android.internal.R.styleable.View_paddingTop: 4388 topPadding = a.getDimensionPixelSize(attr, -1); 4389 break; 4390 case com.android.internal.R.styleable.View_paddingRight: 4391 rightPadding = a.getDimensionPixelSize(attr, -1); 4392 mUserPaddingRightInitial = rightPadding; 4393 rightPaddingDefined = true; 4394 break; 4395 case com.android.internal.R.styleable.View_paddingBottom: 4396 bottomPadding = a.getDimensionPixelSize(attr, -1); 4397 break; 4398 case com.android.internal.R.styleable.View_paddingStart: 4399 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4400 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4401 break; 4402 case com.android.internal.R.styleable.View_paddingEnd: 4403 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4404 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4405 break; 4406 case com.android.internal.R.styleable.View_scrollX: 4407 x = a.getDimensionPixelOffset(attr, 0); 4408 break; 4409 case com.android.internal.R.styleable.View_scrollY: 4410 y = a.getDimensionPixelOffset(attr, 0); 4411 break; 4412 case com.android.internal.R.styleable.View_alpha: 4413 setAlpha(a.getFloat(attr, 1f)); 4414 break; 4415 case com.android.internal.R.styleable.View_transformPivotX: 4416 setPivotX(a.getDimension(attr, 0)); 4417 break; 4418 case com.android.internal.R.styleable.View_transformPivotY: 4419 setPivotY(a.getDimension(attr, 0)); 4420 break; 4421 case com.android.internal.R.styleable.View_translationX: 4422 tx = a.getDimension(attr, 0); 4423 transformSet = true; 4424 break; 4425 case com.android.internal.R.styleable.View_translationY: 4426 ty = a.getDimension(attr, 0); 4427 transformSet = true; 4428 break; 4429 case com.android.internal.R.styleable.View_translationZ: 4430 tz = a.getDimension(attr, 0); 4431 transformSet = true; 4432 break; 4433 case com.android.internal.R.styleable.View_elevation: 4434 elevation = a.getDimension(attr, 0); 4435 transformSet = true; 4436 break; 4437 case com.android.internal.R.styleable.View_rotation: 4438 rotation = a.getFloat(attr, 0); 4439 transformSet = true; 4440 break; 4441 case com.android.internal.R.styleable.View_rotationX: 4442 rotationX = a.getFloat(attr, 0); 4443 transformSet = true; 4444 break; 4445 case com.android.internal.R.styleable.View_rotationY: 4446 rotationY = a.getFloat(attr, 0); 4447 transformSet = true; 4448 break; 4449 case com.android.internal.R.styleable.View_scaleX: 4450 sx = a.getFloat(attr, 1f); 4451 transformSet = true; 4452 break; 4453 case com.android.internal.R.styleable.View_scaleY: 4454 sy = a.getFloat(attr, 1f); 4455 transformSet = true; 4456 break; 4457 case com.android.internal.R.styleable.View_id: 4458 mID = a.getResourceId(attr, NO_ID); 4459 break; 4460 case com.android.internal.R.styleable.View_tag: 4461 mTag = a.getText(attr); 4462 break; 4463 case com.android.internal.R.styleable.View_fitsSystemWindows: 4464 if (a.getBoolean(attr, false)) { 4465 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4466 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4467 } 4468 break; 4469 case com.android.internal.R.styleable.View_focusable: 4470 if (a.getBoolean(attr, false)) { 4471 viewFlagValues |= FOCUSABLE; 4472 viewFlagMasks |= FOCUSABLE_MASK; 4473 } 4474 break; 4475 case com.android.internal.R.styleable.View_focusableInTouchMode: 4476 if (a.getBoolean(attr, false)) { 4477 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4478 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4479 } 4480 break; 4481 case com.android.internal.R.styleable.View_clickable: 4482 if (a.getBoolean(attr, false)) { 4483 viewFlagValues |= CLICKABLE; 4484 viewFlagMasks |= CLICKABLE; 4485 } 4486 break; 4487 case com.android.internal.R.styleable.View_longClickable: 4488 if (a.getBoolean(attr, false)) { 4489 viewFlagValues |= LONG_CLICKABLE; 4490 viewFlagMasks |= LONG_CLICKABLE; 4491 } 4492 break; 4493 case com.android.internal.R.styleable.View_contextClickable: 4494 if (a.getBoolean(attr, false)) { 4495 viewFlagValues |= CONTEXT_CLICKABLE; 4496 viewFlagMasks |= CONTEXT_CLICKABLE; 4497 } 4498 break; 4499 case com.android.internal.R.styleable.View_saveEnabled: 4500 if (!a.getBoolean(attr, true)) { 4501 viewFlagValues |= SAVE_DISABLED; 4502 viewFlagMasks |= SAVE_DISABLED_MASK; 4503 } 4504 break; 4505 case com.android.internal.R.styleable.View_duplicateParentState: 4506 if (a.getBoolean(attr, false)) { 4507 viewFlagValues |= DUPLICATE_PARENT_STATE; 4508 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4509 } 4510 break; 4511 case com.android.internal.R.styleable.View_visibility: 4512 final int visibility = a.getInt(attr, 0); 4513 if (visibility != 0) { 4514 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4515 viewFlagMasks |= VISIBILITY_MASK; 4516 } 4517 break; 4518 case com.android.internal.R.styleable.View_layoutDirection: 4519 // Clear any layout direction flags (included resolved bits) already set 4520 mPrivateFlags2 &= 4521 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4522 // Set the layout direction flags depending on the value of the attribute 4523 final int layoutDirection = a.getInt(attr, -1); 4524 final int value = (layoutDirection != -1) ? 4525 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4526 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4527 break; 4528 case com.android.internal.R.styleable.View_drawingCacheQuality: 4529 final int cacheQuality = a.getInt(attr, 0); 4530 if (cacheQuality != 0) { 4531 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4532 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4533 } 4534 break; 4535 case com.android.internal.R.styleable.View_contentDescription: 4536 setContentDescription(a.getString(attr)); 4537 break; 4538 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4539 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4540 break; 4541 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4542 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4543 break; 4544 case com.android.internal.R.styleable.View_labelFor: 4545 setLabelFor(a.getResourceId(attr, NO_ID)); 4546 break; 4547 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4548 if (!a.getBoolean(attr, true)) { 4549 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4550 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4551 } 4552 break; 4553 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4554 if (!a.getBoolean(attr, true)) { 4555 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4556 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4557 } 4558 break; 4559 case R.styleable.View_scrollbars: 4560 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4561 if (scrollbars != SCROLLBARS_NONE) { 4562 viewFlagValues |= scrollbars; 4563 viewFlagMasks |= SCROLLBARS_MASK; 4564 initializeScrollbars = true; 4565 } 4566 break; 4567 //noinspection deprecation 4568 case R.styleable.View_fadingEdge: 4569 if (targetSdkVersion >= ICE_CREAM_SANDWICH) { 4570 // Ignore the attribute starting with ICS 4571 break; 4572 } 4573 // With builds < ICS, fall through and apply fading edges 4574 case R.styleable.View_requiresFadingEdge: 4575 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4576 if (fadingEdge != FADING_EDGE_NONE) { 4577 viewFlagValues |= fadingEdge; 4578 viewFlagMasks |= FADING_EDGE_MASK; 4579 initializeFadingEdgeInternal(a); 4580 } 4581 break; 4582 case R.styleable.View_scrollbarStyle: 4583 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4584 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4585 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4586 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4587 } 4588 break; 4589 case R.styleable.View_isScrollContainer: 4590 setScrollContainer = true; 4591 if (a.getBoolean(attr, false)) { 4592 setScrollContainer(true); 4593 } 4594 break; 4595 case com.android.internal.R.styleable.View_keepScreenOn: 4596 if (a.getBoolean(attr, false)) { 4597 viewFlagValues |= KEEP_SCREEN_ON; 4598 viewFlagMasks |= KEEP_SCREEN_ON; 4599 } 4600 break; 4601 case R.styleable.View_filterTouchesWhenObscured: 4602 if (a.getBoolean(attr, false)) { 4603 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4604 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4605 } 4606 break; 4607 case R.styleable.View_nextFocusLeft: 4608 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4609 break; 4610 case R.styleable.View_nextFocusRight: 4611 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4612 break; 4613 case R.styleable.View_nextFocusUp: 4614 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4615 break; 4616 case R.styleable.View_nextFocusDown: 4617 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4618 break; 4619 case R.styleable.View_nextFocusForward: 4620 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4621 break; 4622 case R.styleable.View_nextClusterForward: 4623 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 4624 break; 4625 case R.styleable.View_nextSectionForward: 4626 mNextSectionForwardId = a.getResourceId(attr, View.NO_ID); 4627 break; 4628 case R.styleable.View_minWidth: 4629 mMinWidth = a.getDimensionPixelSize(attr, 0); 4630 break; 4631 case R.styleable.View_minHeight: 4632 mMinHeight = a.getDimensionPixelSize(attr, 0); 4633 break; 4634 case R.styleable.View_onClick: 4635 if (context.isRestricted()) { 4636 throw new IllegalStateException("The android:onClick attribute cannot " 4637 + "be used within a restricted context"); 4638 } 4639 4640 final String handlerName = a.getString(attr); 4641 if (handlerName != null) { 4642 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 4643 } 4644 break; 4645 case R.styleable.View_overScrollMode: 4646 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 4647 break; 4648 case R.styleable.View_verticalScrollbarPosition: 4649 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 4650 break; 4651 case R.styleable.View_layerType: 4652 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 4653 break; 4654 case R.styleable.View_textDirection: 4655 // Clear any text direction flag already set 4656 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 4657 // Set the text direction flags depending on the value of the attribute 4658 final int textDirection = a.getInt(attr, -1); 4659 if (textDirection != -1) { 4660 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 4661 } 4662 break; 4663 case R.styleable.View_textAlignment: 4664 // Clear any text alignment flag already set 4665 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 4666 // Set the text alignment flag depending on the value of the attribute 4667 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 4668 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 4669 break; 4670 case R.styleable.View_importantForAccessibility: 4671 setImportantForAccessibility(a.getInt(attr, 4672 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 4673 break; 4674 case R.styleable.View_accessibilityLiveRegion: 4675 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 4676 break; 4677 case R.styleable.View_transitionName: 4678 setTransitionName(a.getString(attr)); 4679 break; 4680 case R.styleable.View_nestedScrollingEnabled: 4681 setNestedScrollingEnabled(a.getBoolean(attr, false)); 4682 break; 4683 case R.styleable.View_stateListAnimator: 4684 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 4685 a.getResourceId(attr, 0))); 4686 break; 4687 case R.styleable.View_backgroundTint: 4688 // This will get applied later during setBackground(). 4689 if (mBackgroundTint == null) { 4690 mBackgroundTint = new TintInfo(); 4691 } 4692 mBackgroundTint.mTintList = a.getColorStateList( 4693 R.styleable.View_backgroundTint); 4694 mBackgroundTint.mHasTintList = true; 4695 break; 4696 case R.styleable.View_backgroundTintMode: 4697 // This will get applied later during setBackground(). 4698 if (mBackgroundTint == null) { 4699 mBackgroundTint = new TintInfo(); 4700 } 4701 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 4702 R.styleable.View_backgroundTintMode, -1), null); 4703 mBackgroundTint.mHasTintMode = true; 4704 break; 4705 case R.styleable.View_outlineProvider: 4706 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 4707 PROVIDER_BACKGROUND)); 4708 break; 4709 case R.styleable.View_foreground: 4710 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4711 setForeground(a.getDrawable(attr)); 4712 } 4713 break; 4714 case R.styleable.View_foregroundGravity: 4715 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4716 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 4717 } 4718 break; 4719 case R.styleable.View_foregroundTintMode: 4720 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4721 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 4722 } 4723 break; 4724 case R.styleable.View_foregroundTint: 4725 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4726 setForegroundTintList(a.getColorStateList(attr)); 4727 } 4728 break; 4729 case R.styleable.View_foregroundInsidePadding: 4730 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4731 if (mForegroundInfo == null) { 4732 mForegroundInfo = new ForegroundInfo(); 4733 } 4734 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 4735 mForegroundInfo.mInsidePadding); 4736 } 4737 break; 4738 case R.styleable.View_scrollIndicators: 4739 final int scrollIndicators = 4740 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 4741 & SCROLL_INDICATORS_PFLAG3_MASK; 4742 if (scrollIndicators != 0) { 4743 mPrivateFlags3 |= scrollIndicators; 4744 initializeScrollIndicators = true; 4745 } 4746 break; 4747 case R.styleable.View_pointerIcon: 4748 final int resourceId = a.getResourceId(attr, 0); 4749 if (resourceId != 0) { 4750 setPointerIcon(PointerIcon.load( 4751 context.getResources(), resourceId)); 4752 } else { 4753 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 4754 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 4755 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 4756 } 4757 } 4758 break; 4759 case R.styleable.View_forceHasOverlappingRendering: 4760 if (a.peekValue(attr) != null) { 4761 forceHasOverlappingRendering(a.getBoolean(attr, true)); 4762 } 4763 break; 4764 case R.styleable.View_tooltipText: 4765 setTooltipText(a.getText(attr)); 4766 break; 4767 case R.styleable.View_keyboardNavigationCluster: 4768 if (a.peekValue(attr) != null) { 4769 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 4770 } 4771 break; 4772 case R.styleable.View_keyboardNavigationSection: 4773 if (a.peekValue(attr) != null) { 4774 setKeyboardNavigationSection(a.getBoolean(attr, true)); 4775 } 4776 break; 4777 case R.styleable.View_focusedByDefault: 4778 if (a.peekValue(attr) != null) { 4779 setFocusedByDefault(a.getBoolean(attr, true)); 4780 } 4781 break; 4782 } 4783 } 4784 4785 setOverScrollMode(overScrollMode); 4786 4787 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 4788 // the resolved layout direction). Those cached values will be used later during padding 4789 // resolution. 4790 mUserPaddingStart = startPadding; 4791 mUserPaddingEnd = endPadding; 4792 4793 if (background != null) { 4794 setBackground(background); 4795 } 4796 4797 // setBackground above will record that padding is currently provided by the background. 4798 // If we have padding specified via xml, record that here instead and use it. 4799 mLeftPaddingDefined = leftPaddingDefined; 4800 mRightPaddingDefined = rightPaddingDefined; 4801 4802 if (padding >= 0) { 4803 leftPadding = padding; 4804 topPadding = padding; 4805 rightPadding = padding; 4806 bottomPadding = padding; 4807 mUserPaddingLeftInitial = padding; 4808 mUserPaddingRightInitial = padding; 4809 } else { 4810 if (paddingHorizontal >= 0) { 4811 leftPadding = paddingHorizontal; 4812 rightPadding = paddingHorizontal; 4813 mUserPaddingLeftInitial = paddingHorizontal; 4814 mUserPaddingRightInitial = paddingHorizontal; 4815 } 4816 if (paddingVertical >= 0) { 4817 topPadding = paddingVertical; 4818 bottomPadding = paddingVertical; 4819 } 4820 } 4821 4822 if (isRtlCompatibilityMode()) { 4823 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 4824 // left / right padding are used if defined (meaning here nothing to do). If they are not 4825 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 4826 // start / end and resolve them as left / right (layout direction is not taken into account). 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 if (!mLeftPaddingDefined && startPaddingDefined) { 4831 leftPadding = startPadding; 4832 } 4833 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 4834 if (!mRightPaddingDefined && endPaddingDefined) { 4835 rightPadding = endPadding; 4836 } 4837 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 4838 } else { 4839 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 4840 // values defined. Otherwise, left /right values are used. 4841 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4842 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4843 // defined. 4844 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 4845 4846 if (mLeftPaddingDefined && !hasRelativePadding) { 4847 mUserPaddingLeftInitial = leftPadding; 4848 } 4849 if (mRightPaddingDefined && !hasRelativePadding) { 4850 mUserPaddingRightInitial = rightPadding; 4851 } 4852 } 4853 4854 internalSetPadding( 4855 mUserPaddingLeftInitial, 4856 topPadding >= 0 ? topPadding : mPaddingTop, 4857 mUserPaddingRightInitial, 4858 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 4859 4860 if (viewFlagMasks != 0) { 4861 setFlags(viewFlagValues, viewFlagMasks); 4862 } 4863 4864 if (initializeScrollbars) { 4865 initializeScrollbarsInternal(a); 4866 } 4867 4868 if (initializeScrollIndicators) { 4869 initializeScrollIndicatorsInternal(); 4870 } 4871 4872 a.recycle(); 4873 4874 // Needs to be called after mViewFlags is set 4875 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4876 recomputePadding(); 4877 } 4878 4879 if (x != 0 || y != 0) { 4880 scrollTo(x, y); 4881 } 4882 4883 if (transformSet) { 4884 setTranslationX(tx); 4885 setTranslationY(ty); 4886 setTranslationZ(tz); 4887 setElevation(elevation); 4888 setRotation(rotation); 4889 setRotationX(rotationX); 4890 setRotationY(rotationY); 4891 setScaleX(sx); 4892 setScaleY(sy); 4893 } 4894 4895 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 4896 setScrollContainer(true); 4897 } 4898 4899 computeOpaqueFlags(); 4900 } 4901 4902 /** 4903 * An implementation of OnClickListener that attempts to lazily load a 4904 * named click handling method from a parent or ancestor context. 4905 */ 4906 private static class DeclaredOnClickListener implements OnClickListener { 4907 private final View mHostView; 4908 private final String mMethodName; 4909 4910 private Method mResolvedMethod; 4911 private Context mResolvedContext; 4912 4913 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 4914 mHostView = hostView; 4915 mMethodName = methodName; 4916 } 4917 4918 @Override 4919 public void onClick(@NonNull View v) { 4920 if (mResolvedMethod == null) { 4921 resolveMethod(mHostView.getContext(), mMethodName); 4922 } 4923 4924 try { 4925 mResolvedMethod.invoke(mResolvedContext, v); 4926 } catch (IllegalAccessException e) { 4927 throw new IllegalStateException( 4928 "Could not execute non-public method for android:onClick", e); 4929 } catch (InvocationTargetException e) { 4930 throw new IllegalStateException( 4931 "Could not execute method for android:onClick", e); 4932 } 4933 } 4934 4935 @NonNull 4936 private void resolveMethod(@Nullable Context context, @NonNull String name) { 4937 while (context != null) { 4938 try { 4939 if (!context.isRestricted()) { 4940 final Method method = context.getClass().getMethod(mMethodName, View.class); 4941 if (method != null) { 4942 mResolvedMethod = method; 4943 mResolvedContext = context; 4944 return; 4945 } 4946 } 4947 } catch (NoSuchMethodException e) { 4948 // Failed to find method, keep searching up the hierarchy. 4949 } 4950 4951 if (context instanceof ContextWrapper) { 4952 context = ((ContextWrapper) context).getBaseContext(); 4953 } else { 4954 // Can't search up the hierarchy, null out and fail. 4955 context = null; 4956 } 4957 } 4958 4959 final int id = mHostView.getId(); 4960 final String idText = id == NO_ID ? "" : " with id '" 4961 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 4962 throw new IllegalStateException("Could not find method " + mMethodName 4963 + "(View) in a parent or ancestor Context for android:onClick " 4964 + "attribute defined on view " + mHostView.getClass() + idText); 4965 } 4966 } 4967 4968 /** 4969 * Non-public constructor for use in testing 4970 */ 4971 View() { 4972 mResources = null; 4973 mRenderNode = RenderNode.create(getClass().getName(), this); 4974 } 4975 4976 final boolean debugDraw() { 4977 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 4978 } 4979 4980 private static SparseArray<String> getAttributeMap() { 4981 if (mAttributeMap == null) { 4982 mAttributeMap = new SparseArray<>(); 4983 } 4984 return mAttributeMap; 4985 } 4986 4987 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 4988 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 4989 final int indexCount = t.getIndexCount(); 4990 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 4991 4992 int i = 0; 4993 4994 // Store raw XML attributes. 4995 for (int j = 0; j < attrsCount; ++j) { 4996 attributes[i] = attrs.getAttributeName(j); 4997 attributes[i + 1] = attrs.getAttributeValue(j); 4998 i += 2; 4999 } 5000 5001 // Store resolved styleable attributes. 5002 final Resources res = t.getResources(); 5003 final SparseArray<String> attributeMap = getAttributeMap(); 5004 for (int j = 0; j < indexCount; ++j) { 5005 final int index = t.getIndex(j); 5006 if (!t.hasValueOrEmpty(index)) { 5007 // Value is undefined. Skip it. 5008 continue; 5009 } 5010 5011 final int resourceId = t.getResourceId(index, 0); 5012 if (resourceId == 0) { 5013 // Value is not a reference. Skip it. 5014 continue; 5015 } 5016 5017 String resourceName = attributeMap.get(resourceId); 5018 if (resourceName == null) { 5019 try { 5020 resourceName = res.getResourceName(resourceId); 5021 } catch (Resources.NotFoundException e) { 5022 resourceName = "0x" + Integer.toHexString(resourceId); 5023 } 5024 attributeMap.put(resourceId, resourceName); 5025 } 5026 5027 attributes[i] = resourceName; 5028 attributes[i + 1] = t.getString(index); 5029 i += 2; 5030 } 5031 5032 // Trim to fit contents. 5033 final String[] trimmed = new String[i]; 5034 System.arraycopy(attributes, 0, trimmed, 0, i); 5035 mAttributes = trimmed; 5036 } 5037 5038 public String toString() { 5039 StringBuilder out = new StringBuilder(128); 5040 out.append(getClass().getName()); 5041 out.append('{'); 5042 out.append(Integer.toHexString(System.identityHashCode(this))); 5043 out.append(' '); 5044 switch (mViewFlags&VISIBILITY_MASK) { 5045 case VISIBLE: out.append('V'); break; 5046 case INVISIBLE: out.append('I'); break; 5047 case GONE: out.append('G'); break; 5048 default: out.append('.'); break; 5049 } 5050 out.append((mViewFlags&FOCUSABLE_MASK) == FOCUSABLE ? 'F' : '.'); 5051 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5052 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5053 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5054 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5055 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5056 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5057 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5058 out.append(' '); 5059 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5060 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5061 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5062 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5063 out.append('p'); 5064 } else { 5065 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5066 } 5067 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5068 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5069 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5070 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5071 out.append(' '); 5072 out.append(mLeft); 5073 out.append(','); 5074 out.append(mTop); 5075 out.append('-'); 5076 out.append(mRight); 5077 out.append(','); 5078 out.append(mBottom); 5079 final int id = getId(); 5080 if (id != NO_ID) { 5081 out.append(" #"); 5082 out.append(Integer.toHexString(id)); 5083 final Resources r = mResources; 5084 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5085 try { 5086 String pkgname; 5087 switch (id&0xff000000) { 5088 case 0x7f000000: 5089 pkgname="app"; 5090 break; 5091 case 0x01000000: 5092 pkgname="android"; 5093 break; 5094 default: 5095 pkgname = r.getResourcePackageName(id); 5096 break; 5097 } 5098 String typename = r.getResourceTypeName(id); 5099 String entryname = r.getResourceEntryName(id); 5100 out.append(" "); 5101 out.append(pkgname); 5102 out.append(":"); 5103 out.append(typename); 5104 out.append("/"); 5105 out.append(entryname); 5106 } catch (Resources.NotFoundException e) { 5107 } 5108 } 5109 } 5110 out.append("}"); 5111 return out.toString(); 5112 } 5113 5114 /** 5115 * <p> 5116 * Initializes the fading edges from a given set of styled attributes. This 5117 * method should be called by subclasses that need fading edges and when an 5118 * instance of these subclasses is created programmatically rather than 5119 * being inflated from XML. This method is automatically called when the XML 5120 * is inflated. 5121 * </p> 5122 * 5123 * @param a the styled attributes set to initialize the fading edges from 5124 * 5125 * @removed 5126 */ 5127 protected void initializeFadingEdge(TypedArray a) { 5128 // This method probably shouldn't have been included in the SDK to begin with. 5129 // It relies on 'a' having been initialized using an attribute filter array that is 5130 // not publicly available to the SDK. The old method has been renamed 5131 // to initializeFadingEdgeInternal and hidden for framework use only; 5132 // this one initializes using defaults to make it safe to call for apps. 5133 5134 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5135 5136 initializeFadingEdgeInternal(arr); 5137 5138 arr.recycle(); 5139 } 5140 5141 /** 5142 * <p> 5143 * Initializes the fading edges from a given set of styled attributes. This 5144 * method should be called by subclasses that need fading edges and when an 5145 * instance of these subclasses is created programmatically rather than 5146 * being inflated from XML. This method is automatically called when the XML 5147 * is inflated. 5148 * </p> 5149 * 5150 * @param a the styled attributes set to initialize the fading edges from 5151 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5152 */ 5153 protected void initializeFadingEdgeInternal(TypedArray a) { 5154 initScrollCache(); 5155 5156 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5157 R.styleable.View_fadingEdgeLength, 5158 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5159 } 5160 5161 /** 5162 * Returns the size of the vertical faded edges used to indicate that more 5163 * content in this view is visible. 5164 * 5165 * @return The size in pixels of the vertical faded edge or 0 if vertical 5166 * faded edges are not enabled for this view. 5167 * @attr ref android.R.styleable#View_fadingEdgeLength 5168 */ 5169 public int getVerticalFadingEdgeLength() { 5170 if (isVerticalFadingEdgeEnabled()) { 5171 ScrollabilityCache cache = mScrollCache; 5172 if (cache != null) { 5173 return cache.fadingEdgeLength; 5174 } 5175 } 5176 return 0; 5177 } 5178 5179 /** 5180 * Set the size of the faded edge used to indicate that more content in this 5181 * view is available. Will not change whether the fading edge is enabled; use 5182 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5183 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5184 * for the vertical or horizontal fading edges. 5185 * 5186 * @param length The size in pixels of the faded edge used to indicate that more 5187 * content in this view is visible. 5188 */ 5189 public void setFadingEdgeLength(int length) { 5190 initScrollCache(); 5191 mScrollCache.fadingEdgeLength = length; 5192 } 5193 5194 /** 5195 * Returns the size of the horizontal faded edges used to indicate that more 5196 * content in this view is visible. 5197 * 5198 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5199 * faded edges are not enabled for this view. 5200 * @attr ref android.R.styleable#View_fadingEdgeLength 5201 */ 5202 public int getHorizontalFadingEdgeLength() { 5203 if (isHorizontalFadingEdgeEnabled()) { 5204 ScrollabilityCache cache = mScrollCache; 5205 if (cache != null) { 5206 return cache.fadingEdgeLength; 5207 } 5208 } 5209 return 0; 5210 } 5211 5212 /** 5213 * Returns the width of the vertical scrollbar. 5214 * 5215 * @return The width in pixels of the vertical scrollbar or 0 if there 5216 * is no vertical scrollbar. 5217 */ 5218 public int getVerticalScrollbarWidth() { 5219 ScrollabilityCache cache = mScrollCache; 5220 if (cache != null) { 5221 ScrollBarDrawable scrollBar = cache.scrollBar; 5222 if (scrollBar != null) { 5223 int size = scrollBar.getSize(true); 5224 if (size <= 0) { 5225 size = cache.scrollBarSize; 5226 } 5227 return size; 5228 } 5229 return 0; 5230 } 5231 return 0; 5232 } 5233 5234 /** 5235 * Returns the height of the horizontal scrollbar. 5236 * 5237 * @return The height in pixels of the horizontal scrollbar or 0 if 5238 * there is no horizontal scrollbar. 5239 */ 5240 protected int getHorizontalScrollbarHeight() { 5241 ScrollabilityCache cache = mScrollCache; 5242 if (cache != null) { 5243 ScrollBarDrawable scrollBar = cache.scrollBar; 5244 if (scrollBar != null) { 5245 int size = scrollBar.getSize(false); 5246 if (size <= 0) { 5247 size = cache.scrollBarSize; 5248 } 5249 return size; 5250 } 5251 return 0; 5252 } 5253 return 0; 5254 } 5255 5256 /** 5257 * <p> 5258 * Initializes the scrollbars from a given set of styled attributes. This 5259 * method should be called by subclasses that need scrollbars and when an 5260 * instance of these subclasses is created programmatically rather than 5261 * being inflated from XML. This method is automatically called when the XML 5262 * is inflated. 5263 * </p> 5264 * 5265 * @param a the styled attributes set to initialize the scrollbars from 5266 * 5267 * @removed 5268 */ 5269 protected void initializeScrollbars(TypedArray a) { 5270 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5271 // using the View filter array which is not available to the SDK. As such, internal 5272 // framework usage now uses initializeScrollbarsInternal and we grab a default 5273 // TypedArray with the right filter instead here. 5274 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5275 5276 initializeScrollbarsInternal(arr); 5277 5278 // We ignored the method parameter. Recycle the one we actually did use. 5279 arr.recycle(); 5280 } 5281 5282 /** 5283 * <p> 5284 * Initializes the scrollbars from a given set of styled attributes. This 5285 * method should be called by subclasses that need scrollbars and when an 5286 * instance of these subclasses is created programmatically rather than 5287 * being inflated from XML. This method is automatically called when the XML 5288 * is inflated. 5289 * </p> 5290 * 5291 * @param a the styled attributes set to initialize the scrollbars from 5292 * @hide 5293 */ 5294 protected void initializeScrollbarsInternal(TypedArray a) { 5295 initScrollCache(); 5296 5297 final ScrollabilityCache scrollabilityCache = mScrollCache; 5298 5299 if (scrollabilityCache.scrollBar == null) { 5300 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5301 scrollabilityCache.scrollBar.setState(getDrawableState()); 5302 scrollabilityCache.scrollBar.setCallback(this); 5303 } 5304 5305 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5306 5307 if (!fadeScrollbars) { 5308 scrollabilityCache.state = ScrollabilityCache.ON; 5309 } 5310 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5311 5312 5313 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5314 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5315 .getScrollBarFadeDuration()); 5316 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5317 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5318 ViewConfiguration.getScrollDefaultDelay()); 5319 5320 5321 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5322 com.android.internal.R.styleable.View_scrollbarSize, 5323 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5324 5325 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5326 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5327 5328 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5329 if (thumb != null) { 5330 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5331 } 5332 5333 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5334 false); 5335 if (alwaysDraw) { 5336 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5337 } 5338 5339 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5340 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5341 5342 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5343 if (thumb != null) { 5344 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5345 } 5346 5347 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5348 false); 5349 if (alwaysDraw) { 5350 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5351 } 5352 5353 // Apply layout direction to the new Drawables if needed 5354 final int layoutDirection = getLayoutDirection(); 5355 if (track != null) { 5356 track.setLayoutDirection(layoutDirection); 5357 } 5358 if (thumb != null) { 5359 thumb.setLayoutDirection(layoutDirection); 5360 } 5361 5362 // Re-apply user/background padding so that scrollbar(s) get added 5363 resolvePadding(); 5364 } 5365 5366 private void initializeScrollIndicatorsInternal() { 5367 // Some day maybe we'll break this into top/left/start/etc. and let the 5368 // client control it. Until then, you can have any scroll indicator you 5369 // want as long as it's a 1dp foreground-colored rectangle. 5370 if (mScrollIndicatorDrawable == null) { 5371 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5372 } 5373 } 5374 5375 /** 5376 * <p> 5377 * Initalizes the scrollability cache if necessary. 5378 * </p> 5379 */ 5380 private void initScrollCache() { 5381 if (mScrollCache == null) { 5382 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5383 } 5384 } 5385 5386 private ScrollabilityCache getScrollCache() { 5387 initScrollCache(); 5388 return mScrollCache; 5389 } 5390 5391 /** 5392 * Set the position of the vertical scroll bar. Should be one of 5393 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5394 * {@link #SCROLLBAR_POSITION_RIGHT}. 5395 * 5396 * @param position Where the vertical scroll bar should be positioned. 5397 */ 5398 public void setVerticalScrollbarPosition(int position) { 5399 if (mVerticalScrollbarPosition != position) { 5400 mVerticalScrollbarPosition = position; 5401 computeOpaqueFlags(); 5402 resolvePadding(); 5403 } 5404 } 5405 5406 /** 5407 * @return The position where the vertical scroll bar will show, if applicable. 5408 * @see #setVerticalScrollbarPosition(int) 5409 */ 5410 public int getVerticalScrollbarPosition() { 5411 return mVerticalScrollbarPosition; 5412 } 5413 5414 boolean isOnScrollbar(float x, float y) { 5415 if (mScrollCache == null) { 5416 return false; 5417 } 5418 x += getScrollX(); 5419 y += getScrollY(); 5420 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5421 final Rect bounds = mScrollCache.mScrollBarBounds; 5422 getVerticalScrollBarBounds(bounds); 5423 if (bounds.contains((int)x, (int)y)) { 5424 return true; 5425 } 5426 } 5427 if (isHorizontalScrollBarEnabled()) { 5428 final Rect bounds = mScrollCache.mScrollBarBounds; 5429 getHorizontalScrollBarBounds(bounds); 5430 if (bounds.contains((int)x, (int)y)) { 5431 return true; 5432 } 5433 } 5434 return false; 5435 } 5436 5437 boolean isOnScrollbarThumb(float x, float y) { 5438 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5439 } 5440 5441 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5442 if (mScrollCache == null) { 5443 return false; 5444 } 5445 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5446 x += getScrollX(); 5447 y += getScrollY(); 5448 final Rect bounds = mScrollCache.mScrollBarBounds; 5449 getVerticalScrollBarBounds(bounds); 5450 final int range = computeVerticalScrollRange(); 5451 final int offset = computeVerticalScrollOffset(); 5452 final int extent = computeVerticalScrollExtent(); 5453 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5454 extent, range); 5455 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5456 extent, range, offset); 5457 final int thumbTop = bounds.top + thumbOffset; 5458 if (x >= bounds.left && x <= bounds.right && y >= thumbTop 5459 && y <= thumbTop + thumbLength) { 5460 return true; 5461 } 5462 } 5463 return false; 5464 } 5465 5466 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5467 if (mScrollCache == null) { 5468 return false; 5469 } 5470 if (isHorizontalScrollBarEnabled()) { 5471 x += getScrollX(); 5472 y += getScrollY(); 5473 final Rect bounds = mScrollCache.mScrollBarBounds; 5474 getHorizontalScrollBarBounds(bounds); 5475 final int range = computeHorizontalScrollRange(); 5476 final int offset = computeHorizontalScrollOffset(); 5477 final int extent = computeHorizontalScrollExtent(); 5478 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5479 extent, range); 5480 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5481 extent, range, offset); 5482 final int thumbLeft = bounds.left + thumbOffset; 5483 if (x >= thumbLeft && x <= thumbLeft + thumbLength && y >= bounds.top 5484 && y <= bounds.bottom) { 5485 return true; 5486 } 5487 } 5488 return false; 5489 } 5490 5491 boolean isDraggingScrollBar() { 5492 return mScrollCache != null 5493 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5494 } 5495 5496 /** 5497 * Sets the state of all scroll indicators. 5498 * <p> 5499 * See {@link #setScrollIndicators(int, int)} for usage information. 5500 * 5501 * @param indicators a bitmask of indicators that should be enabled, or 5502 * {@code 0} to disable all indicators 5503 * @see #setScrollIndicators(int, int) 5504 * @see #getScrollIndicators() 5505 * @attr ref android.R.styleable#View_scrollIndicators 5506 */ 5507 public void setScrollIndicators(@ScrollIndicators int indicators) { 5508 setScrollIndicators(indicators, 5509 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5510 } 5511 5512 /** 5513 * Sets the state of the scroll indicators specified by the mask. To change 5514 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5515 * <p> 5516 * When a scroll indicator is enabled, it will be displayed if the view 5517 * can scroll in the direction of the indicator. 5518 * <p> 5519 * Multiple indicator types may be enabled or disabled by passing the 5520 * logical OR of the desired types. If multiple types are specified, they 5521 * will all be set to the same enabled state. 5522 * <p> 5523 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5524 * 5525 * @param indicators the indicator direction, or the logical OR of multiple 5526 * indicator directions. One or more of: 5527 * <ul> 5528 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5529 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5530 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5531 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5532 * <li>{@link #SCROLL_INDICATOR_START}</li> 5533 * <li>{@link #SCROLL_INDICATOR_END}</li> 5534 * </ul> 5535 * @see #setScrollIndicators(int) 5536 * @see #getScrollIndicators() 5537 * @attr ref android.R.styleable#View_scrollIndicators 5538 */ 5539 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5540 // Shift and sanitize mask. 5541 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5542 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5543 5544 // Shift and mask indicators. 5545 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5546 indicators &= mask; 5547 5548 // Merge with non-masked flags. 5549 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5550 5551 if (mPrivateFlags3 != updatedFlags) { 5552 mPrivateFlags3 = updatedFlags; 5553 5554 if (indicators != 0) { 5555 initializeScrollIndicatorsInternal(); 5556 } 5557 invalidate(); 5558 } 5559 } 5560 5561 /** 5562 * Returns a bitmask representing the enabled scroll indicators. 5563 * <p> 5564 * For example, if the top and left scroll indicators are enabled and all 5565 * other indicators are disabled, the return value will be 5566 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5567 * <p> 5568 * To check whether the bottom scroll indicator is enabled, use the value 5569 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5570 * 5571 * @return a bitmask representing the enabled scroll indicators 5572 */ 5573 @ScrollIndicators 5574 public int getScrollIndicators() { 5575 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5576 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5577 } 5578 5579 ListenerInfo getListenerInfo() { 5580 if (mListenerInfo != null) { 5581 return mListenerInfo; 5582 } 5583 mListenerInfo = new ListenerInfo(); 5584 return mListenerInfo; 5585 } 5586 5587 /** 5588 * Register a callback to be invoked when the scroll X or Y positions of 5589 * this view change. 5590 * <p> 5591 * <b>Note:</b> Some views handle scrolling independently from View and may 5592 * have their own separate listeners for scroll-type events. For example, 5593 * {@link android.widget.ListView ListView} allows clients to register an 5594 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 5595 * to listen for changes in list scroll position. 5596 * 5597 * @param l The listener to notify when the scroll X or Y position changes. 5598 * @see android.view.View#getScrollX() 5599 * @see android.view.View#getScrollY() 5600 */ 5601 public void setOnScrollChangeListener(OnScrollChangeListener l) { 5602 getListenerInfo().mOnScrollChangeListener = l; 5603 } 5604 5605 /** 5606 * Register a callback to be invoked when focus of this view changed. 5607 * 5608 * @param l The callback that will run. 5609 */ 5610 public void setOnFocusChangeListener(OnFocusChangeListener l) { 5611 getListenerInfo().mOnFocusChangeListener = l; 5612 } 5613 5614 /** 5615 * Add a listener that will be called when the bounds of the view change due to 5616 * layout processing. 5617 * 5618 * @param listener The listener that will be called when layout bounds change. 5619 */ 5620 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 5621 ListenerInfo li = getListenerInfo(); 5622 if (li.mOnLayoutChangeListeners == null) { 5623 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 5624 } 5625 if (!li.mOnLayoutChangeListeners.contains(listener)) { 5626 li.mOnLayoutChangeListeners.add(listener); 5627 } 5628 } 5629 5630 /** 5631 * Remove a listener for layout changes. 5632 * 5633 * @param listener The listener for layout bounds change. 5634 */ 5635 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 5636 ListenerInfo li = mListenerInfo; 5637 if (li == null || li.mOnLayoutChangeListeners == null) { 5638 return; 5639 } 5640 li.mOnLayoutChangeListeners.remove(listener); 5641 } 5642 5643 /** 5644 * Add a listener for attach state changes. 5645 * 5646 * This listener will be called whenever this view is attached or detached 5647 * from a window. Remove the listener using 5648 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 5649 * 5650 * @param listener Listener to attach 5651 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 5652 */ 5653 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5654 ListenerInfo li = getListenerInfo(); 5655 if (li.mOnAttachStateChangeListeners == null) { 5656 li.mOnAttachStateChangeListeners 5657 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 5658 } 5659 li.mOnAttachStateChangeListeners.add(listener); 5660 } 5661 5662 /** 5663 * Remove a listener for attach state changes. The listener will receive no further 5664 * notification of window attach/detach events. 5665 * 5666 * @param listener Listener to remove 5667 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 5668 */ 5669 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5670 ListenerInfo li = mListenerInfo; 5671 if (li == null || li.mOnAttachStateChangeListeners == null) { 5672 return; 5673 } 5674 li.mOnAttachStateChangeListeners.remove(listener); 5675 } 5676 5677 /** 5678 * Returns the focus-change callback registered for this view. 5679 * 5680 * @return The callback, or null if one is not registered. 5681 */ 5682 public OnFocusChangeListener getOnFocusChangeListener() { 5683 ListenerInfo li = mListenerInfo; 5684 return li != null ? li.mOnFocusChangeListener : null; 5685 } 5686 5687 /** 5688 * Register a callback to be invoked when this view is clicked. If this view is not 5689 * clickable, it becomes clickable. 5690 * 5691 * @param l The callback that will run 5692 * 5693 * @see #setClickable(boolean) 5694 */ 5695 public void setOnClickListener(@Nullable OnClickListener l) { 5696 if (!isClickable()) { 5697 setClickable(true); 5698 } 5699 getListenerInfo().mOnClickListener = l; 5700 } 5701 5702 /** 5703 * Return whether this view has an attached OnClickListener. Returns 5704 * true if there is a listener, false if there is none. 5705 */ 5706 public boolean hasOnClickListeners() { 5707 ListenerInfo li = mListenerInfo; 5708 return (li != null && li.mOnClickListener != null); 5709 } 5710 5711 /** 5712 * Register a callback to be invoked when this view is clicked and held. If this view is not 5713 * long clickable, it becomes long clickable. 5714 * 5715 * @param l The callback that will run 5716 * 5717 * @see #setLongClickable(boolean) 5718 */ 5719 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 5720 if (!isLongClickable()) { 5721 setLongClickable(true); 5722 } 5723 getListenerInfo().mOnLongClickListener = l; 5724 } 5725 5726 /** 5727 * Register a callback to be invoked when this view is context clicked. If the view is not 5728 * context clickable, it becomes context clickable. 5729 * 5730 * @param l The callback that will run 5731 * @see #setContextClickable(boolean) 5732 */ 5733 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 5734 if (!isContextClickable()) { 5735 setContextClickable(true); 5736 } 5737 getListenerInfo().mOnContextClickListener = l; 5738 } 5739 5740 /** 5741 * Register a callback to be invoked when the context menu for this view is 5742 * being built. If this view is not long clickable, it becomes long clickable. 5743 * 5744 * @param l The callback that will run 5745 * 5746 */ 5747 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 5748 if (!isLongClickable()) { 5749 setLongClickable(true); 5750 } 5751 getListenerInfo().mOnCreateContextMenuListener = l; 5752 } 5753 5754 /** 5755 * Set an observer to collect stats for each frame rendered for this view. 5756 * 5757 * @hide 5758 */ 5759 public void addFrameMetricsListener(Window window, 5760 Window.OnFrameMetricsAvailableListener listener, 5761 Handler handler) { 5762 if (mAttachInfo != null) { 5763 if (mAttachInfo.mThreadedRenderer != null) { 5764 if (mFrameMetricsObservers == null) { 5765 mFrameMetricsObservers = new ArrayList<>(); 5766 } 5767 5768 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5769 handler.getLooper(), listener); 5770 mFrameMetricsObservers.add(fmo); 5771 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 5772 } else { 5773 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5774 } 5775 } else { 5776 if (mFrameMetricsObservers == null) { 5777 mFrameMetricsObservers = new ArrayList<>(); 5778 } 5779 5780 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5781 handler.getLooper(), listener); 5782 mFrameMetricsObservers.add(fmo); 5783 } 5784 } 5785 5786 /** 5787 * Remove observer configured to collect frame stats for this view. 5788 * 5789 * @hide 5790 */ 5791 public void removeFrameMetricsListener( 5792 Window.OnFrameMetricsAvailableListener listener) { 5793 ThreadedRenderer renderer = getThreadedRenderer(); 5794 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 5795 if (fmo == null) { 5796 throw new IllegalArgumentException( 5797 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 5798 } 5799 5800 if (mFrameMetricsObservers != null) { 5801 mFrameMetricsObservers.remove(fmo); 5802 if (renderer != null) { 5803 renderer.removeFrameMetricsObserver(fmo); 5804 } 5805 } 5806 } 5807 5808 private void registerPendingFrameMetricsObservers() { 5809 if (mFrameMetricsObservers != null) { 5810 ThreadedRenderer renderer = getThreadedRenderer(); 5811 if (renderer != null) { 5812 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 5813 renderer.addFrameMetricsObserver(fmo); 5814 } 5815 } else { 5816 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5817 } 5818 } 5819 } 5820 5821 private FrameMetricsObserver findFrameMetricsObserver( 5822 Window.OnFrameMetricsAvailableListener listener) { 5823 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 5824 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 5825 if (observer.mListener == listener) { 5826 return observer; 5827 } 5828 } 5829 5830 return null; 5831 } 5832 5833 /** 5834 * Call this view's OnClickListener, if it is defined. Performs all normal 5835 * actions associated with clicking: reporting accessibility event, playing 5836 * a sound, etc. 5837 * 5838 * @return True there was an assigned OnClickListener that was called, false 5839 * otherwise is returned. 5840 */ 5841 public boolean performClick() { 5842 final boolean result; 5843 final ListenerInfo li = mListenerInfo; 5844 if (li != null && li.mOnClickListener != null) { 5845 playSoundEffect(SoundEffectConstants.CLICK); 5846 li.mOnClickListener.onClick(this); 5847 result = true; 5848 } else { 5849 result = false; 5850 } 5851 5852 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 5853 return result; 5854 } 5855 5856 /** 5857 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 5858 * this only calls the listener, and does not do any associated clicking 5859 * actions like reporting an accessibility event. 5860 * 5861 * @return True there was an assigned OnClickListener that was called, false 5862 * otherwise is returned. 5863 */ 5864 public boolean callOnClick() { 5865 ListenerInfo li = mListenerInfo; 5866 if (li != null && li.mOnClickListener != null) { 5867 li.mOnClickListener.onClick(this); 5868 return true; 5869 } 5870 return false; 5871 } 5872 5873 /** 5874 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5875 * context menu if the OnLongClickListener did not consume the event. 5876 * 5877 * @return {@code true} if one of the above receivers consumed the event, 5878 * {@code false} otherwise 5879 */ 5880 public boolean performLongClick() { 5881 return performLongClickInternal(mLongClickX, mLongClickY); 5882 } 5883 5884 /** 5885 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5886 * context menu if the OnLongClickListener did not consume the event, 5887 * anchoring it to an (x,y) coordinate. 5888 * 5889 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5890 * to disable anchoring 5891 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5892 * to disable anchoring 5893 * @return {@code true} if one of the above receivers consumed the event, 5894 * {@code false} otherwise 5895 */ 5896 public boolean performLongClick(float x, float y) { 5897 mLongClickX = x; 5898 mLongClickY = y; 5899 final boolean handled = performLongClick(); 5900 mLongClickX = Float.NaN; 5901 mLongClickY = Float.NaN; 5902 return handled; 5903 } 5904 5905 /** 5906 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5907 * context menu if the OnLongClickListener did not consume the event, 5908 * optionally anchoring it to an (x,y) coordinate. 5909 * 5910 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5911 * to disable anchoring 5912 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5913 * to disable anchoring 5914 * @return {@code true} if one of the above receivers consumed the event, 5915 * {@code false} otherwise 5916 */ 5917 private boolean performLongClickInternal(float x, float y) { 5918 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 5919 5920 boolean handled = false; 5921 final ListenerInfo li = mListenerInfo; 5922 if (li != null && li.mOnLongClickListener != null) { 5923 handled = li.mOnLongClickListener.onLongClick(View.this); 5924 } 5925 if (!handled) { 5926 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 5927 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 5928 } 5929 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 5930 if (!handled) { 5931 handled = showLongClickTooltip((int) x, (int) y); 5932 } 5933 } 5934 if (handled) { 5935 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 5936 } 5937 return handled; 5938 } 5939 5940 /** 5941 * Call this view's OnContextClickListener, if it is defined. 5942 * 5943 * @param x the x coordinate of the context click 5944 * @param y the y coordinate of the context click 5945 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5946 * otherwise. 5947 */ 5948 public boolean performContextClick(float x, float y) { 5949 return performContextClick(); 5950 } 5951 5952 /** 5953 * Call this view's OnContextClickListener, if it is defined. 5954 * 5955 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5956 * otherwise. 5957 */ 5958 public boolean performContextClick() { 5959 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 5960 5961 boolean handled = false; 5962 ListenerInfo li = mListenerInfo; 5963 if (li != null && li.mOnContextClickListener != null) { 5964 handled = li.mOnContextClickListener.onContextClick(View.this); 5965 } 5966 if (handled) { 5967 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 5968 } 5969 return handled; 5970 } 5971 5972 /** 5973 * Performs button-related actions during a touch down event. 5974 * 5975 * @param event The event. 5976 * @return True if the down was consumed. 5977 * 5978 * @hide 5979 */ 5980 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 5981 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 5982 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 5983 showContextMenu(event.getX(), event.getY()); 5984 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 5985 return true; 5986 } 5987 return false; 5988 } 5989 5990 /** 5991 * Shows the context menu for this view. 5992 * 5993 * @return {@code true} if the context menu was shown, {@code false} 5994 * otherwise 5995 * @see #showContextMenu(float, float) 5996 */ 5997 public boolean showContextMenu() { 5998 return getParent().showContextMenuForChild(this); 5999 } 6000 6001 /** 6002 * Shows the context menu for this view anchored to the specified 6003 * view-relative coordinate. 6004 * 6005 * @param x the X coordinate in pixels relative to the view to which the 6006 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6007 * @param y the Y coordinate in pixels relative to the view to which the 6008 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6009 * @return {@code true} if the context menu was shown, {@code false} 6010 * otherwise 6011 */ 6012 public boolean showContextMenu(float x, float y) { 6013 return getParent().showContextMenuForChild(this, x, y); 6014 } 6015 6016 /** 6017 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 6018 * 6019 * @param callback Callback that will control the lifecycle of the action mode 6020 * @return The new action mode if it is started, null otherwise 6021 * 6022 * @see ActionMode 6023 * @see #startActionMode(android.view.ActionMode.Callback, int) 6024 */ 6025 public ActionMode startActionMode(ActionMode.Callback callback) { 6026 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 6027 } 6028 6029 /** 6030 * Start an action mode with the given type. 6031 * 6032 * @param callback Callback that will control the lifecycle of the action mode 6033 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 6034 * @return The new action mode if it is started, null otherwise 6035 * 6036 * @see ActionMode 6037 */ 6038 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6039 ViewParent parent = getParent(); 6040 if (parent == null) return null; 6041 try { 6042 return parent.startActionModeForChild(this, callback, type); 6043 } catch (AbstractMethodError ame) { 6044 // Older implementations of custom views might not implement this. 6045 return parent.startActionModeForChild(this, callback); 6046 } 6047 } 6048 6049 /** 6050 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6051 * Context, creating a unique View identifier to retrieve the result. 6052 * 6053 * @param intent The Intent to be started. 6054 * @param requestCode The request code to use. 6055 * @hide 6056 */ 6057 public void startActivityForResult(Intent intent, int requestCode) { 6058 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6059 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6060 } 6061 6062 /** 6063 * If this View corresponds to the calling who, dispatches the activity result. 6064 * @param who The identifier for the targeted View to receive the result. 6065 * @param requestCode The integer request code originally supplied to 6066 * startActivityForResult(), allowing you to identify who this 6067 * result came from. 6068 * @param resultCode The integer result code returned by the child activity 6069 * through its setResult(). 6070 * @param data An Intent, which can return result data to the caller 6071 * (various data can be attached to Intent "extras"). 6072 * @return {@code true} if the activity result was dispatched. 6073 * @hide 6074 */ 6075 public boolean dispatchActivityResult( 6076 String who, int requestCode, int resultCode, Intent data) { 6077 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6078 onActivityResult(requestCode, resultCode, data); 6079 mStartActivityRequestWho = null; 6080 return true; 6081 } 6082 return false; 6083 } 6084 6085 /** 6086 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6087 * 6088 * @param requestCode The integer request code originally supplied to 6089 * startActivityForResult(), allowing you to identify who this 6090 * result came from. 6091 * @param resultCode The integer result code returned by the child activity 6092 * through its setResult(). 6093 * @param data An Intent, which can return result data to the caller 6094 * (various data can be attached to Intent "extras"). 6095 * @hide 6096 */ 6097 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6098 // Do nothing. 6099 } 6100 6101 /** 6102 * Register a callback to be invoked when a hardware key is pressed in this view. 6103 * Key presses in software input methods will generally not trigger the methods of 6104 * this listener. 6105 * @param l the key listener to attach to this view 6106 */ 6107 public void setOnKeyListener(OnKeyListener l) { 6108 getListenerInfo().mOnKeyListener = l; 6109 } 6110 6111 /** 6112 * Register a callback to be invoked when a touch event is sent to this view. 6113 * @param l the touch listener to attach to this view 6114 */ 6115 public void setOnTouchListener(OnTouchListener l) { 6116 getListenerInfo().mOnTouchListener = l; 6117 } 6118 6119 /** 6120 * Register a callback to be invoked when a generic motion event is sent to this view. 6121 * @param l the generic motion listener to attach to this view 6122 */ 6123 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6124 getListenerInfo().mOnGenericMotionListener = l; 6125 } 6126 6127 /** 6128 * Register a callback to be invoked when a hover event is sent to this view. 6129 * @param l the hover listener to attach to this view 6130 */ 6131 public void setOnHoverListener(OnHoverListener l) { 6132 getListenerInfo().mOnHoverListener = l; 6133 } 6134 6135 /** 6136 * Register a drag event listener callback object for this View. The parameter is 6137 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6138 * View, the system calls the 6139 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6140 * @param l An implementation of {@link android.view.View.OnDragListener}. 6141 */ 6142 public void setOnDragListener(OnDragListener l) { 6143 getListenerInfo().mOnDragListener = l; 6144 } 6145 6146 /** 6147 * Give this view focus. This will cause 6148 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6149 * 6150 * Note: this does not check whether this {@link View} should get focus, it just 6151 * gives it focus no matter what. It should only be called internally by framework 6152 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6153 * 6154 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6155 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6156 * focus moved when requestFocus() is called. It may not always 6157 * apply, in which case use the default View.FOCUS_DOWN. 6158 * @param previouslyFocusedRect The rectangle of the view that had focus 6159 * prior in this View's coordinate system. 6160 */ 6161 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6162 if (DBG) { 6163 System.out.println(this + " requestFocus()"); 6164 } 6165 6166 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6167 mPrivateFlags |= PFLAG_FOCUSED; 6168 6169 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6170 6171 if (mParent != null) { 6172 mParent.requestChildFocus(this, this); 6173 if (mParent instanceof ViewGroup) { 6174 ((ViewGroup) mParent).setDefaultFocus(this); 6175 } 6176 } 6177 6178 if (mAttachInfo != null) { 6179 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6180 } 6181 6182 onFocusChanged(true, direction, previouslyFocusedRect); 6183 refreshDrawableState(); 6184 } 6185 } 6186 6187 /** 6188 * Sets this view's preference for reveal behavior when it gains focus. 6189 * 6190 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6191 * this view would prefer to be brought fully into view when it gains focus. 6192 * For example, a text field that a user is meant to type into. Other views such 6193 * as scrolling containers may prefer to opt-out of this behavior.</p> 6194 * 6195 * <p>The default value for views is true, though subclasses may change this 6196 * based on their preferred behavior.</p> 6197 * 6198 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6199 * 6200 * @see #getRevealOnFocusHint() 6201 */ 6202 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6203 if (revealOnFocus) { 6204 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6205 } else { 6206 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6207 } 6208 } 6209 6210 /** 6211 * Returns this view's preference for reveal behavior when it gains focus. 6212 * 6213 * <p>When this method returns true for a child view requesting focus, ancestor 6214 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6215 * should make a best effort to make the newly focused child fully visible to the user. 6216 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6217 * other properties affecting visibility to the user as part of the focus change.</p> 6218 * 6219 * @return true if this view would prefer to become fully visible when it gains focus, 6220 * false if it would prefer not to disrupt scroll positioning 6221 * 6222 * @see #setRevealOnFocusHint(boolean) 6223 */ 6224 public final boolean getRevealOnFocusHint() { 6225 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6226 } 6227 6228 /** 6229 * Populates <code>outRect</code> with the hotspot bounds. By default, 6230 * the hotspot bounds are identical to the screen bounds. 6231 * 6232 * @param outRect rect to populate with hotspot bounds 6233 * @hide Only for internal use by views and widgets. 6234 */ 6235 public void getHotspotBounds(Rect outRect) { 6236 final Drawable background = getBackground(); 6237 if (background != null) { 6238 background.getHotspotBounds(outRect); 6239 } else { 6240 getBoundsOnScreen(outRect); 6241 } 6242 } 6243 6244 /** 6245 * Request that a rectangle of this view be visible on the screen, 6246 * scrolling if necessary just enough. 6247 * 6248 * <p>A View should call this if it maintains some notion of which part 6249 * of its content is interesting. For example, a text editing view 6250 * should call this when its cursor moves. 6251 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6252 * It should not be affected by which part of the View is currently visible or its scroll 6253 * position. 6254 * 6255 * @param rectangle The rectangle in the View's content coordinate space 6256 * @return Whether any parent scrolled. 6257 */ 6258 public boolean requestRectangleOnScreen(Rect rectangle) { 6259 return requestRectangleOnScreen(rectangle, false); 6260 } 6261 6262 /** 6263 * Request that a rectangle of this view be visible on the screen, 6264 * scrolling if necessary just enough. 6265 * 6266 * <p>A View should call this if it maintains some notion of which part 6267 * of its content is interesting. For example, a text editing view 6268 * should call this when its cursor moves. 6269 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6270 * It should not be affected by which part of the View is currently visible or its scroll 6271 * position. 6272 * <p>When <code>immediate</code> is set to true, scrolling will not be 6273 * animated. 6274 * 6275 * @param rectangle The rectangle in the View's content coordinate space 6276 * @param immediate True to forbid animated scrolling, false otherwise 6277 * @return Whether any parent scrolled. 6278 */ 6279 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6280 if (mParent == null) { 6281 return false; 6282 } 6283 6284 View child = this; 6285 6286 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6287 position.set(rectangle); 6288 6289 ViewParent parent = mParent; 6290 boolean scrolled = false; 6291 while (parent != null) { 6292 rectangle.set((int) position.left, (int) position.top, 6293 (int) position.right, (int) position.bottom); 6294 6295 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6296 6297 if (!(parent instanceof View)) { 6298 break; 6299 } 6300 6301 // move it from child's content coordinate space to parent's content coordinate space 6302 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6303 6304 child = (View) parent; 6305 parent = child.getParent(); 6306 } 6307 6308 return scrolled; 6309 } 6310 6311 /** 6312 * Called when this view wants to give up focus. If focus is cleared 6313 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6314 * <p> 6315 * <strong>Note:</strong> When a View clears focus the framework is trying 6316 * to give focus to the first focusable View from the top. Hence, if this 6317 * View is the first from the top that can take focus, then all callbacks 6318 * related to clearing focus will be invoked after which the framework will 6319 * give focus to this view. 6320 * </p> 6321 */ 6322 public void clearFocus() { 6323 if (DBG) { 6324 System.out.println(this + " clearFocus()"); 6325 } 6326 6327 clearFocusInternal(null, true, true); 6328 } 6329 6330 /** 6331 * Clears focus from the view, optionally propagating the change up through 6332 * the parent hierarchy and requesting that the root view place new focus. 6333 * 6334 * @param propagate whether to propagate the change up through the parent 6335 * hierarchy 6336 * @param refocus when propagate is true, specifies whether to request the 6337 * root view place new focus 6338 */ 6339 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6340 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6341 mPrivateFlags &= ~PFLAG_FOCUSED; 6342 6343 if (propagate && mParent != null) { 6344 mParent.clearChildFocus(this); 6345 } 6346 6347 onFocusChanged(false, 0, null); 6348 refreshDrawableState(); 6349 6350 if (propagate && (!refocus || !rootViewRequestFocus())) { 6351 notifyGlobalFocusCleared(this); 6352 } 6353 } 6354 } 6355 6356 void notifyGlobalFocusCleared(View oldFocus) { 6357 if (oldFocus != null && mAttachInfo != null) { 6358 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6359 } 6360 } 6361 6362 boolean rootViewRequestFocus() { 6363 final View root = getRootView(); 6364 return root != null && root.requestFocus(); 6365 } 6366 6367 /** 6368 * Called internally by the view system when a new view is getting focus. 6369 * This is what clears the old focus. 6370 * <p> 6371 * <b>NOTE:</b> The parent view's focused child must be updated manually 6372 * after calling this method. Otherwise, the view hierarchy may be left in 6373 * an inconstent state. 6374 */ 6375 void unFocus(View focused) { 6376 if (DBG) { 6377 System.out.println(this + " unFocus()"); 6378 } 6379 6380 clearFocusInternal(focused, false, false); 6381 } 6382 6383 /** 6384 * Returns true if this view has focus itself, or is the ancestor of the 6385 * view that has focus. 6386 * 6387 * @return True if this view has or contains focus, false otherwise. 6388 */ 6389 @ViewDebug.ExportedProperty(category = "focus") 6390 public boolean hasFocus() { 6391 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6392 } 6393 6394 /** 6395 * Returns true if this view is focusable or if it contains a reachable View 6396 * for which {@link #hasFocusable()} returns true. A "reachable hasFocusable()" 6397 * is a View whose parents do not block descendants focus. 6398 * 6399 * Only {@link #VISIBLE} views are considered focusable. 6400 * 6401 * @return True if the view is focusable or if the view contains a focusable 6402 * View, false otherwise. 6403 * 6404 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6405 * @see ViewGroup#getTouchscreenBlocksFocus() 6406 */ 6407 public boolean hasFocusable() { 6408 if (!isFocusableInTouchMode()) { 6409 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6410 final ViewGroup g = (ViewGroup) p; 6411 if (g.shouldBlockFocusForTouchscreen()) { 6412 return false; 6413 } 6414 } 6415 } 6416 return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable(); 6417 } 6418 6419 /** 6420 * Called by the view system when the focus state of this view changes. 6421 * When the focus change event is caused by directional navigation, direction 6422 * and previouslyFocusedRect provide insight into where the focus is coming from. 6423 * When overriding, be sure to call up through to the super class so that 6424 * the standard focus handling will occur. 6425 * 6426 * @param gainFocus True if the View has focus; false otherwise. 6427 * @param direction The direction focus has moved when requestFocus() 6428 * is called to give this view focus. Values are 6429 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6430 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6431 * It may not always apply, in which case use the default. 6432 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6433 * system, of the previously focused view. If applicable, this will be 6434 * passed in as finer grained information about where the focus is coming 6435 * from (in addition to direction). Will be <code>null</code> otherwise. 6436 */ 6437 @CallSuper 6438 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6439 @Nullable Rect previouslyFocusedRect) { 6440 if (gainFocus) { 6441 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6442 } else { 6443 notifyViewAccessibilityStateChangedIfNeeded( 6444 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6445 } 6446 6447 InputMethodManager imm = InputMethodManager.peekInstance(); 6448 if (!gainFocus) { 6449 if (isPressed()) { 6450 setPressed(false); 6451 } 6452 if (imm != null && mAttachInfo != null 6453 && mAttachInfo.mHasWindowFocus) { 6454 imm.focusOut(this); 6455 } 6456 onFocusLost(); 6457 } else if (imm != null && mAttachInfo != null 6458 && mAttachInfo.mHasWindowFocus) { 6459 imm.focusIn(this); 6460 } 6461 6462 invalidate(true); 6463 ListenerInfo li = mListenerInfo; 6464 if (li != null && li.mOnFocusChangeListener != null) { 6465 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6466 } 6467 6468 if (mAttachInfo != null) { 6469 mAttachInfo.mKeyDispatchState.reset(this); 6470 } 6471 } 6472 6473 /** 6474 * Sends an accessibility event of the given type. If accessibility is 6475 * not enabled this method has no effect. The default implementation calls 6476 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6477 * to populate information about the event source (this View), then calls 6478 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6479 * populate the text content of the event source including its descendants, 6480 * and last calls 6481 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6482 * on its parent to request sending of the event to interested parties. 6483 * <p> 6484 * If an {@link AccessibilityDelegate} has been specified via calling 6485 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6486 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6487 * responsible for handling this call. 6488 * </p> 6489 * 6490 * @param eventType The type of the event to send, as defined by several types from 6491 * {@link android.view.accessibility.AccessibilityEvent}, such as 6492 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6493 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6494 * 6495 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6496 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6497 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6498 * @see AccessibilityDelegate 6499 */ 6500 public void sendAccessibilityEvent(int eventType) { 6501 if (mAccessibilityDelegate != null) { 6502 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6503 } else { 6504 sendAccessibilityEventInternal(eventType); 6505 } 6506 } 6507 6508 /** 6509 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6510 * {@link AccessibilityEvent} to make an announcement which is related to some 6511 * sort of a context change for which none of the events representing UI transitions 6512 * is a good fit. For example, announcing a new page in a book. If accessibility 6513 * is not enabled this method does nothing. 6514 * 6515 * @param text The announcement text. 6516 */ 6517 public void announceForAccessibility(CharSequence text) { 6518 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6519 AccessibilityEvent event = AccessibilityEvent.obtain( 6520 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6521 onInitializeAccessibilityEvent(event); 6522 event.getText().add(text); 6523 event.setContentDescription(null); 6524 mParent.requestSendAccessibilityEvent(this, event); 6525 } 6526 } 6527 6528 /** 6529 * @see #sendAccessibilityEvent(int) 6530 * 6531 * Note: Called from the default {@link AccessibilityDelegate}. 6532 * 6533 * @hide 6534 */ 6535 public void sendAccessibilityEventInternal(int eventType) { 6536 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 6537 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 6538 } 6539 } 6540 6541 /** 6542 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 6543 * takes as an argument an empty {@link AccessibilityEvent} and does not 6544 * perform a check whether accessibility is enabled. 6545 * <p> 6546 * If an {@link AccessibilityDelegate} has been specified via calling 6547 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6548 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 6549 * is responsible for handling this call. 6550 * </p> 6551 * 6552 * @param event The event to send. 6553 * 6554 * @see #sendAccessibilityEvent(int) 6555 */ 6556 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 6557 if (mAccessibilityDelegate != null) { 6558 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 6559 } else { 6560 sendAccessibilityEventUncheckedInternal(event); 6561 } 6562 } 6563 6564 /** 6565 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 6566 * 6567 * Note: Called from the default {@link AccessibilityDelegate}. 6568 * 6569 * @hide 6570 */ 6571 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 6572 if (!isShown()) { 6573 return; 6574 } 6575 onInitializeAccessibilityEvent(event); 6576 // Only a subset of accessibility events populates text content. 6577 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 6578 dispatchPopulateAccessibilityEvent(event); 6579 } 6580 // In the beginning we called #isShown(), so we know that getParent() is not null. 6581 getParent().requestSendAccessibilityEvent(this, event); 6582 } 6583 6584 /** 6585 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 6586 * to its children for adding their text content to the event. Note that the 6587 * event text is populated in a separate dispatch path since we add to the 6588 * event not only the text of the source but also the text of all its descendants. 6589 * A typical implementation will call 6590 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 6591 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6592 * on each child. Override this method if custom population of the event text 6593 * content is required. 6594 * <p> 6595 * If an {@link AccessibilityDelegate} has been specified via calling 6596 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6597 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 6598 * is responsible for handling this call. 6599 * </p> 6600 * <p> 6601 * <em>Note:</em> Accessibility events of certain types are not dispatched for 6602 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 6603 * </p> 6604 * 6605 * @param event The event. 6606 * 6607 * @return True if the event population was completed. 6608 */ 6609 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 6610 if (mAccessibilityDelegate != null) { 6611 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 6612 } else { 6613 return dispatchPopulateAccessibilityEventInternal(event); 6614 } 6615 } 6616 6617 /** 6618 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6619 * 6620 * Note: Called from the default {@link AccessibilityDelegate}. 6621 * 6622 * @hide 6623 */ 6624 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6625 onPopulateAccessibilityEvent(event); 6626 return false; 6627 } 6628 6629 /** 6630 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6631 * giving a chance to this View to populate the accessibility event with its 6632 * text content. While this method is free to modify event 6633 * attributes other than text content, doing so should normally be performed in 6634 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 6635 * <p> 6636 * Example: Adding formatted date string to an accessibility event in addition 6637 * to the text added by the super implementation: 6638 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6639 * super.onPopulateAccessibilityEvent(event); 6640 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 6641 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 6642 * mCurrentDate.getTimeInMillis(), flags); 6643 * event.getText().add(selectedDateUtterance); 6644 * }</pre> 6645 * <p> 6646 * If an {@link AccessibilityDelegate} has been specified via calling 6647 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6648 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 6649 * is responsible for handling this call. 6650 * </p> 6651 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6652 * information to the event, in case the default implementation has basic information to add. 6653 * </p> 6654 * 6655 * @param event The accessibility event which to populate. 6656 * 6657 * @see #sendAccessibilityEvent(int) 6658 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6659 */ 6660 @CallSuper 6661 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6662 if (mAccessibilityDelegate != null) { 6663 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 6664 } else { 6665 onPopulateAccessibilityEventInternal(event); 6666 } 6667 } 6668 6669 /** 6670 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 6671 * 6672 * Note: Called from the default {@link AccessibilityDelegate}. 6673 * 6674 * @hide 6675 */ 6676 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6677 } 6678 6679 /** 6680 * Initializes an {@link AccessibilityEvent} with information about 6681 * this View which is the event source. In other words, the source of 6682 * an accessibility event is the view whose state change triggered firing 6683 * the event. 6684 * <p> 6685 * Example: Setting the password property of an event in addition 6686 * to properties set by the super implementation: 6687 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6688 * super.onInitializeAccessibilityEvent(event); 6689 * event.setPassword(true); 6690 * }</pre> 6691 * <p> 6692 * If an {@link AccessibilityDelegate} has been specified via calling 6693 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6694 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 6695 * is responsible for handling this call. 6696 * </p> 6697 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6698 * information to the event, in case the default implementation has basic information to add. 6699 * </p> 6700 * @param event The event to initialize. 6701 * 6702 * @see #sendAccessibilityEvent(int) 6703 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6704 */ 6705 @CallSuper 6706 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6707 if (mAccessibilityDelegate != null) { 6708 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 6709 } else { 6710 onInitializeAccessibilityEventInternal(event); 6711 } 6712 } 6713 6714 /** 6715 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6716 * 6717 * Note: Called from the default {@link AccessibilityDelegate}. 6718 * 6719 * @hide 6720 */ 6721 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 6722 event.setSource(this); 6723 event.setClassName(getAccessibilityClassName()); 6724 event.setPackageName(getContext().getPackageName()); 6725 event.setEnabled(isEnabled()); 6726 event.setContentDescription(mContentDescription); 6727 6728 switch (event.getEventType()) { 6729 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 6730 ArrayList<View> focusablesTempList = (mAttachInfo != null) 6731 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 6732 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 6733 event.setItemCount(focusablesTempList.size()); 6734 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 6735 if (mAttachInfo != null) { 6736 focusablesTempList.clear(); 6737 } 6738 } break; 6739 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 6740 CharSequence text = getIterableTextForAccessibility(); 6741 if (text != null && text.length() > 0) { 6742 event.setFromIndex(getAccessibilitySelectionStart()); 6743 event.setToIndex(getAccessibilitySelectionEnd()); 6744 event.setItemCount(text.length()); 6745 } 6746 } break; 6747 } 6748 } 6749 6750 /** 6751 * Returns an {@link AccessibilityNodeInfo} representing this view from the 6752 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 6753 * This method is responsible for obtaining an accessibility node info from a 6754 * pool of reusable instances and calling 6755 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 6756 * initialize the former. 6757 * <p> 6758 * Note: The client is responsible for recycling the obtained instance by calling 6759 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 6760 * </p> 6761 * 6762 * @return A populated {@link AccessibilityNodeInfo}. 6763 * 6764 * @see AccessibilityNodeInfo 6765 */ 6766 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 6767 if (mAccessibilityDelegate != null) { 6768 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 6769 } else { 6770 return createAccessibilityNodeInfoInternal(); 6771 } 6772 } 6773 6774 /** 6775 * @see #createAccessibilityNodeInfo() 6776 * 6777 * @hide 6778 */ 6779 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 6780 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 6781 if (provider != null) { 6782 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 6783 } else { 6784 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 6785 onInitializeAccessibilityNodeInfo(info); 6786 return info; 6787 } 6788 } 6789 6790 /** 6791 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 6792 * The base implementation sets: 6793 * <ul> 6794 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 6795 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 6796 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 6797 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 6798 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 6799 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 6800 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 6801 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 6802 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 6803 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 6804 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 6805 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 6806 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 6807 * </ul> 6808 * <p> 6809 * Subclasses should override this method, call the super implementation, 6810 * and set additional attributes. 6811 * </p> 6812 * <p> 6813 * If an {@link AccessibilityDelegate} has been specified via calling 6814 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6815 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 6816 * is responsible for handling this call. 6817 * </p> 6818 * 6819 * @param info The instance to initialize. 6820 */ 6821 @CallSuper 6822 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 6823 if (mAccessibilityDelegate != null) { 6824 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 6825 } else { 6826 onInitializeAccessibilityNodeInfoInternal(info); 6827 } 6828 } 6829 6830 /** 6831 * Gets the location of this view in screen coordinates. 6832 * 6833 * @param outRect The output location 6834 * @hide 6835 */ 6836 public void getBoundsOnScreen(Rect outRect) { 6837 getBoundsOnScreen(outRect, false); 6838 } 6839 6840 /** 6841 * Gets the location of this view in screen coordinates. 6842 * 6843 * @param outRect The output location 6844 * @param clipToParent Whether to clip child bounds to the parent ones. 6845 * @hide 6846 */ 6847 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 6848 if (mAttachInfo == null) { 6849 return; 6850 } 6851 6852 RectF position = mAttachInfo.mTmpTransformRect; 6853 position.set(0, 0, mRight - mLeft, mBottom - mTop); 6854 6855 if (!hasIdentityMatrix()) { 6856 getMatrix().mapRect(position); 6857 } 6858 6859 position.offset(mLeft, mTop); 6860 6861 ViewParent parent = mParent; 6862 while (parent instanceof View) { 6863 View parentView = (View) parent; 6864 6865 position.offset(-parentView.mScrollX, -parentView.mScrollY); 6866 6867 if (clipToParent) { 6868 position.left = Math.max(position.left, 0); 6869 position.top = Math.max(position.top, 0); 6870 position.right = Math.min(position.right, parentView.getWidth()); 6871 position.bottom = Math.min(position.bottom, parentView.getHeight()); 6872 } 6873 6874 if (!parentView.hasIdentityMatrix()) { 6875 parentView.getMatrix().mapRect(position); 6876 } 6877 6878 position.offset(parentView.mLeft, parentView.mTop); 6879 6880 parent = parentView.mParent; 6881 } 6882 6883 if (parent instanceof ViewRootImpl) { 6884 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 6885 position.offset(0, -viewRootImpl.mCurScrollY); 6886 } 6887 6888 position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 6889 6890 outRect.set(Math.round(position.left), Math.round(position.top), 6891 Math.round(position.right), Math.round(position.bottom)); 6892 } 6893 6894 /** 6895 * Return the class name of this object to be used for accessibility purposes. 6896 * Subclasses should only override this if they are implementing something that 6897 * should be seen as a completely new class of view when used by accessibility, 6898 * unrelated to the class it is deriving from. This is used to fill in 6899 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 6900 */ 6901 public CharSequence getAccessibilityClassName() { 6902 return View.class.getName(); 6903 } 6904 6905 /** 6906 * Called when assist structure is being retrieved from a view as part of 6907 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 6908 * @param structure Fill in with structured view data. The default implementation 6909 * fills in all data that can be inferred from the view itself. 6910 */ 6911 public void onProvideStructure(ViewStructure structure) { 6912 onProvideStructureForAssistOrAutoFill(structure, 0); 6913 } 6914 6915 /** 6916 * Called when assist structure is being retrieved from a view as part of an auto-fill request. 6917 * 6918 * <p>The structure must be filled according to the request type, which is set in the 6919 * {@code flags} parameter - see the documentation on each flag for more details. 6920 * 6921 * @param structure Fill in with structured view data. The default implementation 6922 * fills in all data that can be inferred from the view itself. 6923 * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and 6924 * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info). 6925 */ 6926 public void onProvideAutoFillStructure(ViewStructure structure, int flags) { 6927 onProvideStructureForAssistOrAutoFill(structure, flags); 6928 } 6929 6930 private void onProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) { 6931 // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well, 6932 // this method should take a boolean with the type of request. 6933 boolean forAutoFill = (flags 6934 & (View.AUTO_FILL_FLAG_TYPE_FILL 6935 | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0; 6936 final int id = mID; 6937 if (id != NO_ID && !isViewIdGenerated(id)) { 6938 String pkg, type, entry; 6939 try { 6940 final Resources res = getResources(); 6941 entry = res.getResourceEntryName(id); 6942 type = res.getResourceTypeName(id); 6943 pkg = res.getResourcePackageName(id); 6944 } catch (Resources.NotFoundException e) { 6945 entry = type = pkg = null; 6946 } 6947 structure.setId(id, pkg, type, entry); 6948 } else { 6949 structure.setId(id, null, null, null); 6950 } 6951 6952 if (forAutoFill) { 6953 // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to 6954 // reuse the accessibility id to save space. 6955 structure.setAutoFillId(getAccessibilityViewId()); 6956 6957 structure.setAutoFillType(getAutoFillType()); 6958 } 6959 6960 structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop); 6961 if (!hasIdentityMatrix()) { 6962 structure.setTransformation(getMatrix()); 6963 } 6964 structure.setElevation(getZ()); 6965 structure.setVisibility(getVisibility()); 6966 structure.setEnabled(isEnabled()); 6967 if (isClickable()) { 6968 structure.setClickable(true); 6969 } 6970 if (isFocusable()) { 6971 structure.setFocusable(true); 6972 } 6973 if (isFocused()) { 6974 structure.setFocused(true); 6975 } 6976 if (isAccessibilityFocused()) { 6977 structure.setAccessibilityFocused(true); 6978 } 6979 if (isSelected()) { 6980 structure.setSelected(true); 6981 } 6982 if (isActivated()) { 6983 structure.setActivated(true); 6984 } 6985 if (isLongClickable()) { 6986 structure.setLongClickable(true); 6987 } 6988 if (this instanceof Checkable) { 6989 structure.setCheckable(true); 6990 if (((Checkable)this).isChecked()) { 6991 structure.setChecked(true); 6992 } 6993 } 6994 if (isContextClickable()) { 6995 structure.setContextClickable(true); 6996 } 6997 structure.setClassName(getAccessibilityClassName().toString()); 6998 structure.setContentDescription(getContentDescription()); 6999 } 7000 7001 /** 7002 * Called when assist structure is being retrieved from a view as part of 7003 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 7004 * generate additional virtual structure under this view. The defaullt implementation 7005 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 7006 * view's virtual accessibility nodes, if any. You can override this for a more 7007 * optimal implementation providing this data. 7008 */ 7009 public void onProvideVirtualStructure(ViewStructure structure) { 7010 onProvideVirtualStructureForAssistOrAutoFill(structure, 0); 7011 } 7012 7013 /** 7014 * Called when assist structure is being retrieved from a view as part of an auto-fill request 7015 * to generate additional virtual structure under this view. 7016 * 7017 * <p>The defaullt implementation uses {@link #getAccessibilityNodeProvider()} to try to 7018 * generate this from the view's virtual accessibility nodes, if any. You can override this 7019 * for a more optimal implementation providing this data. 7020 * 7021 * <p>The structure must be filled according to the request type, which is set in the 7022 * {@code flags} parameter - see the documentation on each flag for more details. 7023 * 7024 * @param structure Fill in with structured view data. 7025 * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and 7026 * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info). 7027 */ 7028 public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) { 7029 onProvideVirtualStructureForAssistOrAutoFill(structure, flags); 7030 } 7031 7032 private void onProvideVirtualStructureForAssistOrAutoFill(ViewStructure structure, int flags) { 7033 // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well, 7034 // this method should take a boolean with the type of request. 7035 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7036 if (provider != null) { 7037 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7038 structure.setChildCount(1); 7039 ViewStructure root = structure.newChild(0); 7040 populateVirtualStructure(root, provider, info, flags); 7041 info.recycle(); 7042 } 7043 } 7044 7045 /** 7046 * Gets the {@link VirtualViewDelegate} responsible for auto-filling the virtual children of 7047 * this view. 7048 * 7049 * <p>By default returns {@code null} but should be overridden when view provides a virtual 7050 * hierachy on {@link OnProvideAssistDataListener} that takes flags used by the AutoFill 7051 * Framework (such as {@link #AUTO_FILL_FLAG_TYPE_FILL} and 7052 * {@link #AUTO_FILL_FLAG_TYPE_SAVE}). 7053 */ 7054 @Nullable 7055 public VirtualViewDelegate getAutoFillVirtualViewDelegate( 7056 @SuppressWarnings("unused") VirtualViewDelegate.Callback callback) { 7057 return null; 7058 } 7059 7060 /** 7061 * Automatically fills the content of this view with the {@code value}. 7062 * 7063 * <p>By default does nothing, but views should override it (and {@link #getAutoFillType()} to 7064 * support the AutoFill Framework. 7065 * 7066 * <p>Typically, it is implemented by: 7067 * 7068 * <ol> 7069 * <li>Call the proper getter method on {@link AutoFillValue} to fetch the actual value. 7070 * <li>Pass the actual value to the equivalent setter in the view. 7071 * <ol> 7072 * 7073 * <p>For example, a text-field view would call: 7074 * 7075 * <pre class="prettyprint"> 7076 * CharSequence text = value.getTextValue(); 7077 * if (text != null) { 7078 * setText(text); 7079 * } 7080 * </pre> 7081 */ 7082 public void autoFill(@SuppressWarnings("unused") AutoFillValue value) { 7083 } 7084 7085 /** 7086 * Describes the auto-fill type that should be used on callas to 7087 * {@link #autoFill(AutoFillValue)} and 7088 * {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}. 7089 * 7090 * <p>By default returns {@code null}, but views should override it (and 7091 * {@link #autoFill(AutoFillValue)} to support the AutoFill Framework. 7092 */ 7093 @Nullable 7094 public AutoFillType getAutoFillType() { 7095 return null; 7096 } 7097 7098 private void populateVirtualStructure(ViewStructure structure, 7099 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, int flags) { 7100 // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well, 7101 // this method should take a boolean with the type of request. 7102 7103 final boolean sanitized = (flags & View.AUTO_FILL_FLAG_TYPE_FILL) != 0; 7104 7105 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 7106 null, null, null); 7107 Rect rect = structure.getTempRect(); 7108 info.getBoundsInParent(rect); 7109 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 7110 structure.setVisibility(VISIBLE); 7111 structure.setEnabled(info.isEnabled()); 7112 if (info.isClickable()) { 7113 structure.setClickable(true); 7114 } 7115 if (info.isFocusable()) { 7116 structure.setFocusable(true); 7117 } 7118 if (info.isFocused()) { 7119 structure.setFocused(true); 7120 } 7121 if (info.isAccessibilityFocused()) { 7122 structure.setAccessibilityFocused(true); 7123 } 7124 if (info.isSelected()) { 7125 structure.setSelected(true); 7126 } 7127 if (info.isLongClickable()) { 7128 structure.setLongClickable(true); 7129 } 7130 if (info.isCheckable()) { 7131 structure.setCheckable(true); 7132 if (info.isChecked()) { 7133 structure.setChecked(true); 7134 } 7135 } 7136 if (info.isContextClickable()) { 7137 structure.setContextClickable(true); 7138 } 7139 CharSequence cname = info.getClassName(); 7140 structure.setClassName(cname != null ? cname.toString() : null); 7141 structure.setContentDescription(info.getContentDescription()); 7142 if (!sanitized && (info.getText() != null || info.getError() != null)) { 7143 // TODO(b/33197203) (b/33269702): when sanitized, try to use the Accessibility API to 7144 // just set sanitized values (like text coming from resource files), rather than not 7145 // setting it at all. 7146 structure.setText(info.getText(), info.getTextSelectionStart(), 7147 info.getTextSelectionEnd()); 7148 } 7149 final int NCHILDREN = info.getChildCount(); 7150 if (NCHILDREN > 0) { 7151 structure.setChildCount(NCHILDREN); 7152 for (int i=0; i<NCHILDREN; i++) { 7153 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 7154 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 7155 ViewStructure child = structure.newChild(i); 7156 populateVirtualStructure(child, provider, cinfo, flags); 7157 cinfo.recycle(); 7158 } 7159 } 7160 } 7161 7162 /** 7163 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 7164 * implementation calls {@link #onProvideStructure} and 7165 * {@link #onProvideVirtualStructure}. 7166 */ 7167 public void dispatchProvideStructure(ViewStructure structure) { 7168 dispatchProvideStructureForAssistOrAutoFill(structure, 0); 7169 } 7170 7171 /** 7172 * Dispatch creation of {@link ViewStructure} down the hierarchy. 7173 * 7174 * <p>The structure must be filled according to the request type, which is set in the 7175 * {@code flags} parameter - see the documentation on each flag for more details. 7176 * 7177 * <p>The default implementation calls {@link #onProvideAutoFillStructure(ViewStructure, int)} 7178 * and {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)}. 7179 * 7180 * @param structure Fill in with structured view data. 7181 * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and 7182 * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info). 7183 */ 7184 public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) { 7185 dispatchProvideStructureForAssistOrAutoFill(structure, flags); 7186 } 7187 7188 private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) { 7189 // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well, 7190 // this method should take a boolean with the type of request. 7191 boolean forAutoFill = (flags 7192 & (View.AUTO_FILL_FLAG_TYPE_FILL 7193 | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0; 7194 7195 boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked(); 7196 if (!blocked) { 7197 if (forAutoFill) { 7198 onProvideAutoFillStructure(structure, flags); 7199 onProvideAutoFillVirtualStructure(structure, flags); 7200 } else { 7201 onProvideStructure(structure); 7202 onProvideVirtualStructure(structure); 7203 } 7204 } else { 7205 structure.setClassName(getAccessibilityClassName().toString()); 7206 structure.setAssistBlocked(true); 7207 } 7208 } 7209 7210 /** 7211 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 7212 * 7213 * Note: Called from the default {@link AccessibilityDelegate}. 7214 * 7215 * @hide 7216 */ 7217 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 7218 if (mAttachInfo == null) { 7219 return; 7220 } 7221 7222 Rect bounds = mAttachInfo.mTmpInvalRect; 7223 7224 getDrawingRect(bounds); 7225 info.setBoundsInParent(bounds); 7226 7227 getBoundsOnScreen(bounds, true); 7228 info.setBoundsInScreen(bounds); 7229 7230 ViewParent parent = getParentForAccessibility(); 7231 if (parent instanceof View) { 7232 info.setParent((View) parent); 7233 } 7234 7235 if (mID != View.NO_ID) { 7236 View rootView = getRootView(); 7237 if (rootView == null) { 7238 rootView = this; 7239 } 7240 7241 View label = rootView.findLabelForView(this, mID); 7242 if (label != null) { 7243 info.setLabeledBy(label); 7244 } 7245 7246 if ((mAttachInfo.mAccessibilityFetchFlags 7247 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 7248 && Resources.resourceHasPackage(mID)) { 7249 try { 7250 String viewId = getResources().getResourceName(mID); 7251 info.setViewIdResourceName(viewId); 7252 } catch (Resources.NotFoundException nfe) { 7253 /* ignore */ 7254 } 7255 } 7256 } 7257 7258 if (mLabelForId != View.NO_ID) { 7259 View rootView = getRootView(); 7260 if (rootView == null) { 7261 rootView = this; 7262 } 7263 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 7264 if (labeled != null) { 7265 info.setLabelFor(labeled); 7266 } 7267 } 7268 7269 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 7270 View rootView = getRootView(); 7271 if (rootView == null) { 7272 rootView = this; 7273 } 7274 View next = rootView.findViewInsideOutShouldExist(this, 7275 mAccessibilityTraversalBeforeId); 7276 if (next != null && next.includeForAccessibility()) { 7277 info.setTraversalBefore(next); 7278 } 7279 } 7280 7281 if (mAccessibilityTraversalAfterId != View.NO_ID) { 7282 View rootView = getRootView(); 7283 if (rootView == null) { 7284 rootView = this; 7285 } 7286 View next = rootView.findViewInsideOutShouldExist(this, 7287 mAccessibilityTraversalAfterId); 7288 if (next != null && next.includeForAccessibility()) { 7289 info.setTraversalAfter(next); 7290 } 7291 } 7292 7293 info.setVisibleToUser(isVisibleToUser()); 7294 7295 info.setImportantForAccessibility(isImportantForAccessibility()); 7296 info.setPackageName(mContext.getPackageName()); 7297 info.setClassName(getAccessibilityClassName()); 7298 info.setContentDescription(getContentDescription()); 7299 7300 info.setEnabled(isEnabled()); 7301 info.setClickable(isClickable()); 7302 info.setFocusable(isFocusable()); 7303 info.setFocused(isFocused()); 7304 info.setAccessibilityFocused(isAccessibilityFocused()); 7305 info.setSelected(isSelected()); 7306 info.setLongClickable(isLongClickable()); 7307 info.setContextClickable(isContextClickable()); 7308 info.setLiveRegion(getAccessibilityLiveRegion()); 7309 7310 // TODO: These make sense only if we are in an AdapterView but all 7311 // views can be selected. Maybe from accessibility perspective 7312 // we should report as selectable view in an AdapterView. 7313 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 7314 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 7315 7316 if (isFocusable()) { 7317 if (isFocused()) { 7318 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 7319 } else { 7320 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 7321 } 7322 } 7323 7324 if (!isAccessibilityFocused()) { 7325 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 7326 } else { 7327 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 7328 } 7329 7330 if (isClickable() && isEnabled()) { 7331 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 7332 } 7333 7334 if (isLongClickable() && isEnabled()) { 7335 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 7336 } 7337 7338 if (isContextClickable() && isEnabled()) { 7339 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 7340 } 7341 7342 CharSequence text = getIterableTextForAccessibility(); 7343 if (text != null && text.length() > 0) { 7344 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 7345 7346 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 7347 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 7348 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 7349 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 7350 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 7351 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 7352 } 7353 7354 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 7355 populateAccessibilityNodeInfoDrawingOrderInParent(info); 7356 } 7357 7358 /** 7359 * Determine the order in which this view will be drawn relative to its siblings for a11y 7360 * 7361 * @param info The info whose drawing order should be populated 7362 */ 7363 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 7364 /* 7365 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 7366 * drawing order may not be well-defined, and some Views with custom drawing order may 7367 * not be initialized sufficiently to respond properly getChildDrawingOrder. 7368 */ 7369 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 7370 info.setDrawingOrder(0); 7371 return; 7372 } 7373 int drawingOrderInParent = 1; 7374 // Iterate up the hierarchy if parents are not important for a11y 7375 View viewAtDrawingLevel = this; 7376 final ViewParent parent = getParentForAccessibility(); 7377 while (viewAtDrawingLevel != parent) { 7378 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 7379 if (!(currentParent instanceof ViewGroup)) { 7380 // Should only happen for the Decor 7381 drawingOrderInParent = 0; 7382 break; 7383 } else { 7384 final ViewGroup parentGroup = (ViewGroup) currentParent; 7385 final int childCount = parentGroup.getChildCount(); 7386 if (childCount > 1) { 7387 List<View> preorderedList = parentGroup.buildOrderedChildList(); 7388 if (preorderedList != null) { 7389 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 7390 for (int i = 0; i < childDrawIndex; i++) { 7391 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 7392 } 7393 } else { 7394 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 7395 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 7396 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 7397 .getChildDrawingOrder(childCount, childIndex) : childIndex; 7398 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 7399 if (childDrawIndex != 0) { 7400 for (int i = 0; i < numChildrenToIterate; i++) { 7401 final int otherDrawIndex = (customOrder ? 7402 parentGroup.getChildDrawingOrder(childCount, i) : i); 7403 if (otherDrawIndex < childDrawIndex) { 7404 drawingOrderInParent += 7405 numViewsForAccessibility(parentGroup.getChildAt(i)); 7406 } 7407 } 7408 } 7409 } 7410 } 7411 } 7412 viewAtDrawingLevel = (View) currentParent; 7413 } 7414 info.setDrawingOrder(drawingOrderInParent); 7415 } 7416 7417 private static int numViewsForAccessibility(View view) { 7418 if (view != null) { 7419 if (view.includeForAccessibility()) { 7420 return 1; 7421 } else if (view instanceof ViewGroup) { 7422 return ((ViewGroup) view).getNumChildrenForAccessibility(); 7423 } 7424 } 7425 return 0; 7426 } 7427 7428 private View findLabelForView(View view, int labeledId) { 7429 if (mMatchLabelForPredicate == null) { 7430 mMatchLabelForPredicate = new MatchLabelForPredicate(); 7431 } 7432 mMatchLabelForPredicate.mLabeledId = labeledId; 7433 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 7434 } 7435 7436 /** 7437 * Computes whether this view is visible to the user. Such a view is 7438 * attached, visible, all its predecessors are visible, it is not clipped 7439 * entirely by its predecessors, and has an alpha greater than zero. 7440 * 7441 * @return Whether the view is visible on the screen. 7442 * 7443 * @hide 7444 */ 7445 protected boolean isVisibleToUser() { 7446 return isVisibleToUser(null); 7447 } 7448 7449 /** 7450 * Computes whether the given portion of this view is visible to the user. 7451 * Such a view is attached, visible, all its predecessors are visible, 7452 * has an alpha greater than zero, and the specified portion is not 7453 * clipped entirely by its predecessors. 7454 * 7455 * @param boundInView the portion of the view to test; coordinates should be relative; may be 7456 * <code>null</code>, and the entire view will be tested in this case. 7457 * When <code>true</code> is returned by the function, the actual visible 7458 * region will be stored in this parameter; that is, if boundInView is fully 7459 * contained within the view, no modification will be made, otherwise regions 7460 * outside of the visible area of the view will be clipped. 7461 * 7462 * @return Whether the specified portion of the view is visible on the screen. 7463 * 7464 * @hide 7465 */ 7466 protected boolean isVisibleToUser(Rect boundInView) { 7467 if (mAttachInfo != null) { 7468 // Attached to invisible window means this view is not visible. 7469 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 7470 return false; 7471 } 7472 // An invisible predecessor or one with alpha zero means 7473 // that this view is not visible to the user. 7474 Object current = this; 7475 while (current instanceof View) { 7476 View view = (View) current; 7477 // We have attach info so this view is attached and there is no 7478 // need to check whether we reach to ViewRootImpl on the way up. 7479 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 7480 view.getVisibility() != VISIBLE) { 7481 return false; 7482 } 7483 current = view.mParent; 7484 } 7485 // Check if the view is entirely covered by its predecessors. 7486 Rect visibleRect = mAttachInfo.mTmpInvalRect; 7487 Point offset = mAttachInfo.mPoint; 7488 if (!getGlobalVisibleRect(visibleRect, offset)) { 7489 return false; 7490 } 7491 // Check if the visible portion intersects the rectangle of interest. 7492 if (boundInView != null) { 7493 visibleRect.offset(-offset.x, -offset.y); 7494 return boundInView.intersect(visibleRect); 7495 } 7496 return true; 7497 } 7498 return false; 7499 } 7500 7501 /** 7502 * Returns the delegate for implementing accessibility support via 7503 * composition. For more details see {@link AccessibilityDelegate}. 7504 * 7505 * @return The delegate, or null if none set. 7506 * 7507 * @hide 7508 */ 7509 public AccessibilityDelegate getAccessibilityDelegate() { 7510 return mAccessibilityDelegate; 7511 } 7512 7513 /** 7514 * Sets a delegate for implementing accessibility support via composition 7515 * (as opposed to inheritance). For more details, see 7516 * {@link AccessibilityDelegate}. 7517 * <p> 7518 * <strong>Note:</strong> On platform versions prior to 7519 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 7520 * views in the {@code android.widget.*} package are called <i>before</i> 7521 * host methods. This prevents certain properties such as class name from 7522 * being modified by overriding 7523 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 7524 * as any changes will be overwritten by the host class. 7525 * <p> 7526 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 7527 * methods are called <i>after</i> host methods, which all properties to be 7528 * modified without being overwritten by the host class. 7529 * 7530 * @param delegate the object to which accessibility method calls should be 7531 * delegated 7532 * @see AccessibilityDelegate 7533 */ 7534 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 7535 mAccessibilityDelegate = delegate; 7536 } 7537 7538 /** 7539 * Gets the provider for managing a virtual view hierarchy rooted at this View 7540 * and reported to {@link android.accessibilityservice.AccessibilityService}s 7541 * that explore the window content. 7542 * <p> 7543 * If this method returns an instance, this instance is responsible for managing 7544 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 7545 * View including the one representing the View itself. Similarly the returned 7546 * instance is responsible for performing accessibility actions on any virtual 7547 * view or the root view itself. 7548 * </p> 7549 * <p> 7550 * If an {@link AccessibilityDelegate} has been specified via calling 7551 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7552 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 7553 * is responsible for handling this call. 7554 * </p> 7555 * 7556 * @return The provider. 7557 * 7558 * @see AccessibilityNodeProvider 7559 */ 7560 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 7561 if (mAccessibilityDelegate != null) { 7562 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 7563 } else { 7564 return null; 7565 } 7566 } 7567 7568 /** 7569 * Gets the unique identifier of this view on the screen for accessibility purposes. 7570 * 7571 * @return The view accessibility id. 7572 * 7573 * @hide 7574 */ 7575 public int getAccessibilityViewId() { 7576 if (mAccessibilityViewId == NO_ID) { 7577 mAccessibilityViewId = sNextAccessibilityViewId++; 7578 } 7579 return mAccessibilityViewId; 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 * Gets the id of the root of the next keyboard navigation section. 8047 * @return The next keyboard navigation section ID, or {@link #NO_ID} if the framework should 8048 * decide automatically. 8049 * 8050 * @attr ref android.R.styleable#View_nextSectionForward 8051 */ 8052 public int getNextSectionForwardId() { 8053 return mNextSectionForwardId; 8054 } 8055 8056 /** 8057 * Sets the id of the view to use as the root of the next keyboard navigation section. 8058 * @param nextSectionForwardId The next section ID, or {@link #NO_ID} if the framework should 8059 * decide automatically. 8060 * 8061 * @attr ref android.R.styleable#View_nextSectionForward 8062 */ 8063 public void setNextSectionForwardId(int nextSectionForwardId) { 8064 mNextSectionForwardId = nextSectionForwardId; 8065 } 8066 8067 /** 8068 * Returns the visibility of this view and all of its ancestors 8069 * 8070 * @return True if this view and all of its ancestors are {@link #VISIBLE} 8071 */ 8072 public boolean isShown() { 8073 View current = this; 8074 //noinspection ConstantConditions 8075 do { 8076 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 8077 return false; 8078 } 8079 ViewParent parent = current.mParent; 8080 if (parent == null) { 8081 return false; // We are not attached to the view root 8082 } 8083 if (!(parent instanceof View)) { 8084 return true; 8085 } 8086 current = (View) parent; 8087 } while (current != null); 8088 8089 return false; 8090 } 8091 8092 /** 8093 * Called by the view hierarchy when the content insets for a window have 8094 * changed, to allow it to adjust its content to fit within those windows. 8095 * The content insets tell you the space that the status bar, input method, 8096 * and other system windows infringe on the application's window. 8097 * 8098 * <p>You do not normally need to deal with this function, since the default 8099 * window decoration given to applications takes care of applying it to the 8100 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 8101 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 8102 * and your content can be placed under those system elements. You can then 8103 * use this method within your view hierarchy if you have parts of your UI 8104 * which you would like to ensure are not being covered. 8105 * 8106 * <p>The default implementation of this method simply applies the content 8107 * insets to the view's padding, consuming that content (modifying the 8108 * insets to be 0), and returning true. This behavior is off by default, but can 8109 * be enabled through {@link #setFitsSystemWindows(boolean)}. 8110 * 8111 * <p>This function's traversal down the hierarchy is depth-first. The same content 8112 * insets object is propagated down the hierarchy, so any changes made to it will 8113 * be seen by all following views (including potentially ones above in 8114 * the hierarchy since this is a depth-first traversal). The first view 8115 * that returns true will abort the entire traversal. 8116 * 8117 * <p>The default implementation works well for a situation where it is 8118 * used with a container that covers the entire window, allowing it to 8119 * apply the appropriate insets to its content on all edges. If you need 8120 * a more complicated layout (such as two different views fitting system 8121 * windows, one on the top of the window, and one on the bottom), 8122 * you can override the method and handle the insets however you would like. 8123 * Note that the insets provided by the framework are always relative to the 8124 * far edges of the window, not accounting for the location of the called view 8125 * within that window. (In fact when this method is called you do not yet know 8126 * where the layout will place the view, as it is done before layout happens.) 8127 * 8128 * <p>Note: unlike many View methods, there is no dispatch phase to this 8129 * call. If you are overriding it in a ViewGroup and want to allow the 8130 * call to continue to your children, you must be sure to call the super 8131 * implementation. 8132 * 8133 * <p>Here is a sample layout that makes use of fitting system windows 8134 * to have controls for a video view placed inside of the window decorations 8135 * that it hides and shows. This can be used with code like the second 8136 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 8137 * 8138 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 8139 * 8140 * @param insets Current content insets of the window. Prior to 8141 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 8142 * the insets or else you and Android will be unhappy. 8143 * 8144 * @return {@code true} if this view applied the insets and it should not 8145 * continue propagating further down the hierarchy, {@code false} otherwise. 8146 * @see #getFitsSystemWindows() 8147 * @see #setFitsSystemWindows(boolean) 8148 * @see #setSystemUiVisibility(int) 8149 * 8150 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 8151 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 8152 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 8153 * to implement handling their own insets. 8154 */ 8155 @Deprecated 8156 protected boolean fitSystemWindows(Rect insets) { 8157 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 8158 if (insets == null) { 8159 // Null insets by definition have already been consumed. 8160 // This call cannot apply insets since there are none to apply, 8161 // so return false. 8162 return false; 8163 } 8164 // If we're not in the process of dispatching the newer apply insets call, 8165 // that means we're not in the compatibility path. Dispatch into the newer 8166 // apply insets path and take things from there. 8167 try { 8168 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 8169 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 8170 } finally { 8171 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 8172 } 8173 } else { 8174 // We're being called from the newer apply insets path. 8175 // Perform the standard fallback behavior. 8176 return fitSystemWindowsInt(insets); 8177 } 8178 } 8179 8180 private boolean fitSystemWindowsInt(Rect insets) { 8181 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 8182 mUserPaddingStart = UNDEFINED_PADDING; 8183 mUserPaddingEnd = UNDEFINED_PADDING; 8184 Rect localInsets = sThreadLocal.get(); 8185 if (localInsets == null) { 8186 localInsets = new Rect(); 8187 sThreadLocal.set(localInsets); 8188 } 8189 boolean res = computeFitSystemWindows(insets, localInsets); 8190 mUserPaddingLeftInitial = localInsets.left; 8191 mUserPaddingRightInitial = localInsets.right; 8192 internalSetPadding(localInsets.left, localInsets.top, 8193 localInsets.right, localInsets.bottom); 8194 return res; 8195 } 8196 return false; 8197 } 8198 8199 /** 8200 * Called when the view should apply {@link WindowInsets} according to its internal policy. 8201 * 8202 * <p>This method should be overridden by views that wish to apply a policy different from or 8203 * in addition to the default behavior. Clients that wish to force a view subtree 8204 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 8205 * 8206 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 8207 * it will be called during dispatch instead of this method. The listener may optionally 8208 * call this method from its own implementation if it wishes to apply the view's default 8209 * insets policy in addition to its own.</p> 8210 * 8211 * <p>Implementations of this method should either return the insets parameter unchanged 8212 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 8213 * that this view applied itself. This allows new inset types added in future platform 8214 * versions to pass through existing implementations unchanged without being erroneously 8215 * consumed.</p> 8216 * 8217 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 8218 * property is set then the view will consume the system window insets and apply them 8219 * as padding for the view.</p> 8220 * 8221 * @param insets Insets to apply 8222 * @return The supplied insets with any applied insets consumed 8223 */ 8224 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 8225 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 8226 // We weren't called from within a direct call to fitSystemWindows, 8227 // call into it as a fallback in case we're in a class that overrides it 8228 // and has logic to perform. 8229 if (fitSystemWindows(insets.getSystemWindowInsets())) { 8230 return insets.consumeSystemWindowInsets(); 8231 } 8232 } else { 8233 // We were called from within a direct call to fitSystemWindows. 8234 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 8235 return insets.consumeSystemWindowInsets(); 8236 } 8237 } 8238 return insets; 8239 } 8240 8241 /** 8242 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 8243 * window insets to this view. The listener's 8244 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 8245 * method will be called instead of the view's 8246 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 8247 * 8248 * @param listener Listener to set 8249 * 8250 * @see #onApplyWindowInsets(WindowInsets) 8251 */ 8252 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 8253 getListenerInfo().mOnApplyWindowInsetsListener = listener; 8254 } 8255 8256 /** 8257 * Request to apply the given window insets to this view or another view in its subtree. 8258 * 8259 * <p>This method should be called by clients wishing to apply insets corresponding to areas 8260 * obscured by window decorations or overlays. This can include the status and navigation bars, 8261 * action bars, input methods and more. New inset categories may be added in the future. 8262 * The method returns the insets provided minus any that were applied by this view or its 8263 * children.</p> 8264 * 8265 * <p>Clients wishing to provide custom behavior should override the 8266 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 8267 * {@link OnApplyWindowInsetsListener} via the 8268 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 8269 * method.</p> 8270 * 8271 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 8272 * </p> 8273 * 8274 * @param insets Insets to apply 8275 * @return The provided insets minus the insets that were consumed 8276 */ 8277 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 8278 try { 8279 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 8280 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 8281 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 8282 } else { 8283 return onApplyWindowInsets(insets); 8284 } 8285 } finally { 8286 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 8287 } 8288 } 8289 8290 /** 8291 * Compute the view's coordinate within the surface. 8292 * 8293 * <p>Computes the coordinates of this view in its surface. The argument 8294 * must be an array of two integers. After the method returns, the array 8295 * contains the x and y location in that order.</p> 8296 * @hide 8297 * @param location an array of two integers in which to hold the coordinates 8298 */ 8299 public void getLocationInSurface(@Size(2) int[] location) { 8300 getLocationInWindow(location); 8301 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 8302 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 8303 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 8304 } 8305 } 8306 8307 /** 8308 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 8309 * only available if the view is attached. 8310 * 8311 * @return WindowInsets from the top of the view hierarchy or null if View is detached 8312 */ 8313 public WindowInsets getRootWindowInsets() { 8314 if (mAttachInfo != null) { 8315 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 8316 } 8317 return null; 8318 } 8319 8320 /** 8321 * @hide Compute the insets that should be consumed by this view and the ones 8322 * that should propagate to those under it. 8323 */ 8324 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 8325 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8326 || mAttachInfo == null 8327 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 8328 && !mAttachInfo.mOverscanRequested)) { 8329 outLocalInsets.set(inoutInsets); 8330 inoutInsets.set(0, 0, 0, 0); 8331 return true; 8332 } else { 8333 // The application wants to take care of fitting system window for 8334 // the content... however we still need to take care of any overscan here. 8335 final Rect overscan = mAttachInfo.mOverscanInsets; 8336 outLocalInsets.set(overscan); 8337 inoutInsets.left -= overscan.left; 8338 inoutInsets.top -= overscan.top; 8339 inoutInsets.right -= overscan.right; 8340 inoutInsets.bottom -= overscan.bottom; 8341 return false; 8342 } 8343 } 8344 8345 /** 8346 * Compute insets that should be consumed by this view and the ones that should propagate 8347 * to those under it. 8348 * 8349 * @param in Insets currently being processed by this View, likely received as a parameter 8350 * to {@link #onApplyWindowInsets(WindowInsets)}. 8351 * @param outLocalInsets A Rect that will receive the insets that should be consumed 8352 * by this view 8353 * @return Insets that should be passed along to views under this one 8354 */ 8355 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 8356 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8357 || mAttachInfo == null 8358 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 8359 outLocalInsets.set(in.getSystemWindowInsets()); 8360 return in.consumeSystemWindowInsets(); 8361 } else { 8362 outLocalInsets.set(0, 0, 0, 0); 8363 return in; 8364 } 8365 } 8366 8367 /** 8368 * Sets whether or not this view should account for system screen decorations 8369 * such as the status bar and inset its content; that is, controlling whether 8370 * the default implementation of {@link #fitSystemWindows(Rect)} will be 8371 * executed. See that method for more details. 8372 * 8373 * <p>Note that if you are providing your own implementation of 8374 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 8375 * flag to true -- your implementation will be overriding the default 8376 * implementation that checks this flag. 8377 * 8378 * @param fitSystemWindows If true, then the default implementation of 8379 * {@link #fitSystemWindows(Rect)} will be executed. 8380 * 8381 * @attr ref android.R.styleable#View_fitsSystemWindows 8382 * @see #getFitsSystemWindows() 8383 * @see #fitSystemWindows(Rect) 8384 * @see #setSystemUiVisibility(int) 8385 */ 8386 public void setFitsSystemWindows(boolean fitSystemWindows) { 8387 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 8388 } 8389 8390 /** 8391 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 8392 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 8393 * will be executed. 8394 * 8395 * @return {@code true} if the default implementation of 8396 * {@link #fitSystemWindows(Rect)} will be executed. 8397 * 8398 * @attr ref android.R.styleable#View_fitsSystemWindows 8399 * @see #setFitsSystemWindows(boolean) 8400 * @see #fitSystemWindows(Rect) 8401 * @see #setSystemUiVisibility(int) 8402 */ 8403 @ViewDebug.ExportedProperty 8404 public boolean getFitsSystemWindows() { 8405 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 8406 } 8407 8408 /** @hide */ 8409 public boolean fitsSystemWindows() { 8410 return getFitsSystemWindows(); 8411 } 8412 8413 /** 8414 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 8415 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 8416 */ 8417 @Deprecated 8418 public void requestFitSystemWindows() { 8419 if (mParent != null) { 8420 mParent.requestFitSystemWindows(); 8421 } 8422 } 8423 8424 /** 8425 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 8426 */ 8427 public void requestApplyInsets() { 8428 requestFitSystemWindows(); 8429 } 8430 8431 /** 8432 * For use by PhoneWindow to make its own system window fitting optional. 8433 * @hide 8434 */ 8435 public void makeOptionalFitsSystemWindows() { 8436 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 8437 } 8438 8439 /** 8440 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 8441 * treat them as such. 8442 * @hide 8443 */ 8444 public void getOutsets(Rect outOutsetRect) { 8445 if (mAttachInfo != null) { 8446 outOutsetRect.set(mAttachInfo.mOutsets); 8447 } else { 8448 outOutsetRect.setEmpty(); 8449 } 8450 } 8451 8452 /** 8453 * Returns the visibility status for this view. 8454 * 8455 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8456 * @attr ref android.R.styleable#View_visibility 8457 */ 8458 @ViewDebug.ExportedProperty(mapping = { 8459 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 8460 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 8461 @ViewDebug.IntToString(from = GONE, to = "GONE") 8462 }) 8463 @Visibility 8464 public int getVisibility() { 8465 return mViewFlags & VISIBILITY_MASK; 8466 } 8467 8468 /** 8469 * Set the visibility state of this view. 8470 * 8471 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8472 * @attr ref android.R.styleable#View_visibility 8473 */ 8474 @RemotableViewMethod 8475 public void setVisibility(@Visibility int visibility) { 8476 setFlags(visibility, VISIBILITY_MASK); 8477 } 8478 8479 /** 8480 * Returns the enabled status for this view. The interpretation of the 8481 * enabled state varies by subclass. 8482 * 8483 * @return True if this view is enabled, false otherwise. 8484 */ 8485 @ViewDebug.ExportedProperty 8486 public boolean isEnabled() { 8487 return (mViewFlags & ENABLED_MASK) == ENABLED; 8488 } 8489 8490 /** 8491 * Set the enabled state of this view. The interpretation of the enabled 8492 * state varies by subclass. 8493 * 8494 * @param enabled True if this view is enabled, false otherwise. 8495 */ 8496 @RemotableViewMethod 8497 public void setEnabled(boolean enabled) { 8498 if (enabled == isEnabled()) return; 8499 8500 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 8501 8502 /* 8503 * The View most likely has to change its appearance, so refresh 8504 * the drawable state. 8505 */ 8506 refreshDrawableState(); 8507 8508 // Invalidate too, since the default behavior for views is to be 8509 // be drawn at 50% alpha rather than to change the drawable. 8510 invalidate(true); 8511 8512 if (!enabled) { 8513 cancelPendingInputEvents(); 8514 } 8515 } 8516 8517 /** 8518 * Set whether this view can receive the focus. 8519 * 8520 * Setting this to false will also ensure that this view is not focusable 8521 * in touch mode. 8522 * 8523 * @param focusable If true, this view can receive the focus. 8524 * 8525 * @see #setFocusableInTouchMode(boolean) 8526 * @attr ref android.R.styleable#View_focusable 8527 */ 8528 public void setFocusable(boolean focusable) { 8529 if (!focusable) { 8530 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 8531 } 8532 setFlags(focusable ? FOCUSABLE : NOT_FOCUSABLE, FOCUSABLE_MASK); 8533 } 8534 8535 /** 8536 * Set whether this view can receive focus while in touch mode. 8537 * 8538 * Setting this to true will also ensure that this view is focusable. 8539 * 8540 * @param focusableInTouchMode If true, this view can receive the focus while 8541 * in touch mode. 8542 * 8543 * @see #setFocusable(boolean) 8544 * @attr ref android.R.styleable#View_focusableInTouchMode 8545 */ 8546 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 8547 // Focusable in touch mode should always be set before the focusable flag 8548 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 8549 // which, in touch mode, will not successfully request focus on this view 8550 // because the focusable in touch mode flag is not set 8551 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 8552 if (focusableInTouchMode) { 8553 setFlags(FOCUSABLE, FOCUSABLE_MASK); 8554 } 8555 } 8556 8557 /** 8558 * Set whether this view should have sound effects enabled for events such as 8559 * clicking and touching. 8560 * 8561 * <p>You may wish to disable sound effects for a view if you already play sounds, 8562 * for instance, a dial key that plays dtmf tones. 8563 * 8564 * @param soundEffectsEnabled whether sound effects are enabled for this view. 8565 * @see #isSoundEffectsEnabled() 8566 * @see #playSoundEffect(int) 8567 * @attr ref android.R.styleable#View_soundEffectsEnabled 8568 */ 8569 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 8570 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 8571 } 8572 8573 /** 8574 * @return whether this view should have sound effects enabled for events such as 8575 * clicking and touching. 8576 * 8577 * @see #setSoundEffectsEnabled(boolean) 8578 * @see #playSoundEffect(int) 8579 * @attr ref android.R.styleable#View_soundEffectsEnabled 8580 */ 8581 @ViewDebug.ExportedProperty 8582 public boolean isSoundEffectsEnabled() { 8583 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 8584 } 8585 8586 /** 8587 * Set whether this view should have haptic feedback for events such as 8588 * long presses. 8589 * 8590 * <p>You may wish to disable haptic feedback if your view already controls 8591 * its own haptic feedback. 8592 * 8593 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 8594 * @see #isHapticFeedbackEnabled() 8595 * @see #performHapticFeedback(int) 8596 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8597 */ 8598 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 8599 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 8600 } 8601 8602 /** 8603 * @return whether this view should have haptic feedback enabled for events 8604 * long presses. 8605 * 8606 * @see #setHapticFeedbackEnabled(boolean) 8607 * @see #performHapticFeedback(int) 8608 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8609 */ 8610 @ViewDebug.ExportedProperty 8611 public boolean isHapticFeedbackEnabled() { 8612 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 8613 } 8614 8615 /** 8616 * Returns the layout direction for this view. 8617 * 8618 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 8619 * {@link #LAYOUT_DIRECTION_RTL}, 8620 * {@link #LAYOUT_DIRECTION_INHERIT} or 8621 * {@link #LAYOUT_DIRECTION_LOCALE}. 8622 * 8623 * @attr ref android.R.styleable#View_layoutDirection 8624 * 8625 * @hide 8626 */ 8627 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8628 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 8629 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 8630 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 8631 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 8632 }) 8633 @LayoutDir 8634 public int getRawLayoutDirection() { 8635 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 8636 } 8637 8638 /** 8639 * Set the layout direction for this view. This will propagate a reset of layout direction 8640 * resolution to the view's children and resolve layout direction for this view. 8641 * 8642 * @param layoutDirection the layout direction to set. Should be one of: 8643 * 8644 * {@link #LAYOUT_DIRECTION_LTR}, 8645 * {@link #LAYOUT_DIRECTION_RTL}, 8646 * {@link #LAYOUT_DIRECTION_INHERIT}, 8647 * {@link #LAYOUT_DIRECTION_LOCALE}. 8648 * 8649 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 8650 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 8651 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 8652 * 8653 * @attr ref android.R.styleable#View_layoutDirection 8654 */ 8655 @RemotableViewMethod 8656 public void setLayoutDirection(@LayoutDir int layoutDirection) { 8657 if (getRawLayoutDirection() != layoutDirection) { 8658 // Reset the current layout direction and the resolved one 8659 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 8660 resetRtlProperties(); 8661 // Set the new layout direction (filtered) 8662 mPrivateFlags2 |= 8663 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 8664 // We need to resolve all RTL properties as they all depend on layout direction 8665 resolveRtlPropertiesIfNeeded(); 8666 requestLayout(); 8667 invalidate(true); 8668 } 8669 } 8670 8671 /** 8672 * Returns the resolved layout direction for this view. 8673 * 8674 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 8675 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 8676 * 8677 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 8678 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 8679 * 8680 * @attr ref android.R.styleable#View_layoutDirection 8681 */ 8682 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8683 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 8684 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 8685 }) 8686 @ResolvedLayoutDir 8687 public int getLayoutDirection() { 8688 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 8689 if (targetSdkVersion < JELLY_BEAN_MR1) { 8690 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 8691 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 8692 } 8693 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 8694 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 8695 } 8696 8697 /** 8698 * Indicates whether or not this view's layout is right-to-left. This is resolved from 8699 * layout attribute and/or the inherited value from the parent 8700 * 8701 * @return true if the layout is right-to-left. 8702 * 8703 * @hide 8704 */ 8705 @ViewDebug.ExportedProperty(category = "layout") 8706 public boolean isLayoutRtl() { 8707 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 8708 } 8709 8710 /** 8711 * Indicates whether the view is currently tracking transient state that the 8712 * app should not need to concern itself with saving and restoring, but that 8713 * the framework should take special note to preserve when possible. 8714 * 8715 * <p>A view with transient state cannot be trivially rebound from an external 8716 * data source, such as an adapter binding item views in a list. This may be 8717 * because the view is performing an animation, tracking user selection 8718 * of content, or similar.</p> 8719 * 8720 * @return true if the view has transient state 8721 */ 8722 @ViewDebug.ExportedProperty(category = "layout") 8723 public boolean hasTransientState() { 8724 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 8725 } 8726 8727 /** 8728 * Set whether this view is currently tracking transient state that the 8729 * framework should attempt to preserve when possible. This flag is reference counted, 8730 * so every call to setHasTransientState(true) should be paired with a later call 8731 * to setHasTransientState(false). 8732 * 8733 * <p>A view with transient state cannot be trivially rebound from an external 8734 * data source, such as an adapter binding item views in a list. This may be 8735 * because the view is performing an animation, tracking user selection 8736 * of content, or similar.</p> 8737 * 8738 * @param hasTransientState true if this view has transient state 8739 */ 8740 public void setHasTransientState(boolean hasTransientState) { 8741 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 8742 mTransientStateCount - 1; 8743 if (mTransientStateCount < 0) { 8744 mTransientStateCount = 0; 8745 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 8746 "unmatched pair of setHasTransientState calls"); 8747 } else if ((hasTransientState && mTransientStateCount == 1) || 8748 (!hasTransientState && mTransientStateCount == 0)) { 8749 // update flag if we've just incremented up from 0 or decremented down to 0 8750 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 8751 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 8752 if (mParent != null) { 8753 try { 8754 mParent.childHasTransientStateChanged(this, hasTransientState); 8755 } catch (AbstractMethodError e) { 8756 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 8757 " does not fully implement ViewParent", e); 8758 } 8759 } 8760 } 8761 } 8762 8763 /** 8764 * Returns true if this view is currently attached to a window. 8765 */ 8766 public boolean isAttachedToWindow() { 8767 return mAttachInfo != null; 8768 } 8769 8770 /** 8771 * Returns true if this view has been through at least one layout since it 8772 * was last attached to or detached from a window. 8773 */ 8774 public boolean isLaidOut() { 8775 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 8776 } 8777 8778 /** 8779 * If this view doesn't do any drawing on its own, set this flag to 8780 * allow further optimizations. By default, this flag is not set on 8781 * View, but could be set on some View subclasses such as ViewGroup. 8782 * 8783 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 8784 * you should clear this flag. 8785 * 8786 * @param willNotDraw whether or not this View draw on its own 8787 */ 8788 public void setWillNotDraw(boolean willNotDraw) { 8789 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 8790 } 8791 8792 /** 8793 * Returns whether or not this View draws on its own. 8794 * 8795 * @return true if this view has nothing to draw, false otherwise 8796 */ 8797 @ViewDebug.ExportedProperty(category = "drawing") 8798 public boolean willNotDraw() { 8799 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 8800 } 8801 8802 /** 8803 * When a View's drawing cache is enabled, drawing is redirected to an 8804 * offscreen bitmap. Some views, like an ImageView, must be able to 8805 * bypass this mechanism if they already draw a single bitmap, to avoid 8806 * unnecessary usage of the memory. 8807 * 8808 * @param willNotCacheDrawing true if this view does not cache its 8809 * drawing, false otherwise 8810 */ 8811 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 8812 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 8813 } 8814 8815 /** 8816 * Returns whether or not this View can cache its drawing or not. 8817 * 8818 * @return true if this view does not cache its drawing, false otherwise 8819 */ 8820 @ViewDebug.ExportedProperty(category = "drawing") 8821 public boolean willNotCacheDrawing() { 8822 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 8823 } 8824 8825 /** 8826 * Indicates whether this view reacts to click events or not. 8827 * 8828 * @return true if the view is clickable, false otherwise 8829 * 8830 * @see #setClickable(boolean) 8831 * @attr ref android.R.styleable#View_clickable 8832 */ 8833 @ViewDebug.ExportedProperty 8834 public boolean isClickable() { 8835 return (mViewFlags & CLICKABLE) == CLICKABLE; 8836 } 8837 8838 /** 8839 * Enables or disables click events for this view. When a view 8840 * is clickable it will change its state to "pressed" on every click. 8841 * Subclasses should set the view clickable to visually react to 8842 * user's clicks. 8843 * 8844 * @param clickable true to make the view clickable, false otherwise 8845 * 8846 * @see #isClickable() 8847 * @attr ref android.R.styleable#View_clickable 8848 */ 8849 public void setClickable(boolean clickable) { 8850 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 8851 } 8852 8853 /** 8854 * Indicates whether this view reacts to long click events or not. 8855 * 8856 * @return true if the view is long clickable, false otherwise 8857 * 8858 * @see #setLongClickable(boolean) 8859 * @attr ref android.R.styleable#View_longClickable 8860 */ 8861 public boolean isLongClickable() { 8862 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 8863 } 8864 8865 /** 8866 * Enables or disables long click events for this view. When a view is long 8867 * clickable it reacts to the user holding down the button for a longer 8868 * duration than a tap. This event can either launch the listener or a 8869 * context menu. 8870 * 8871 * @param longClickable true to make the view long clickable, false otherwise 8872 * @see #isLongClickable() 8873 * @attr ref android.R.styleable#View_longClickable 8874 */ 8875 public void setLongClickable(boolean longClickable) { 8876 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 8877 } 8878 8879 /** 8880 * Indicates whether this view reacts to context clicks or not. 8881 * 8882 * @return true if the view is context clickable, false otherwise 8883 * @see #setContextClickable(boolean) 8884 * @attr ref android.R.styleable#View_contextClickable 8885 */ 8886 public boolean isContextClickable() { 8887 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 8888 } 8889 8890 /** 8891 * Enables or disables context clicking for this view. This event can launch the listener. 8892 * 8893 * @param contextClickable true to make the view react to a context click, false otherwise 8894 * @see #isContextClickable() 8895 * @attr ref android.R.styleable#View_contextClickable 8896 */ 8897 public void setContextClickable(boolean contextClickable) { 8898 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 8899 } 8900 8901 /** 8902 * Sets the pressed state for this view and provides a touch coordinate for 8903 * animation hinting. 8904 * 8905 * @param pressed Pass true to set the View's internal state to "pressed", 8906 * or false to reverts the View's internal state from a 8907 * previously set "pressed" state. 8908 * @param x The x coordinate of the touch that caused the press 8909 * @param y The y coordinate of the touch that caused the press 8910 */ 8911 private void setPressed(boolean pressed, float x, float y) { 8912 if (pressed) { 8913 drawableHotspotChanged(x, y); 8914 } 8915 8916 setPressed(pressed); 8917 } 8918 8919 /** 8920 * Sets the pressed state for this view. 8921 * 8922 * @see #isClickable() 8923 * @see #setClickable(boolean) 8924 * 8925 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 8926 * the View's internal state from a previously set "pressed" state. 8927 */ 8928 public void setPressed(boolean pressed) { 8929 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 8930 8931 if (pressed) { 8932 mPrivateFlags |= PFLAG_PRESSED; 8933 } else { 8934 mPrivateFlags &= ~PFLAG_PRESSED; 8935 } 8936 8937 if (needsRefresh) { 8938 refreshDrawableState(); 8939 } 8940 dispatchSetPressed(pressed); 8941 } 8942 8943 /** 8944 * Dispatch setPressed to all of this View's children. 8945 * 8946 * @see #setPressed(boolean) 8947 * 8948 * @param pressed The new pressed state 8949 */ 8950 protected void dispatchSetPressed(boolean pressed) { 8951 } 8952 8953 /** 8954 * Indicates whether the view is currently in pressed state. Unless 8955 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 8956 * the pressed state. 8957 * 8958 * @see #setPressed(boolean) 8959 * @see #isClickable() 8960 * @see #setClickable(boolean) 8961 * 8962 * @return true if the view is currently pressed, false otherwise 8963 */ 8964 @ViewDebug.ExportedProperty 8965 public boolean isPressed() { 8966 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 8967 } 8968 8969 /** 8970 * @hide 8971 * Indicates whether this view will participate in data collection through 8972 * {@link ViewStructure}. If true, it will not provide any data 8973 * for itself or its children. If false, the normal data collection will be allowed. 8974 * 8975 * @return Returns false if assist data collection is not blocked, else true. 8976 * 8977 * @see #setAssistBlocked(boolean) 8978 * @attr ref android.R.styleable#View_assistBlocked 8979 */ 8980 public boolean isAssistBlocked() { 8981 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 8982 } 8983 8984 /** 8985 * @hide 8986 * Indicates whether this view will participate in data collection through 8987 * {@link ViewStructure} for auto-fill purposes. 8988 * 8989 * <p>If {@code true}, it will not provide any data for itself or its children. 8990 * <p>If {@code false}, the normal data collection will be allowed. 8991 * 8992 * @return Returns {@code false} if assist data collection for auto-fill is not blocked, 8993 * else {@code true}. 8994 * 8995 * TODO(b/33197203): update / remove javadoc tags below 8996 * @see #setAssistBlocked(boolean) 8997 * @attr ref android.R.styleable#View_assistBlocked 8998 */ 8999 public boolean isAutoFillBlocked() { 9000 return false; // TODO(b/33197203): properly implement it 9001 } 9002 9003 /** 9004 * @hide 9005 * Controls whether assist data collection from this view and its children is enabled 9006 * (that is, whether {@link #onProvideStructure} and 9007 * {@link #onProvideVirtualStructure} will be called). The default value is false, 9008 * allowing normal assist collection. Setting this to false will disable assist collection. 9009 * 9010 * @param enabled Set to true to <em>disable</em> assist data collection, or false 9011 * (the default) to allow it. 9012 * 9013 * @see #isAssistBlocked() 9014 * @see #onProvideStructure 9015 * @see #onProvideVirtualStructure 9016 * @attr ref android.R.styleable#View_assistBlocked 9017 */ 9018 public void setAssistBlocked(boolean enabled) { 9019 if (enabled) { 9020 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 9021 } else { 9022 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 9023 } 9024 } 9025 9026 /** 9027 * Indicates whether this view will save its state (that is, 9028 * whether its {@link #onSaveInstanceState} method will be called). 9029 * 9030 * @return Returns true if the view state saving is enabled, else false. 9031 * 9032 * @see #setSaveEnabled(boolean) 9033 * @attr ref android.R.styleable#View_saveEnabled 9034 */ 9035 public boolean isSaveEnabled() { 9036 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 9037 } 9038 9039 /** 9040 * Controls whether the saving of this view's state is 9041 * enabled (that is, whether its {@link #onSaveInstanceState} method 9042 * will be called). Note that even if freezing is enabled, the 9043 * view still must have an id assigned to it (via {@link #setId(int)}) 9044 * for its state to be saved. This flag can only disable the 9045 * saving of this view; any child views may still have their state saved. 9046 * 9047 * @param enabled Set to false to <em>disable</em> state saving, or true 9048 * (the default) to allow it. 9049 * 9050 * @see #isSaveEnabled() 9051 * @see #setId(int) 9052 * @see #onSaveInstanceState() 9053 * @attr ref android.R.styleable#View_saveEnabled 9054 */ 9055 public void setSaveEnabled(boolean enabled) { 9056 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 9057 } 9058 9059 /** 9060 * Gets whether the framework should discard touches when the view's 9061 * window is obscured by another visible window. 9062 * Refer to the {@link View} security documentation for more details. 9063 * 9064 * @return True if touch filtering is enabled. 9065 * 9066 * @see #setFilterTouchesWhenObscured(boolean) 9067 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9068 */ 9069 @ViewDebug.ExportedProperty 9070 public boolean getFilterTouchesWhenObscured() { 9071 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 9072 } 9073 9074 /** 9075 * Sets whether the framework should discard touches when the view's 9076 * window is obscured by another visible window. 9077 * Refer to the {@link View} security documentation for more details. 9078 * 9079 * @param enabled True if touch filtering should be enabled. 9080 * 9081 * @see #getFilterTouchesWhenObscured 9082 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9083 */ 9084 public void setFilterTouchesWhenObscured(boolean enabled) { 9085 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 9086 FILTER_TOUCHES_WHEN_OBSCURED); 9087 } 9088 9089 /** 9090 * Indicates whether the entire hierarchy under this view will save its 9091 * state when a state saving traversal occurs from its parent. The default 9092 * is true; if false, these views will not be saved unless 9093 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9094 * 9095 * @return Returns true if the view state saving from parent is enabled, else false. 9096 * 9097 * @see #setSaveFromParentEnabled(boolean) 9098 */ 9099 public boolean isSaveFromParentEnabled() { 9100 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 9101 } 9102 9103 /** 9104 * Controls whether the entire hierarchy under this view will save its 9105 * state when a state saving traversal occurs from its parent. The default 9106 * is true; if false, these views will not be saved unless 9107 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9108 * 9109 * @param enabled Set to false to <em>disable</em> state saving, or true 9110 * (the default) to allow it. 9111 * 9112 * @see #isSaveFromParentEnabled() 9113 * @see #setId(int) 9114 * @see #onSaveInstanceState() 9115 */ 9116 public void setSaveFromParentEnabled(boolean enabled) { 9117 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 9118 } 9119 9120 9121 /** 9122 * Returns whether this View is able to take focus. 9123 * 9124 * @return True if this view can take focus, or false otherwise. 9125 * @attr ref android.R.styleable#View_focusable 9126 */ 9127 @ViewDebug.ExportedProperty(category = "focus") 9128 public final boolean isFocusable() { 9129 return FOCUSABLE == (mViewFlags & FOCUSABLE_MASK); 9130 } 9131 9132 /** 9133 * When a view is focusable, it may not want to take focus when in touch mode. 9134 * For example, a button would like focus when the user is navigating via a D-pad 9135 * so that the user can click on it, but once the user starts touching the screen, 9136 * the button shouldn't take focus 9137 * @return Whether the view is focusable in touch mode. 9138 * @attr ref android.R.styleable#View_focusableInTouchMode 9139 */ 9140 @ViewDebug.ExportedProperty 9141 public final boolean isFocusableInTouchMode() { 9142 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 9143 } 9144 9145 /** 9146 * Find the nearest view in the specified direction that can take focus. 9147 * This does not actually give focus to that view. 9148 * 9149 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9150 * 9151 * @return The nearest focusable in the specified direction, or null if none 9152 * can be found. 9153 */ 9154 public View focusSearch(@FocusRealDirection int direction) { 9155 if (mParent != null) { 9156 return mParent.focusSearch(this, direction); 9157 } else { 9158 return null; 9159 } 9160 } 9161 9162 /** 9163 * Returns whether this View is a root of a keyboard navigation cluster. 9164 * 9165 * @return True if this view is a root of a cluster, or false otherwise. 9166 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9167 */ 9168 @ViewDebug.ExportedProperty(category = "keyboardNavigationCluster") 9169 public final boolean isKeyboardNavigationCluster() { 9170 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 9171 } 9172 9173 /** 9174 * Set whether this view is a root of a keyboard navigation cluster. 9175 * 9176 * @param isCluster If true, this view is a root of a cluster. 9177 * 9178 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9179 */ 9180 public void setKeyboardNavigationCluster(boolean isCluster) { 9181 if (isCluster) { 9182 mPrivateFlags3 |= PFLAG3_CLUSTER; 9183 } else { 9184 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 9185 } 9186 } 9187 9188 /** 9189 * Returns whether this View is a root of a keyboard navigation section. 9190 * 9191 * @return True if this view is a root of a section, or false otherwise. 9192 * @attr ref android.R.styleable#View_keyboardNavigationSection 9193 */ 9194 @ViewDebug.ExportedProperty(category = "keyboardNavigationSection") 9195 public final boolean isKeyboardNavigationSection() { 9196 return (mPrivateFlags3 & PFLAG3_SECTION) != 0; 9197 } 9198 9199 /** 9200 * Set whether this view is a root of a keyboard navigation section. 9201 * 9202 * @param isSection If true, this view is a root of a section. 9203 * 9204 * @attr ref android.R.styleable#View_keyboardNavigationSection 9205 */ 9206 public void setKeyboardNavigationSection(boolean isSection) { 9207 if (isSection) { 9208 mPrivateFlags3 |= PFLAG3_SECTION; 9209 } else { 9210 mPrivateFlags3 &= ~PFLAG3_SECTION; 9211 } 9212 } 9213 9214 final boolean isKeyboardNavigationGroupOfType(@KeyboardNavigationGroupType int groupType) { 9215 switch (groupType) { 9216 case KEYBOARD_NAVIGATION_GROUP_CLUSTER: 9217 return isKeyboardNavigationCluster(); 9218 case KEYBOARD_NAVIGATION_GROUP_SECTION: 9219 return isKeyboardNavigationSection(); 9220 default: 9221 throw new IllegalArgumentException( 9222 "Unknown keyboard navigation group type: " + groupType); 9223 } 9224 } 9225 9226 /** 9227 * Returns whether this View should receive focus when the focus is restored for the view 9228 * hierarchy containing this view. 9229 * <p> 9230 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 9231 * window or serves as a target of cluster or section navigation. 9232 * 9233 * @see #restoreDefaultFocus(int) 9234 * 9235 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 9236 * @attr ref android.R.styleable#View_focusedByDefault 9237 */ 9238 @ViewDebug.ExportedProperty(category = "focusedByDefault") 9239 public final boolean isFocusedByDefault() { 9240 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 9241 } 9242 9243 /** 9244 * Sets whether this View should receive focus when the focus is restored for the view 9245 * hierarchy containing this view. 9246 * <p> 9247 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 9248 * window or serves as a target of cluster or section navigation. 9249 * 9250 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 9251 * {@code false} otherwise. 9252 * 9253 * @see #restoreDefaultFocus(int) 9254 * 9255 * @attr ref android.R.styleable#View_focusedByDefault 9256 */ 9257 public void setFocusedByDefault(boolean isFocusedByDefault) { 9258 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 9259 return; 9260 } 9261 9262 if (isFocusedByDefault) { 9263 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 9264 } else { 9265 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 9266 } 9267 9268 if (mParent instanceof ViewGroup) { 9269 if (isFocusedByDefault) { 9270 ((ViewGroup) mParent).setDefaultFocus(this); 9271 } else { 9272 ((ViewGroup) mParent).cleanDefaultFocus(this); 9273 } 9274 } 9275 } 9276 9277 /** 9278 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 9279 * 9280 * @return {@code true} if this view has default focus, {@code false} otherwise 9281 */ 9282 boolean hasDefaultFocus() { 9283 return isFocusedByDefault(); 9284 } 9285 9286 /** 9287 * Find the nearest keyboard navigation group in the specified direction. The group type can be 9288 * either a cluster or a section. 9289 * This does not actually give focus to that group. 9290 * 9291 * @param groupType Type of the keyboard navigation group 9292 * @param currentGroup The starting point of the search. Null means the current group is not 9293 * found yet 9294 * @param direction Direction to look 9295 * 9296 * @return The nearest keyboard navigation group in the specified direction, or null if none 9297 * can be found 9298 */ 9299 public View keyboardNavigationGroupSearch( 9300 @KeyboardNavigationGroupType int groupType, View currentGroup, int direction) { 9301 if (isKeyboardNavigationGroupOfType(groupType)) { 9302 currentGroup = this; 9303 } 9304 if (isRootNamespace() 9305 || (groupType == KEYBOARD_NAVIGATION_GROUP_SECTION 9306 && isKeyboardNavigationCluster())) { 9307 // Root namespace means we should consider ourselves the top of the 9308 // tree for group searching; otherwise we could be group searching 9309 // into other tabs. see LocalActivityManager and TabHost for more info. 9310 // In addition, a cluster node works as a root for section searches. 9311 return FocusFinder.getInstance().findNextKeyboardNavigationGroup( 9312 groupType, this, currentGroup, direction); 9313 } else if (mParent != null) { 9314 return mParent.keyboardNavigationGroupSearch( 9315 groupType, currentGroup, direction); 9316 } 9317 return null; 9318 } 9319 9320 /** 9321 * This method is the last chance for the focused view and its ancestors to 9322 * respond to an arrow key. This is called when the focused view did not 9323 * consume the key internally, nor could the view system find a new view in 9324 * the requested direction to give focus to. 9325 * 9326 * @param focused The currently focused view. 9327 * @param direction The direction focus wants to move. One of FOCUS_UP, 9328 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 9329 * @return True if the this view consumed this unhandled move. 9330 */ 9331 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 9332 return false; 9333 } 9334 9335 /** 9336 * If a user manually specified the next view id for a particular direction, 9337 * use the root to look up the view. 9338 * @param root The root view of the hierarchy containing this view. 9339 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 9340 * or FOCUS_BACKWARD. 9341 * @return The user specified next view, or null if there is none. 9342 */ 9343 View findUserSetNextFocus(View root, @FocusDirection int direction) { 9344 switch (direction) { 9345 case FOCUS_LEFT: 9346 if (mNextFocusLeftId == View.NO_ID) return null; 9347 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 9348 case FOCUS_RIGHT: 9349 if (mNextFocusRightId == View.NO_ID) return null; 9350 return findViewInsideOutShouldExist(root, mNextFocusRightId); 9351 case FOCUS_UP: 9352 if (mNextFocusUpId == View.NO_ID) return null; 9353 return findViewInsideOutShouldExist(root, mNextFocusUpId); 9354 case FOCUS_DOWN: 9355 if (mNextFocusDownId == View.NO_ID) return null; 9356 return findViewInsideOutShouldExist(root, mNextFocusDownId); 9357 case FOCUS_FORWARD: 9358 if (mNextFocusForwardId == View.NO_ID) return null; 9359 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 9360 case FOCUS_BACKWARD: { 9361 if (mID == View.NO_ID) return null; 9362 final int id = mID; 9363 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 9364 @Override 9365 public boolean apply(View t) { 9366 return t.mNextFocusForwardId == id; 9367 } 9368 }); 9369 } 9370 } 9371 return null; 9372 } 9373 9374 private View findViewInsideOutShouldExist(View root, int id) { 9375 if (mMatchIdPredicate == null) { 9376 mMatchIdPredicate = new MatchIdPredicate(); 9377 } 9378 mMatchIdPredicate.mId = id; 9379 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 9380 if (result == null) { 9381 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 9382 } 9383 return result; 9384 } 9385 9386 /** 9387 * Find and return all focusable views that are descendants of this view, 9388 * possibly including this view if it is focusable itself. 9389 * 9390 * @param direction The direction of the focus 9391 * @return A list of focusable views 9392 */ 9393 public ArrayList<View> getFocusables(@FocusDirection int direction) { 9394 ArrayList<View> result = new ArrayList<View>(24); 9395 addFocusables(result, direction); 9396 return result; 9397 } 9398 9399 /** 9400 * Add any focusable views that are descendants of this view (possibly 9401 * including this view if it is focusable itself) to views. If we are in touch mode, 9402 * only add views that are also focusable in touch mode. 9403 * 9404 * @param views Focusable views found so far 9405 * @param direction The direction of the focus 9406 */ 9407 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 9408 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 9409 } 9410 9411 /** 9412 * Adds any focusable views that are descendants of this view (possibly 9413 * including this view if it is focusable itself) to views. This method 9414 * adds all focusable views regardless if we are in touch mode or 9415 * only views focusable in touch mode if we are in touch mode or 9416 * only views that can take accessibility focus if accessibility is enabled 9417 * depending on the focusable mode parameter. 9418 * 9419 * @param views Focusable views found so far or null if all we are interested is 9420 * the number of focusables. 9421 * @param direction The direction of the focus. 9422 * @param focusableMode The type of focusables to be added. 9423 * 9424 * @see #FOCUSABLES_ALL 9425 * @see #FOCUSABLES_TOUCH_MODE 9426 */ 9427 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 9428 @FocusableMode int focusableMode) { 9429 if (views == null) { 9430 return; 9431 } 9432 if (!isFocusable()) { 9433 return; 9434 } 9435 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 9436 && !isFocusableInTouchMode()) { 9437 return; 9438 } 9439 views.add(this); 9440 } 9441 9442 /** 9443 * Adds any keyboard navigation group roots that are descendants of this view (possibly 9444 * including this view if it is a group root itself) to views. The group type can be either a 9445 * cluster or a section. 9446 * 9447 * @param groupType Type of the keyboard navigation group 9448 * @param views Keyboard navigation group roots found so far 9449 * @param direction Direction to look 9450 */ 9451 public void addKeyboardNavigationGroups( 9452 @KeyboardNavigationGroupType int groupType, 9453 @NonNull Collection<View> views, 9454 int direction) { 9455 if (!(isKeyboardNavigationGroupOfType(groupType))) { 9456 return; 9457 } 9458 views.add(this); 9459 } 9460 9461 /** 9462 * Finds the Views that contain given text. The containment is case insensitive. 9463 * The search is performed by either the text that the View renders or the content 9464 * description that describes the view for accessibility purposes and the view does 9465 * not render or both. Clients can specify how the search is to be performed via 9466 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 9467 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 9468 * 9469 * @param outViews The output list of matching Views. 9470 * @param searched The text to match against. 9471 * 9472 * @see #FIND_VIEWS_WITH_TEXT 9473 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 9474 * @see #setContentDescription(CharSequence) 9475 */ 9476 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 9477 @FindViewFlags int flags) { 9478 if (getAccessibilityNodeProvider() != null) { 9479 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 9480 outViews.add(this); 9481 } 9482 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 9483 && (searched != null && searched.length() > 0) 9484 && (mContentDescription != null && mContentDescription.length() > 0)) { 9485 String searchedLowerCase = searched.toString().toLowerCase(); 9486 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 9487 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 9488 outViews.add(this); 9489 } 9490 } 9491 } 9492 9493 /** 9494 * Find and return all touchable views that are descendants of this view, 9495 * possibly including this view if it is touchable itself. 9496 * 9497 * @return A list of touchable views 9498 */ 9499 public ArrayList<View> getTouchables() { 9500 ArrayList<View> result = new ArrayList<View>(); 9501 addTouchables(result); 9502 return result; 9503 } 9504 9505 /** 9506 * Add any touchable views that are descendants of this view (possibly 9507 * including this view if it is touchable itself) to views. 9508 * 9509 * @param views Touchable views found so far 9510 */ 9511 public void addTouchables(ArrayList<View> views) { 9512 final int viewFlags = mViewFlags; 9513 9514 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 9515 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 9516 && (viewFlags & ENABLED_MASK) == ENABLED) { 9517 views.add(this); 9518 } 9519 } 9520 9521 /** 9522 * Returns whether this View is accessibility focused. 9523 * 9524 * @return True if this View is accessibility focused. 9525 */ 9526 public boolean isAccessibilityFocused() { 9527 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 9528 } 9529 9530 /** 9531 * Call this to try to give accessibility focus to this view. 9532 * 9533 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 9534 * returns false or the view is no visible or the view already has accessibility 9535 * focus. 9536 * 9537 * See also {@link #focusSearch(int)}, which is what you call to say that you 9538 * have focus, and you want your parent to look for the next one. 9539 * 9540 * @return Whether this view actually took accessibility focus. 9541 * 9542 * @hide 9543 */ 9544 public boolean requestAccessibilityFocus() { 9545 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 9546 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 9547 return false; 9548 } 9549 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9550 return false; 9551 } 9552 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 9553 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 9554 ViewRootImpl viewRootImpl = getViewRootImpl(); 9555 if (viewRootImpl != null) { 9556 viewRootImpl.setAccessibilityFocus(this, null); 9557 } 9558 invalidate(); 9559 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 9560 return true; 9561 } 9562 return false; 9563 } 9564 9565 /** 9566 * Call this to try to clear accessibility focus of this view. 9567 * 9568 * See also {@link #focusSearch(int)}, which is what you call to say that you 9569 * have focus, and you want your parent to look for the next one. 9570 * 9571 * @hide 9572 */ 9573 public void clearAccessibilityFocus() { 9574 clearAccessibilityFocusNoCallbacks(0); 9575 9576 // Clear the global reference of accessibility focus if this view or 9577 // any of its descendants had accessibility focus. This will NOT send 9578 // an event or update internal state if focus is cleared from a 9579 // descendant view, which may leave views in inconsistent states. 9580 final ViewRootImpl viewRootImpl = getViewRootImpl(); 9581 if (viewRootImpl != null) { 9582 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 9583 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 9584 viewRootImpl.setAccessibilityFocus(null, null); 9585 } 9586 } 9587 } 9588 9589 private void sendAccessibilityHoverEvent(int eventType) { 9590 // Since we are not delivering to a client accessibility events from not 9591 // important views (unless the clinet request that) we need to fire the 9592 // event from the deepest view exposed to the client. As a consequence if 9593 // the user crosses a not exposed view the client will see enter and exit 9594 // of the exposed predecessor followed by and enter and exit of that same 9595 // predecessor when entering and exiting the not exposed descendant. This 9596 // is fine since the client has a clear idea which view is hovered at the 9597 // price of a couple more events being sent. This is a simple and 9598 // working solution. 9599 View source = this; 9600 while (true) { 9601 if (source.includeForAccessibility()) { 9602 source.sendAccessibilityEvent(eventType); 9603 return; 9604 } 9605 ViewParent parent = source.getParent(); 9606 if (parent instanceof View) { 9607 source = (View) parent; 9608 } else { 9609 return; 9610 } 9611 } 9612 } 9613 9614 /** 9615 * Clears accessibility focus without calling any callback methods 9616 * normally invoked in {@link #clearAccessibilityFocus()}. This method 9617 * is used separately from that one for clearing accessibility focus when 9618 * giving this focus to another view. 9619 * 9620 * @param action The action, if any, that led to focus being cleared. Set to 9621 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 9622 * the window. 9623 */ 9624 void clearAccessibilityFocusNoCallbacks(int action) { 9625 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 9626 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 9627 invalidate(); 9628 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 9629 AccessibilityEvent event = AccessibilityEvent.obtain( 9630 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 9631 event.setAction(action); 9632 if (mAccessibilityDelegate != null) { 9633 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 9634 } else { 9635 sendAccessibilityEventUnchecked(event); 9636 } 9637 } 9638 } 9639 } 9640 9641 /** 9642 * Call this to try to give focus to a specific view or to one of its 9643 * descendants. 9644 * 9645 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9646 * false), or if it is focusable and it is not focusable in touch mode 9647 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9648 * 9649 * See also {@link #focusSearch(int)}, which is what you call to say that you 9650 * have focus, and you want your parent to look for the next one. 9651 * 9652 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 9653 * {@link #FOCUS_DOWN} and <code>null</code>. 9654 * 9655 * @return Whether this view or one of its descendants actually took focus. 9656 */ 9657 public final boolean requestFocus() { 9658 return requestFocus(View.FOCUS_DOWN); 9659 } 9660 9661 /** 9662 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 9663 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 9664 * Nested keyboard navigation clusters are excluded from the hierarchy. 9665 * 9666 * @param direction The direction of the focus 9667 * @return Whether this view or one of its descendants actually took focus 9668 */ 9669 public boolean restoreDefaultFocus(@FocusDirection int direction) { 9670 return requestFocus(direction); 9671 } 9672 9673 /** 9674 * Call this to try to give focus to a specific view or to one of its 9675 * descendants and give it a hint about what direction focus is heading. 9676 * 9677 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9678 * false), or if it is focusable and it is not focusable in touch mode 9679 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9680 * 9681 * See also {@link #focusSearch(int)}, which is what you call to say that you 9682 * have focus, and you want your parent to look for the next one. 9683 * 9684 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 9685 * <code>null</code> set for the previously focused rectangle. 9686 * 9687 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9688 * @return Whether this view or one of its descendants actually took focus. 9689 */ 9690 public final boolean requestFocus(int direction) { 9691 return requestFocus(direction, null); 9692 } 9693 9694 /** 9695 * Call this to try to give focus to a specific view or to one of its descendants 9696 * and give it hints about the direction and a specific rectangle that the focus 9697 * is coming from. The rectangle can help give larger views a finer grained hint 9698 * about where focus is coming from, and therefore, where to show selection, or 9699 * forward focus change internally. 9700 * 9701 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9702 * false), or if it is focusable and it is not focusable in touch mode 9703 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9704 * 9705 * A View will not take focus if it is not visible. 9706 * 9707 * A View will not take focus if one of its parents has 9708 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 9709 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 9710 * 9711 * See also {@link #focusSearch(int)}, which is what you call to say that you 9712 * have focus, and you want your parent to look for the next one. 9713 * 9714 * You may wish to override this method if your custom {@link View} has an internal 9715 * {@link View} that it wishes to forward the request to. 9716 * 9717 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9718 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 9719 * to give a finer grained hint about where focus is coming from. May be null 9720 * if there is no hint. 9721 * @return Whether this view or one of its descendants actually took focus. 9722 */ 9723 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 9724 return requestFocusNoSearch(direction, previouslyFocusedRect); 9725 } 9726 9727 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 9728 // need to be focusable 9729 if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE || 9730 (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9731 return false; 9732 } 9733 9734 // need to be focusable in touch mode if in touch mode 9735 if (isInTouchMode() && 9736 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 9737 return false; 9738 } 9739 9740 // need to not have any parents blocking us 9741 if (hasAncestorThatBlocksDescendantFocus()) { 9742 return false; 9743 } 9744 9745 handleFocusGainInternal(direction, previouslyFocusedRect); 9746 return true; 9747 } 9748 9749 /** 9750 * Call this to try to give focus to a specific view or to one of its descendants. This is a 9751 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 9752 * touch mode to request focus when they are touched. 9753 * 9754 * @return Whether this view or one of its descendants actually took focus. 9755 * 9756 * @see #isInTouchMode() 9757 * 9758 */ 9759 public final boolean requestFocusFromTouch() { 9760 // Leave touch mode if we need to 9761 if (isInTouchMode()) { 9762 ViewRootImpl viewRoot = getViewRootImpl(); 9763 if (viewRoot != null) { 9764 viewRoot.ensureTouchMode(false); 9765 } 9766 } 9767 return requestFocus(View.FOCUS_DOWN); 9768 } 9769 9770 /** 9771 * @return Whether any ancestor of this view blocks descendant focus. 9772 */ 9773 private boolean hasAncestorThatBlocksDescendantFocus() { 9774 final boolean focusableInTouchMode = isFocusableInTouchMode(); 9775 ViewParent ancestor = mParent; 9776 while (ancestor instanceof ViewGroup) { 9777 final ViewGroup vgAncestor = (ViewGroup) ancestor; 9778 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 9779 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 9780 return true; 9781 } else { 9782 ancestor = vgAncestor.getParent(); 9783 } 9784 } 9785 return false; 9786 } 9787 9788 /** 9789 * Gets the mode for determining whether this View is important for accessibility. 9790 * A view is important for accessibility if it fires accessibility events and if it 9791 * is reported to accessibility services that query the screen. 9792 * 9793 * @return The mode for determining whether a view is important for accessibility, one 9794 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 9795 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 9796 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 9797 * 9798 * @attr ref android.R.styleable#View_importantForAccessibility 9799 * 9800 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9801 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9802 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9803 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9804 */ 9805 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 9806 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 9807 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 9808 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 9809 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 9810 to = "noHideDescendants") 9811 }) 9812 public int getImportantForAccessibility() { 9813 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9814 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9815 } 9816 9817 /** 9818 * Sets the live region mode for this view. This indicates to accessibility 9819 * services whether they should automatically notify the user about changes 9820 * to the view's content description or text, or to the content descriptions 9821 * or text of the view's children (where applicable). 9822 * <p> 9823 * For example, in a login screen with a TextView that displays an "incorrect 9824 * password" notification, that view should be marked as a live region with 9825 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9826 * <p> 9827 * To disable change notifications for this view, use 9828 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 9829 * mode for most views. 9830 * <p> 9831 * To indicate that the user should be notified of changes, use 9832 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9833 * <p> 9834 * If the view's changes should interrupt ongoing speech and notify the user 9835 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 9836 * 9837 * @param mode The live region mode for this view, one of: 9838 * <ul> 9839 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 9840 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 9841 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 9842 * </ul> 9843 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9844 */ 9845 public void setAccessibilityLiveRegion(int mode) { 9846 if (mode != getAccessibilityLiveRegion()) { 9847 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9848 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 9849 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9850 notifyViewAccessibilityStateChangedIfNeeded( 9851 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9852 } 9853 } 9854 9855 /** 9856 * Gets the live region mode for this View. 9857 * 9858 * @return The live region mode for the view. 9859 * 9860 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9861 * 9862 * @see #setAccessibilityLiveRegion(int) 9863 */ 9864 public int getAccessibilityLiveRegion() { 9865 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 9866 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 9867 } 9868 9869 /** 9870 * Sets how to determine whether this view is important for accessibility 9871 * which is if it fires accessibility events and if it is reported to 9872 * accessibility services that query the screen. 9873 * 9874 * @param mode How to determine whether this view is important for accessibility. 9875 * 9876 * @attr ref android.R.styleable#View_importantForAccessibility 9877 * 9878 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9879 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9880 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9881 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9882 */ 9883 public void setImportantForAccessibility(int mode) { 9884 final int oldMode = getImportantForAccessibility(); 9885 if (mode != oldMode) { 9886 final boolean hideDescendants = 9887 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 9888 9889 // If this node or its descendants are no longer important, try to 9890 // clear accessibility focus. 9891 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 9892 final View focusHost = findAccessibilityFocusHost(hideDescendants); 9893 if (focusHost != null) { 9894 focusHost.clearAccessibilityFocus(); 9895 } 9896 } 9897 9898 // If we're moving between AUTO and another state, we might not need 9899 // to send a subtree changed notification. We'll store the computed 9900 // importance, since we'll need to check it later to make sure. 9901 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 9902 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 9903 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 9904 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9905 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 9906 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9907 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 9908 notifySubtreeAccessibilityStateChangedIfNeeded(); 9909 } else { 9910 notifyViewAccessibilityStateChangedIfNeeded( 9911 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9912 } 9913 } 9914 } 9915 9916 /** 9917 * Returns the view within this view's hierarchy that is hosting 9918 * accessibility focus. 9919 * 9920 * @param searchDescendants whether to search for focus in descendant views 9921 * @return the view hosting accessibility focus, or {@code null} 9922 */ 9923 private View findAccessibilityFocusHost(boolean searchDescendants) { 9924 if (isAccessibilityFocusedViewOrHost()) { 9925 return this; 9926 } 9927 9928 if (searchDescendants) { 9929 final ViewRootImpl viewRoot = getViewRootImpl(); 9930 if (viewRoot != null) { 9931 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 9932 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 9933 return focusHost; 9934 } 9935 } 9936 } 9937 9938 return null; 9939 } 9940 9941 /** 9942 * Computes whether this view should be exposed for accessibility. In 9943 * general, views that are interactive or provide information are exposed 9944 * while views that serve only as containers are hidden. 9945 * <p> 9946 * If an ancestor of this view has importance 9947 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 9948 * returns <code>false</code>. 9949 * <p> 9950 * Otherwise, the value is computed according to the view's 9951 * {@link #getImportantForAccessibility()} value: 9952 * <ol> 9953 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 9954 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 9955 * </code> 9956 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 9957 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 9958 * view satisfies any of the following: 9959 * <ul> 9960 * <li>Is actionable, e.g. {@link #isClickable()}, 9961 * {@link #isLongClickable()}, or {@link #isFocusable()} 9962 * <li>Has an {@link AccessibilityDelegate} 9963 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 9964 * {@link OnKeyListener}, etc. 9965 * <li>Is an accessibility live region, e.g. 9966 * {@link #getAccessibilityLiveRegion()} is not 9967 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 9968 * </ul> 9969 * </ol> 9970 * 9971 * @return Whether the view is exposed for accessibility. 9972 * @see #setImportantForAccessibility(int) 9973 * @see #getImportantForAccessibility() 9974 */ 9975 public boolean isImportantForAccessibility() { 9976 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9977 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9978 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 9979 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 9980 return false; 9981 } 9982 9983 // Check parent mode to ensure we're not hidden. 9984 ViewParent parent = mParent; 9985 while (parent instanceof View) { 9986 if (((View) parent).getImportantForAccessibility() 9987 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 9988 return false; 9989 } 9990 parent = parent.getParent(); 9991 } 9992 9993 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 9994 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 9995 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 9996 } 9997 9998 /** 9999 * Gets the parent for accessibility purposes. Note that the parent for 10000 * accessibility is not necessary the immediate parent. It is the first 10001 * predecessor that is important for accessibility. 10002 * 10003 * @return The parent for accessibility purposes. 10004 */ 10005 public ViewParent getParentForAccessibility() { 10006 if (mParent instanceof View) { 10007 View parentView = (View) mParent; 10008 if (parentView.includeForAccessibility()) { 10009 return mParent; 10010 } else { 10011 return mParent.getParentForAccessibility(); 10012 } 10013 } 10014 return null; 10015 } 10016 10017 /** 10018 * Adds the children of this View relevant for accessibility to the given list 10019 * as output. Since some Views are not important for accessibility the added 10020 * child views are not necessarily direct children of this view, rather they are 10021 * the first level of descendants important for accessibility. 10022 * 10023 * @param outChildren The output list that will receive children for accessibility. 10024 */ 10025 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 10026 10027 } 10028 10029 /** 10030 * Whether to regard this view for accessibility. A view is regarded for 10031 * accessibility if it is important for accessibility or the querying 10032 * accessibility service has explicitly requested that view not 10033 * important for accessibility are regarded. 10034 * 10035 * @return Whether to regard the view for accessibility. 10036 * 10037 * @hide 10038 */ 10039 public boolean includeForAccessibility() { 10040 if (mAttachInfo != null) { 10041 return (mAttachInfo.mAccessibilityFetchFlags 10042 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 10043 || isImportantForAccessibility(); 10044 } 10045 return false; 10046 } 10047 10048 /** 10049 * Returns whether the View is considered actionable from 10050 * accessibility perspective. Such view are important for 10051 * accessibility. 10052 * 10053 * @return True if the view is actionable for accessibility. 10054 * 10055 * @hide 10056 */ 10057 public boolean isActionableForAccessibility() { 10058 return (isClickable() || isLongClickable() || isFocusable()); 10059 } 10060 10061 /** 10062 * Returns whether the View has registered callbacks which makes it 10063 * important for accessibility. 10064 * 10065 * @return True if the view is actionable for accessibility. 10066 */ 10067 private boolean hasListenersForAccessibility() { 10068 ListenerInfo info = getListenerInfo(); 10069 return mTouchDelegate != null || info.mOnKeyListener != null 10070 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 10071 || info.mOnHoverListener != null || info.mOnDragListener != null; 10072 } 10073 10074 /** 10075 * Notifies that the accessibility state of this view changed. The change 10076 * is local to this view and does not represent structural changes such 10077 * as children and parent. For example, the view became focusable. The 10078 * notification is at at most once every 10079 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 10080 * to avoid unnecessary load to the system. Also once a view has a pending 10081 * notification this method is a NOP until the notification has been sent. 10082 * 10083 * @hide 10084 */ 10085 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 10086 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 10087 return; 10088 } 10089 if (mSendViewStateChangedAccessibilityEvent == null) { 10090 mSendViewStateChangedAccessibilityEvent = 10091 new SendViewStateChangedAccessibilityEvent(); 10092 } 10093 mSendViewStateChangedAccessibilityEvent.runOrPost(changeType); 10094 } 10095 10096 /** 10097 * Notifies that the accessibility state of this view changed. The change 10098 * is *not* local to this view and does represent structural changes such 10099 * as children and parent. For example, the view size changed. The 10100 * notification is at at most once every 10101 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 10102 * to avoid unnecessary load to the system. Also once a view has a pending 10103 * notification this method is a NOP until the notification has been sent. 10104 * 10105 * @hide 10106 */ 10107 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 10108 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 10109 return; 10110 } 10111 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 10112 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 10113 if (mParent != null) { 10114 try { 10115 mParent.notifySubtreeAccessibilityStateChanged( 10116 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 10117 } catch (AbstractMethodError e) { 10118 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 10119 " does not fully implement ViewParent", e); 10120 } 10121 } 10122 } 10123 } 10124 10125 /** 10126 * Change the visibility of the View without triggering any other changes. This is 10127 * important for transitions, where visibility changes should not adjust focus or 10128 * trigger a new layout. This is only used when the visibility has already been changed 10129 * and we need a transient value during an animation. When the animation completes, 10130 * the original visibility value is always restored. 10131 * 10132 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 10133 * @hide 10134 */ 10135 public void setTransitionVisibility(@Visibility int visibility) { 10136 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 10137 } 10138 10139 /** 10140 * Reset the flag indicating the accessibility state of the subtree rooted 10141 * at this view changed. 10142 */ 10143 void resetSubtreeAccessibilityStateChanged() { 10144 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 10145 } 10146 10147 /** 10148 * Report an accessibility action to this view's parents for delegated processing. 10149 * 10150 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 10151 * call this method to delegate an accessibility action to a supporting parent. If the parent 10152 * returns true from its 10153 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 10154 * method this method will return true to signify that the action was consumed.</p> 10155 * 10156 * <p>This method is useful for implementing nested scrolling child views. If 10157 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 10158 * a custom view implementation may invoke this method to allow a parent to consume the 10159 * scroll first. If this method returns true the custom view should skip its own scrolling 10160 * behavior.</p> 10161 * 10162 * @param action Accessibility action to delegate 10163 * @param arguments Optional action arguments 10164 * @return true if the action was consumed by a parent 10165 */ 10166 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 10167 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 10168 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 10169 return true; 10170 } 10171 } 10172 return false; 10173 } 10174 10175 /** 10176 * Performs the specified accessibility action on the view. For 10177 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 10178 * <p> 10179 * If an {@link AccessibilityDelegate} has been specified via calling 10180 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10181 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 10182 * is responsible for handling this call. 10183 * </p> 10184 * 10185 * <p>The default implementation will delegate 10186 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 10187 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 10188 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 10189 * 10190 * @param action The action to perform. 10191 * @param arguments Optional action arguments. 10192 * @return Whether the action was performed. 10193 */ 10194 public boolean performAccessibilityAction(int action, Bundle arguments) { 10195 if (mAccessibilityDelegate != null) { 10196 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 10197 } else { 10198 return performAccessibilityActionInternal(action, arguments); 10199 } 10200 } 10201 10202 /** 10203 * @see #performAccessibilityAction(int, Bundle) 10204 * 10205 * Note: Called from the default {@link AccessibilityDelegate}. 10206 * 10207 * @hide 10208 */ 10209 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 10210 if (isNestedScrollingEnabled() 10211 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 10212 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 10213 || action == R.id.accessibilityActionScrollUp 10214 || action == R.id.accessibilityActionScrollLeft 10215 || action == R.id.accessibilityActionScrollDown 10216 || action == R.id.accessibilityActionScrollRight)) { 10217 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 10218 return true; 10219 } 10220 } 10221 10222 switch (action) { 10223 case AccessibilityNodeInfo.ACTION_CLICK: { 10224 if (isClickable()) { 10225 performClick(); 10226 return true; 10227 } 10228 } break; 10229 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 10230 if (isLongClickable()) { 10231 performLongClick(); 10232 return true; 10233 } 10234 } break; 10235 case AccessibilityNodeInfo.ACTION_FOCUS: { 10236 if (!hasFocus()) { 10237 // Get out of touch mode since accessibility 10238 // wants to move focus around. 10239 getViewRootImpl().ensureTouchMode(false); 10240 return requestFocus(); 10241 } 10242 } break; 10243 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 10244 if (hasFocus()) { 10245 clearFocus(); 10246 return !isFocused(); 10247 } 10248 } break; 10249 case AccessibilityNodeInfo.ACTION_SELECT: { 10250 if (!isSelected()) { 10251 setSelected(true); 10252 return isSelected(); 10253 } 10254 } break; 10255 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 10256 if (isSelected()) { 10257 setSelected(false); 10258 return !isSelected(); 10259 } 10260 } break; 10261 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 10262 if (!isAccessibilityFocused()) { 10263 return requestAccessibilityFocus(); 10264 } 10265 } break; 10266 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 10267 if (isAccessibilityFocused()) { 10268 clearAccessibilityFocus(); 10269 return true; 10270 } 10271 } break; 10272 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 10273 if (arguments != null) { 10274 final int granularity = arguments.getInt( 10275 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10276 final boolean extendSelection = arguments.getBoolean( 10277 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10278 return traverseAtGranularity(granularity, true, extendSelection); 10279 } 10280 } break; 10281 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 10282 if (arguments != null) { 10283 final int granularity = arguments.getInt( 10284 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10285 final boolean extendSelection = arguments.getBoolean( 10286 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10287 return traverseAtGranularity(granularity, false, extendSelection); 10288 } 10289 } break; 10290 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 10291 CharSequence text = getIterableTextForAccessibility(); 10292 if (text == null) { 10293 return false; 10294 } 10295 final int start = (arguments != null) ? arguments.getInt( 10296 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 10297 final int end = (arguments != null) ? arguments.getInt( 10298 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 10299 // Only cursor position can be specified (selection length == 0) 10300 if ((getAccessibilitySelectionStart() != start 10301 || getAccessibilitySelectionEnd() != end) 10302 && (start == end)) { 10303 setAccessibilitySelection(start, end); 10304 notifyViewAccessibilityStateChangedIfNeeded( 10305 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10306 return true; 10307 } 10308 } break; 10309 case R.id.accessibilityActionShowOnScreen: { 10310 if (mAttachInfo != null) { 10311 final Rect r = mAttachInfo.mTmpInvalRect; 10312 getDrawingRect(r); 10313 return requestRectangleOnScreen(r, true); 10314 } 10315 } break; 10316 case R.id.accessibilityActionContextClick: { 10317 if (isContextClickable()) { 10318 performContextClick(); 10319 return true; 10320 } 10321 } break; 10322 } 10323 return false; 10324 } 10325 10326 private boolean traverseAtGranularity(int granularity, boolean forward, 10327 boolean extendSelection) { 10328 CharSequence text = getIterableTextForAccessibility(); 10329 if (text == null || text.length() == 0) { 10330 return false; 10331 } 10332 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 10333 if (iterator == null) { 10334 return false; 10335 } 10336 int current = getAccessibilitySelectionEnd(); 10337 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10338 current = forward ? 0 : text.length(); 10339 } 10340 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 10341 if (range == null) { 10342 return false; 10343 } 10344 final int segmentStart = range[0]; 10345 final int segmentEnd = range[1]; 10346 int selectionStart; 10347 int selectionEnd; 10348 if (extendSelection && isAccessibilitySelectionExtendable()) { 10349 selectionStart = getAccessibilitySelectionStart(); 10350 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10351 selectionStart = forward ? segmentStart : segmentEnd; 10352 } 10353 selectionEnd = forward ? segmentEnd : segmentStart; 10354 } else { 10355 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 10356 } 10357 setAccessibilitySelection(selectionStart, selectionEnd); 10358 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 10359 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 10360 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 10361 return true; 10362 } 10363 10364 /** 10365 * Gets the text reported for accessibility purposes. 10366 * 10367 * @return The accessibility text. 10368 * 10369 * @hide 10370 */ 10371 public CharSequence getIterableTextForAccessibility() { 10372 return getContentDescription(); 10373 } 10374 10375 /** 10376 * Gets whether accessibility selection can be extended. 10377 * 10378 * @return If selection is extensible. 10379 * 10380 * @hide 10381 */ 10382 public boolean isAccessibilitySelectionExtendable() { 10383 return false; 10384 } 10385 10386 /** 10387 * @hide 10388 */ 10389 public int getAccessibilitySelectionStart() { 10390 return mAccessibilityCursorPosition; 10391 } 10392 10393 /** 10394 * @hide 10395 */ 10396 public int getAccessibilitySelectionEnd() { 10397 return getAccessibilitySelectionStart(); 10398 } 10399 10400 /** 10401 * @hide 10402 */ 10403 public void setAccessibilitySelection(int start, int end) { 10404 if (start == end && end == mAccessibilityCursorPosition) { 10405 return; 10406 } 10407 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 10408 mAccessibilityCursorPosition = start; 10409 } else { 10410 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 10411 } 10412 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 10413 } 10414 10415 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 10416 int fromIndex, int toIndex) { 10417 if (mParent == null) { 10418 return; 10419 } 10420 AccessibilityEvent event = AccessibilityEvent.obtain( 10421 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 10422 onInitializeAccessibilityEvent(event); 10423 onPopulateAccessibilityEvent(event); 10424 event.setFromIndex(fromIndex); 10425 event.setToIndex(toIndex); 10426 event.setAction(action); 10427 event.setMovementGranularity(granularity); 10428 mParent.requestSendAccessibilityEvent(this, event); 10429 } 10430 10431 /** 10432 * @hide 10433 */ 10434 public TextSegmentIterator getIteratorForGranularity(int granularity) { 10435 switch (granularity) { 10436 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 10437 CharSequence text = getIterableTextForAccessibility(); 10438 if (text != null && text.length() > 0) { 10439 CharacterTextSegmentIterator iterator = 10440 CharacterTextSegmentIterator.getInstance( 10441 mContext.getResources().getConfiguration().locale); 10442 iterator.initialize(text.toString()); 10443 return iterator; 10444 } 10445 } break; 10446 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 10447 CharSequence text = getIterableTextForAccessibility(); 10448 if (text != null && text.length() > 0) { 10449 WordTextSegmentIterator iterator = 10450 WordTextSegmentIterator.getInstance( 10451 mContext.getResources().getConfiguration().locale); 10452 iterator.initialize(text.toString()); 10453 return iterator; 10454 } 10455 } break; 10456 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 10457 CharSequence text = getIterableTextForAccessibility(); 10458 if (text != null && text.length() > 0) { 10459 ParagraphTextSegmentIterator iterator = 10460 ParagraphTextSegmentIterator.getInstance(); 10461 iterator.initialize(text.toString()); 10462 return iterator; 10463 } 10464 } break; 10465 } 10466 return null; 10467 } 10468 10469 /** 10470 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 10471 * and {@link #onFinishTemporaryDetach()}. 10472 * 10473 * <p>This method always returns {@code true} when called directly or indirectly from 10474 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 10475 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 10476 * <ul> 10477 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 10478 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 10479 * </ul> 10480 * </p> 10481 * 10482 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 10483 * and {@link #onFinishTemporaryDetach()}. 10484 */ 10485 public final boolean isTemporarilyDetached() { 10486 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 10487 } 10488 10489 /** 10490 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 10491 * a container View. 10492 */ 10493 @CallSuper 10494 public void dispatchStartTemporaryDetach() { 10495 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 10496 onStartTemporaryDetach(); 10497 } 10498 10499 /** 10500 * This is called when a container is going to temporarily detach a child, with 10501 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 10502 * It will either be followed by {@link #onFinishTemporaryDetach()} or 10503 * {@link #onDetachedFromWindow()} when the container is done. 10504 */ 10505 public void onStartTemporaryDetach() { 10506 removeUnsetPressCallback(); 10507 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 10508 } 10509 10510 /** 10511 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 10512 * a container View. 10513 */ 10514 @CallSuper 10515 public void dispatchFinishTemporaryDetach() { 10516 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 10517 onFinishTemporaryDetach(); 10518 if (hasWindowFocus() && hasFocus()) { 10519 InputMethodManager.getInstance().focusIn(this); 10520 } 10521 } 10522 10523 /** 10524 * Called after {@link #onStartTemporaryDetach} when the container is done 10525 * changing the view. 10526 */ 10527 public void onFinishTemporaryDetach() { 10528 } 10529 10530 /** 10531 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 10532 * for this view's window. Returns null if the view is not currently attached 10533 * to the window. Normally you will not need to use this directly, but 10534 * just use the standard high-level event callbacks like 10535 * {@link #onKeyDown(int, KeyEvent)}. 10536 */ 10537 public KeyEvent.DispatcherState getKeyDispatcherState() { 10538 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 10539 } 10540 10541 /** 10542 * Dispatch a key event before it is processed by any input method 10543 * associated with the view hierarchy. This can be used to intercept 10544 * key events in special situations before the IME consumes them; a 10545 * typical example would be handling the BACK key to update the application's 10546 * UI instead of allowing the IME to see it and close itself. 10547 * 10548 * @param event The key event to be dispatched. 10549 * @return True if the event was handled, false otherwise. 10550 */ 10551 public boolean dispatchKeyEventPreIme(KeyEvent event) { 10552 return onKeyPreIme(event.getKeyCode(), event); 10553 } 10554 10555 /** 10556 * Dispatch a key event to the next view on the focus path. This path runs 10557 * from the top of the view tree down to the currently focused view. If this 10558 * view has focus, it will dispatch to itself. Otherwise it will dispatch 10559 * the next node down the focus path. This method also fires any key 10560 * listeners. 10561 * 10562 * @param event The key event to be dispatched. 10563 * @return True if the event was handled, false otherwise. 10564 */ 10565 public boolean dispatchKeyEvent(KeyEvent event) { 10566 if (mInputEventConsistencyVerifier != null) { 10567 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 10568 } 10569 10570 // Give any attached key listener a first crack at the event. 10571 //noinspection SimplifiableIfStatement 10572 ListenerInfo li = mListenerInfo; 10573 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 10574 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 10575 return true; 10576 } 10577 10578 if (event.dispatch(this, mAttachInfo != null 10579 ? mAttachInfo.mKeyDispatchState : null, this)) { 10580 return true; 10581 } 10582 10583 if (mInputEventConsistencyVerifier != null) { 10584 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10585 } 10586 return false; 10587 } 10588 10589 /** 10590 * Dispatches a key shortcut event. 10591 * 10592 * @param event The key event to be dispatched. 10593 * @return True if the event was handled by the view, false otherwise. 10594 */ 10595 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 10596 return onKeyShortcut(event.getKeyCode(), event); 10597 } 10598 10599 /** 10600 * Pass the touch screen motion event down to the target view, or this 10601 * view if it is the target. 10602 * 10603 * @param event The motion event to be dispatched. 10604 * @return True if the event was handled by the view, false otherwise. 10605 */ 10606 public boolean dispatchTouchEvent(MotionEvent event) { 10607 // If the event should be handled by accessibility focus first. 10608 if (event.isTargetAccessibilityFocus()) { 10609 // We don't have focus or no virtual descendant has it, do not handle the event. 10610 if (!isAccessibilityFocusedViewOrHost()) { 10611 return false; 10612 } 10613 // We have focus and got the event, then use normal event dispatch. 10614 event.setTargetAccessibilityFocus(false); 10615 } 10616 10617 boolean result = false; 10618 10619 if (mInputEventConsistencyVerifier != null) { 10620 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 10621 } 10622 10623 final int actionMasked = event.getActionMasked(); 10624 if (actionMasked == MotionEvent.ACTION_DOWN) { 10625 // Defensive cleanup for new gesture 10626 stopNestedScroll(); 10627 } 10628 10629 if (onFilterTouchEventForSecurity(event)) { 10630 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 10631 result = true; 10632 } 10633 //noinspection SimplifiableIfStatement 10634 ListenerInfo li = mListenerInfo; 10635 if (li != null && li.mOnTouchListener != null 10636 && (mViewFlags & ENABLED_MASK) == ENABLED 10637 && li.mOnTouchListener.onTouch(this, event)) { 10638 result = true; 10639 } 10640 10641 if (!result && onTouchEvent(event)) { 10642 result = true; 10643 } 10644 } 10645 10646 if (!result && mInputEventConsistencyVerifier != null) { 10647 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10648 } 10649 10650 // Clean up after nested scrolls if this is the end of a gesture; 10651 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 10652 // of the gesture. 10653 if (actionMasked == MotionEvent.ACTION_UP || 10654 actionMasked == MotionEvent.ACTION_CANCEL || 10655 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 10656 stopNestedScroll(); 10657 } 10658 10659 return result; 10660 } 10661 10662 boolean isAccessibilityFocusedViewOrHost() { 10663 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 10664 .getAccessibilityFocusedHost() == this); 10665 } 10666 10667 /** 10668 * Filter the touch event to apply security policies. 10669 * 10670 * @param event The motion event to be filtered. 10671 * @return True if the event should be dispatched, false if the event should be dropped. 10672 * 10673 * @see #getFilterTouchesWhenObscured 10674 */ 10675 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 10676 //noinspection RedundantIfStatement 10677 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 10678 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 10679 // Window is obscured, drop this touch. 10680 return false; 10681 } 10682 return true; 10683 } 10684 10685 /** 10686 * Pass a trackball motion event down to the focused view. 10687 * 10688 * @param event The motion event to be dispatched. 10689 * @return True if the event was handled by the view, false otherwise. 10690 */ 10691 public boolean dispatchTrackballEvent(MotionEvent event) { 10692 if (mInputEventConsistencyVerifier != null) { 10693 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 10694 } 10695 10696 return onTrackballEvent(event); 10697 } 10698 10699 /** 10700 * Dispatch a generic motion event. 10701 * <p> 10702 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 10703 * are delivered to the view under the pointer. All other generic motion events are 10704 * delivered to the focused view. Hover events are handled specially and are delivered 10705 * to {@link #onHoverEvent(MotionEvent)}. 10706 * </p> 10707 * 10708 * @param event The motion event to be dispatched. 10709 * @return True if the event was handled by the view, false otherwise. 10710 */ 10711 public boolean dispatchGenericMotionEvent(MotionEvent event) { 10712 if (mInputEventConsistencyVerifier != null) { 10713 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 10714 } 10715 10716 final int source = event.getSource(); 10717 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 10718 final int action = event.getAction(); 10719 if (action == MotionEvent.ACTION_HOVER_ENTER 10720 || action == MotionEvent.ACTION_HOVER_MOVE 10721 || action == MotionEvent.ACTION_HOVER_EXIT) { 10722 if (dispatchHoverEvent(event)) { 10723 return true; 10724 } 10725 } else if (dispatchGenericPointerEvent(event)) { 10726 return true; 10727 } 10728 } else if (dispatchGenericFocusedEvent(event)) { 10729 return true; 10730 } 10731 10732 if (dispatchGenericMotionEventInternal(event)) { 10733 return true; 10734 } 10735 10736 if (mInputEventConsistencyVerifier != null) { 10737 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10738 } 10739 return false; 10740 } 10741 10742 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 10743 //noinspection SimplifiableIfStatement 10744 ListenerInfo li = mListenerInfo; 10745 if (li != null && li.mOnGenericMotionListener != null 10746 && (mViewFlags & ENABLED_MASK) == ENABLED 10747 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 10748 return true; 10749 } 10750 10751 if (onGenericMotionEvent(event)) { 10752 return true; 10753 } 10754 10755 final int actionButton = event.getActionButton(); 10756 switch (event.getActionMasked()) { 10757 case MotionEvent.ACTION_BUTTON_PRESS: 10758 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 10759 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10760 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10761 if (performContextClick(event.getX(), event.getY())) { 10762 mInContextButtonPress = true; 10763 setPressed(true, event.getX(), event.getY()); 10764 removeTapCallback(); 10765 removeLongPressCallback(); 10766 return true; 10767 } 10768 } 10769 break; 10770 10771 case MotionEvent.ACTION_BUTTON_RELEASE: 10772 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10773 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10774 mInContextButtonPress = false; 10775 mIgnoreNextUpEvent = true; 10776 } 10777 break; 10778 } 10779 10780 if (mInputEventConsistencyVerifier != null) { 10781 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10782 } 10783 return false; 10784 } 10785 10786 /** 10787 * Dispatch a hover event. 10788 * <p> 10789 * Do not call this method directly. 10790 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10791 * </p> 10792 * 10793 * @param event The motion event to be dispatched. 10794 * @return True if the event was handled by the view, false otherwise. 10795 */ 10796 protected boolean dispatchHoverEvent(MotionEvent event) { 10797 ListenerInfo li = mListenerInfo; 10798 //noinspection SimplifiableIfStatement 10799 if (li != null && li.mOnHoverListener != null 10800 && (mViewFlags & ENABLED_MASK) == ENABLED 10801 && li.mOnHoverListener.onHover(this, event)) { 10802 return true; 10803 } 10804 10805 return onHoverEvent(event); 10806 } 10807 10808 /** 10809 * Returns true if the view has a child to which it has recently sent 10810 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 10811 * it does not have a hovered child, then it must be the innermost hovered view. 10812 * @hide 10813 */ 10814 protected boolean hasHoveredChild() { 10815 return false; 10816 } 10817 10818 /** 10819 * Dispatch a generic motion event to the view under the first pointer. 10820 * <p> 10821 * Do not call this method directly. 10822 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10823 * </p> 10824 * 10825 * @param event The motion event to be dispatched. 10826 * @return True if the event was handled by the view, false otherwise. 10827 */ 10828 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 10829 return false; 10830 } 10831 10832 /** 10833 * Dispatch a generic motion event to the currently focused view. 10834 * <p> 10835 * Do not call this method directly. 10836 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10837 * </p> 10838 * 10839 * @param event The motion event to be dispatched. 10840 * @return True if the event was handled by the view, false otherwise. 10841 */ 10842 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 10843 return false; 10844 } 10845 10846 /** 10847 * Dispatch a pointer event. 10848 * <p> 10849 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 10850 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 10851 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 10852 * and should not be expected to handle other pointing device features. 10853 * </p> 10854 * 10855 * @param event The motion event to be dispatched. 10856 * @return True if the event was handled by the view, false otherwise. 10857 * @hide 10858 */ 10859 public final boolean dispatchPointerEvent(MotionEvent event) { 10860 if (event.isTouchEvent()) { 10861 return dispatchTouchEvent(event); 10862 } else { 10863 return dispatchGenericMotionEvent(event); 10864 } 10865 } 10866 10867 /** 10868 * Called when the window containing this view gains or loses window focus. 10869 * ViewGroups should override to route to their children. 10870 * 10871 * @param hasFocus True if the window containing this view now has focus, 10872 * false otherwise. 10873 */ 10874 public void dispatchWindowFocusChanged(boolean hasFocus) { 10875 onWindowFocusChanged(hasFocus); 10876 } 10877 10878 /** 10879 * Called when the window containing this view gains or loses focus. Note 10880 * that this is separate from view focus: to receive key events, both 10881 * your view and its window must have focus. If a window is displayed 10882 * on top of yours that takes input focus, then your own window will lose 10883 * focus but the view focus will remain unchanged. 10884 * 10885 * @param hasWindowFocus True if the window containing this view now has 10886 * focus, false otherwise. 10887 */ 10888 public void onWindowFocusChanged(boolean hasWindowFocus) { 10889 InputMethodManager imm = InputMethodManager.peekInstance(); 10890 if (!hasWindowFocus) { 10891 if (isPressed()) { 10892 setPressed(false); 10893 } 10894 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 10895 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10896 imm.focusOut(this); 10897 } 10898 removeLongPressCallback(); 10899 removeTapCallback(); 10900 onFocusLost(); 10901 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10902 imm.focusIn(this); 10903 } 10904 refreshDrawableState(); 10905 } 10906 10907 /** 10908 * Returns true if this view is in a window that currently has window focus. 10909 * Note that this is not the same as the view itself having focus. 10910 * 10911 * @return True if this view is in a window that currently has window focus. 10912 */ 10913 public boolean hasWindowFocus() { 10914 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 10915 } 10916 10917 /** 10918 * Dispatch a view visibility change down the view hierarchy. 10919 * ViewGroups should override to route to their children. 10920 * @param changedView The view whose visibility changed. Could be 'this' or 10921 * an ancestor view. 10922 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 10923 * {@link #INVISIBLE} or {@link #GONE}. 10924 */ 10925 protected void dispatchVisibilityChanged(@NonNull View changedView, 10926 @Visibility int visibility) { 10927 onVisibilityChanged(changedView, visibility); 10928 } 10929 10930 /** 10931 * Called when the visibility of the view or an ancestor of the view has 10932 * changed. 10933 * 10934 * @param changedView The view whose visibility changed. May be 10935 * {@code this} or an ancestor view. 10936 * @param visibility The new visibility, one of {@link #VISIBLE}, 10937 * {@link #INVISIBLE} or {@link #GONE}. 10938 */ 10939 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 10940 } 10941 10942 /** 10943 * Dispatch a hint about whether this view is displayed. For instance, when 10944 * a View moves out of the screen, it might receives a display hint indicating 10945 * the view is not displayed. Applications should not <em>rely</em> on this hint 10946 * as there is no guarantee that they will receive one. 10947 * 10948 * @param hint A hint about whether or not this view is displayed: 10949 * {@link #VISIBLE} or {@link #INVISIBLE}. 10950 */ 10951 public void dispatchDisplayHint(@Visibility int hint) { 10952 onDisplayHint(hint); 10953 } 10954 10955 /** 10956 * Gives this view a hint about whether is displayed or not. For instance, when 10957 * a View moves out of the screen, it might receives a display hint indicating 10958 * the view is not displayed. Applications should not <em>rely</em> on this hint 10959 * as there is no guarantee that they will receive one. 10960 * 10961 * @param hint A hint about whether or not this view is displayed: 10962 * {@link #VISIBLE} or {@link #INVISIBLE}. 10963 */ 10964 protected void onDisplayHint(@Visibility int hint) { 10965 } 10966 10967 /** 10968 * Dispatch a window visibility change down the view hierarchy. 10969 * ViewGroups should override to route to their children. 10970 * 10971 * @param visibility The new visibility of the window. 10972 * 10973 * @see #onWindowVisibilityChanged(int) 10974 */ 10975 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 10976 onWindowVisibilityChanged(visibility); 10977 } 10978 10979 /** 10980 * Called when the window containing has change its visibility 10981 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 10982 * that this tells you whether or not your window is being made visible 10983 * to the window manager; this does <em>not</em> tell you whether or not 10984 * your window is obscured by other windows on the screen, even if it 10985 * is itself visible. 10986 * 10987 * @param visibility The new visibility of the window. 10988 */ 10989 protected void onWindowVisibilityChanged(@Visibility int visibility) { 10990 if (visibility == VISIBLE) { 10991 initialAwakenScrollBars(); 10992 } 10993 } 10994 10995 /** 10996 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 10997 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 10998 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 10999 * 11000 * @param isVisible true if this view's visibility to the user is uninterrupted by its 11001 * ancestors or by window visibility 11002 * @return true if this view is visible to the user, not counting clipping or overlapping 11003 */ 11004 boolean dispatchVisibilityAggregated(boolean isVisible) { 11005 final boolean thisVisible = getVisibility() == VISIBLE; 11006 // If we're not visible but something is telling us we are, ignore it. 11007 if (thisVisible || !isVisible) { 11008 onVisibilityAggregated(isVisible); 11009 } 11010 return thisVisible && isVisible; 11011 } 11012 11013 /** 11014 * Called when the user-visibility of this View is potentially affected by a change 11015 * to this view itself, an ancestor view or the window this view is attached to. 11016 * 11017 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 11018 * and this view's window is also visible 11019 */ 11020 @CallSuper 11021 public void onVisibilityAggregated(boolean isVisible) { 11022 if (isVisible && mAttachInfo != null) { 11023 initialAwakenScrollBars(); 11024 } 11025 11026 final Drawable dr = mBackground; 11027 if (dr != null && isVisible != dr.isVisible()) { 11028 dr.setVisible(isVisible, false); 11029 } 11030 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 11031 if (fg != null && isVisible != fg.isVisible()) { 11032 fg.setVisible(isVisible, false); 11033 } 11034 } 11035 11036 /** 11037 * Returns the current visibility of the window this view is attached to 11038 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 11039 * 11040 * @return Returns the current visibility of the view's window. 11041 */ 11042 @Visibility 11043 public int getWindowVisibility() { 11044 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 11045 } 11046 11047 /** 11048 * Retrieve the overall visible display size in which the window this view is 11049 * attached to has been positioned in. This takes into account screen 11050 * decorations above the window, for both cases where the window itself 11051 * is being position inside of them or the window is being placed under 11052 * then and covered insets are used for the window to position its content 11053 * inside. In effect, this tells you the available area where content can 11054 * be placed and remain visible to users. 11055 * 11056 * <p>This function requires an IPC back to the window manager to retrieve 11057 * the requested information, so should not be used in performance critical 11058 * code like drawing. 11059 * 11060 * @param outRect Filled in with the visible display frame. If the view 11061 * is not attached to a window, this is simply the raw display size. 11062 */ 11063 public void getWindowVisibleDisplayFrame(Rect outRect) { 11064 if (mAttachInfo != null) { 11065 try { 11066 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 11067 } catch (RemoteException e) { 11068 return; 11069 } 11070 // XXX This is really broken, and probably all needs to be done 11071 // in the window manager, and we need to know more about whether 11072 // we want the area behind or in front of the IME. 11073 final Rect insets = mAttachInfo.mVisibleInsets; 11074 outRect.left += insets.left; 11075 outRect.top += insets.top; 11076 outRect.right -= insets.right; 11077 outRect.bottom -= insets.bottom; 11078 return; 11079 } 11080 // The view is not attached to a display so we don't have a context. 11081 // Make a best guess about the display size. 11082 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 11083 d.getRectSize(outRect); 11084 } 11085 11086 /** 11087 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 11088 * is currently in without any insets. 11089 * 11090 * @hide 11091 */ 11092 public void getWindowDisplayFrame(Rect outRect) { 11093 if (mAttachInfo != null) { 11094 try { 11095 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 11096 } catch (RemoteException e) { 11097 return; 11098 } 11099 return; 11100 } 11101 // The view is not attached to a display so we don't have a context. 11102 // Make a best guess about the display size. 11103 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 11104 d.getRectSize(outRect); 11105 } 11106 11107 /** 11108 * Dispatch a notification about a resource configuration change down 11109 * the view hierarchy. 11110 * ViewGroups should override to route to their children. 11111 * 11112 * @param newConfig The new resource configuration. 11113 * 11114 * @see #onConfigurationChanged(android.content.res.Configuration) 11115 */ 11116 public void dispatchConfigurationChanged(Configuration newConfig) { 11117 onConfigurationChanged(newConfig); 11118 } 11119 11120 /** 11121 * Called when the current configuration of the resources being used 11122 * by the application have changed. You can use this to decide when 11123 * to reload resources that can changed based on orientation and other 11124 * configuration characteristics. You only need to use this if you are 11125 * not relying on the normal {@link android.app.Activity} mechanism of 11126 * recreating the activity instance upon a configuration change. 11127 * 11128 * @param newConfig The new resource configuration. 11129 */ 11130 protected void onConfigurationChanged(Configuration newConfig) { 11131 } 11132 11133 /** 11134 * Private function to aggregate all per-view attributes in to the view 11135 * root. 11136 */ 11137 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 11138 performCollectViewAttributes(attachInfo, visibility); 11139 } 11140 11141 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 11142 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 11143 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 11144 attachInfo.mKeepScreenOn = true; 11145 } 11146 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 11147 ListenerInfo li = mListenerInfo; 11148 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 11149 attachInfo.mHasSystemUiListeners = true; 11150 } 11151 } 11152 } 11153 11154 void needGlobalAttributesUpdate(boolean force) { 11155 final AttachInfo ai = mAttachInfo; 11156 if (ai != null && !ai.mRecomputeGlobalAttributes) { 11157 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 11158 || ai.mHasSystemUiListeners) { 11159 ai.mRecomputeGlobalAttributes = true; 11160 } 11161 } 11162 } 11163 11164 /** 11165 * Returns whether the device is currently in touch mode. Touch mode is entered 11166 * once the user begins interacting with the device by touch, and affects various 11167 * things like whether focus is always visible to the user. 11168 * 11169 * @return Whether the device is in touch mode. 11170 */ 11171 @ViewDebug.ExportedProperty 11172 public boolean isInTouchMode() { 11173 if (mAttachInfo != null) { 11174 return mAttachInfo.mInTouchMode; 11175 } else { 11176 return ViewRootImpl.isInTouchMode(); 11177 } 11178 } 11179 11180 /** 11181 * Returns the context the view is running in, through which it can 11182 * access the current theme, resources, etc. 11183 * 11184 * @return The view's Context. 11185 */ 11186 @ViewDebug.CapturedViewProperty 11187 public final Context getContext() { 11188 return mContext; 11189 } 11190 11191 /** 11192 * Handle a key event before it is processed by any input method 11193 * associated with the view hierarchy. This can be used to intercept 11194 * key events in special situations before the IME consumes them; a 11195 * typical example would be handling the BACK key to update the application's 11196 * UI instead of allowing the IME to see it and close itself. 11197 * 11198 * @param keyCode The value in event.getKeyCode(). 11199 * @param event Description of the key event. 11200 * @return If you handled the event, return true. If you want to allow the 11201 * event to be handled by the next receiver, return false. 11202 */ 11203 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 11204 return false; 11205 } 11206 11207 /** 11208 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 11209 * KeyEvent.Callback.onKeyDown()}: perform press of the view 11210 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 11211 * is released, if the view is enabled and clickable. 11212 * <p> 11213 * Key presses in software keyboards will generally NOT trigger this 11214 * listener, although some may elect to do so in some situations. Do not 11215 * rely on this to catch software key presses. 11216 * 11217 * @param keyCode a key code that represents the button pressed, from 11218 * {@link android.view.KeyEvent} 11219 * @param event the KeyEvent object that defines the button action 11220 */ 11221 public boolean onKeyDown(int keyCode, KeyEvent event) { 11222 if (KeyEvent.isConfirmKey(keyCode)) { 11223 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11224 return true; 11225 } 11226 11227 if (event.getRepeatCount() == 0) { 11228 // Long clickable items don't necessarily have to be clickable. 11229 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 11230 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 11231 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 11232 // For the purposes of menu anchoring and drawable hotspots, 11233 // key events are considered to be at the center of the view. 11234 final float x = getWidth() / 2f; 11235 final float y = getHeight() / 2f; 11236 if (clickable) { 11237 setPressed(true, x, y); 11238 } 11239 checkForLongClick(0, x, y); 11240 return true; 11241 } 11242 } 11243 } 11244 11245 return false; 11246 } 11247 11248 /** 11249 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 11250 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 11251 * the event). 11252 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11253 * although some may elect to do so in some situations. Do not rely on this to 11254 * catch software key presses. 11255 */ 11256 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 11257 return false; 11258 } 11259 11260 /** 11261 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 11262 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 11263 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 11264 * or {@link KeyEvent#KEYCODE_SPACE} is released. 11265 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11266 * although some may elect to do so in some situations. Do not rely on this to 11267 * catch software key presses. 11268 * 11269 * @param keyCode A key code that represents the button pressed, from 11270 * {@link android.view.KeyEvent}. 11271 * @param event The KeyEvent object that defines the button action. 11272 */ 11273 public boolean onKeyUp(int keyCode, KeyEvent event) { 11274 if (KeyEvent.isConfirmKey(keyCode)) { 11275 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11276 return true; 11277 } 11278 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 11279 setPressed(false); 11280 11281 if (!mHasPerformedLongPress) { 11282 // This is a tap, so remove the longpress check 11283 removeLongPressCallback(); 11284 return performClick(); 11285 } 11286 } 11287 } 11288 return false; 11289 } 11290 11291 /** 11292 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 11293 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 11294 * the event). 11295 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11296 * although some may elect to do so in some situations. Do not rely on this to 11297 * catch software key presses. 11298 * 11299 * @param keyCode A key code that represents the button pressed, from 11300 * {@link android.view.KeyEvent}. 11301 * @param repeatCount The number of times the action was made. 11302 * @param event The KeyEvent object that defines the button action. 11303 */ 11304 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 11305 return false; 11306 } 11307 11308 /** 11309 * Called on the focused view when a key shortcut event is not handled. 11310 * Override this method to implement local key shortcuts for the View. 11311 * Key shortcuts can also be implemented by setting the 11312 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 11313 * 11314 * @param keyCode The value in event.getKeyCode(). 11315 * @param event Description of the key event. 11316 * @return If you handled the event, return true. If you want to allow the 11317 * event to be handled by the next receiver, return false. 11318 */ 11319 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 11320 return false; 11321 } 11322 11323 /** 11324 * Check whether the called view is a text editor, in which case it 11325 * would make sense to automatically display a soft input window for 11326 * it. Subclasses should override this if they implement 11327 * {@link #onCreateInputConnection(EditorInfo)} to return true if 11328 * a call on that method would return a non-null InputConnection, and 11329 * they are really a first-class editor that the user would normally 11330 * start typing on when the go into a window containing your view. 11331 * 11332 * <p>The default implementation always returns false. This does 11333 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 11334 * will not be called or the user can not otherwise perform edits on your 11335 * view; it is just a hint to the system that this is not the primary 11336 * purpose of this view. 11337 * 11338 * @return Returns true if this view is a text editor, else false. 11339 */ 11340 public boolean onCheckIsTextEditor() { 11341 return false; 11342 } 11343 11344 /** 11345 * Create a new InputConnection for an InputMethod to interact 11346 * with the view. The default implementation returns null, since it doesn't 11347 * support input methods. You can override this to implement such support. 11348 * This is only needed for views that take focus and text input. 11349 * 11350 * <p>When implementing this, you probably also want to implement 11351 * {@link #onCheckIsTextEditor()} to indicate you will return a 11352 * non-null InputConnection.</p> 11353 * 11354 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 11355 * object correctly and in its entirety, so that the connected IME can rely 11356 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 11357 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 11358 * must be filled in with the correct cursor position for IMEs to work correctly 11359 * with your application.</p> 11360 * 11361 * @param outAttrs Fill in with attribute information about the connection. 11362 */ 11363 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 11364 return null; 11365 } 11366 11367 /** 11368 * Called by the {@link android.view.inputmethod.InputMethodManager} 11369 * when a view who is not the current 11370 * input connection target is trying to make a call on the manager. The 11371 * default implementation returns false; you can override this to return 11372 * true for certain views if you are performing InputConnection proxying 11373 * to them. 11374 * @param view The View that is making the InputMethodManager call. 11375 * @return Return true to allow the call, false to reject. 11376 */ 11377 public boolean checkInputConnectionProxy(View view) { 11378 return false; 11379 } 11380 11381 /** 11382 * Show the context menu for this view. It is not safe to hold on to the 11383 * menu after returning from this method. 11384 * 11385 * You should normally not overload this method. Overload 11386 * {@link #onCreateContextMenu(ContextMenu)} or define an 11387 * {@link OnCreateContextMenuListener} to add items to the context menu. 11388 * 11389 * @param menu The context menu to populate 11390 */ 11391 public void createContextMenu(ContextMenu menu) { 11392 ContextMenuInfo menuInfo = getContextMenuInfo(); 11393 11394 // Sets the current menu info so all items added to menu will have 11395 // my extra info set. 11396 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 11397 11398 onCreateContextMenu(menu); 11399 ListenerInfo li = mListenerInfo; 11400 if (li != null && li.mOnCreateContextMenuListener != null) { 11401 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 11402 } 11403 11404 // Clear the extra information so subsequent items that aren't mine don't 11405 // have my extra info. 11406 ((MenuBuilder)menu).setCurrentMenuInfo(null); 11407 11408 if (mParent != null) { 11409 mParent.createContextMenu(menu); 11410 } 11411 } 11412 11413 /** 11414 * Views should implement this if they have extra information to associate 11415 * with the context menu. The return result is supplied as a parameter to 11416 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 11417 * callback. 11418 * 11419 * @return Extra information about the item for which the context menu 11420 * should be shown. This information will vary across different 11421 * subclasses of View. 11422 */ 11423 protected ContextMenuInfo getContextMenuInfo() { 11424 return null; 11425 } 11426 11427 /** 11428 * Views should implement this if the view itself is going to add items to 11429 * the context menu. 11430 * 11431 * @param menu the context menu to populate 11432 */ 11433 protected void onCreateContextMenu(ContextMenu menu) { 11434 } 11435 11436 /** 11437 * Implement this method to handle trackball motion events. The 11438 * <em>relative</em> movement of the trackball since the last event 11439 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 11440 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 11441 * that a movement of 1 corresponds to the user pressing one DPAD key (so 11442 * they will often be fractional values, representing the more fine-grained 11443 * movement information available from a trackball). 11444 * 11445 * @param event The motion event. 11446 * @return True if the event was handled, false otherwise. 11447 */ 11448 public boolean onTrackballEvent(MotionEvent event) { 11449 return false; 11450 } 11451 11452 /** 11453 * Implement this method to handle generic motion events. 11454 * <p> 11455 * Generic motion events describe joystick movements, mouse hovers, track pad 11456 * touches, scroll wheel movements and other input events. The 11457 * {@link MotionEvent#getSource() source} of the motion event specifies 11458 * the class of input that was received. Implementations of this method 11459 * must examine the bits in the source before processing the event. 11460 * The following code example shows how this is done. 11461 * </p><p> 11462 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11463 * are delivered to the view under the pointer. All other generic motion events are 11464 * delivered to the focused view. 11465 * </p> 11466 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 11467 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 11468 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 11469 * // process the joystick movement... 11470 * return true; 11471 * } 11472 * } 11473 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 11474 * switch (event.getAction()) { 11475 * case MotionEvent.ACTION_HOVER_MOVE: 11476 * // process the mouse hover movement... 11477 * return true; 11478 * case MotionEvent.ACTION_SCROLL: 11479 * // process the scroll wheel movement... 11480 * return true; 11481 * } 11482 * } 11483 * return super.onGenericMotionEvent(event); 11484 * }</pre> 11485 * 11486 * @param event The generic motion event being processed. 11487 * @return True if the event was handled, false otherwise. 11488 */ 11489 public boolean onGenericMotionEvent(MotionEvent event) { 11490 return false; 11491 } 11492 11493 /** 11494 * Implement this method to handle hover events. 11495 * <p> 11496 * This method is called whenever a pointer is hovering into, over, or out of the 11497 * bounds of a view and the view is not currently being touched. 11498 * Hover events are represented as pointer events with action 11499 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 11500 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 11501 * </p> 11502 * <ul> 11503 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 11504 * when the pointer enters the bounds of the view.</li> 11505 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 11506 * when the pointer has already entered the bounds of the view and has moved.</li> 11507 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 11508 * when the pointer has exited the bounds of the view or when the pointer is 11509 * about to go down due to a button click, tap, or similar user action that 11510 * causes the view to be touched.</li> 11511 * </ul> 11512 * <p> 11513 * The view should implement this method to return true to indicate that it is 11514 * handling the hover event, such as by changing its drawable state. 11515 * </p><p> 11516 * The default implementation calls {@link #setHovered} to update the hovered state 11517 * of the view when a hover enter or hover exit event is received, if the view 11518 * is enabled and is clickable. The default implementation also sends hover 11519 * accessibility events. 11520 * </p> 11521 * 11522 * @param event The motion event that describes the hover. 11523 * @return True if the view handled the hover event. 11524 * 11525 * @see #isHovered 11526 * @see #setHovered 11527 * @see #onHoverChanged 11528 */ 11529 public boolean onHoverEvent(MotionEvent event) { 11530 // The root view may receive hover (or touch) events that are outside the bounds of 11531 // the window. This code ensures that we only send accessibility events for 11532 // hovers that are actually within the bounds of the root view. 11533 final int action = event.getActionMasked(); 11534 if (!mSendingHoverAccessibilityEvents) { 11535 if ((action == MotionEvent.ACTION_HOVER_ENTER 11536 || action == MotionEvent.ACTION_HOVER_MOVE) 11537 && !hasHoveredChild() 11538 && pointInView(event.getX(), event.getY())) { 11539 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 11540 mSendingHoverAccessibilityEvents = true; 11541 } 11542 } else { 11543 if (action == MotionEvent.ACTION_HOVER_EXIT 11544 || (action == MotionEvent.ACTION_MOVE 11545 && !pointInView(event.getX(), event.getY()))) { 11546 mSendingHoverAccessibilityEvents = false; 11547 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 11548 } 11549 } 11550 11551 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 11552 && event.isFromSource(InputDevice.SOURCE_MOUSE) 11553 && isOnScrollbar(event.getX(), event.getY())) { 11554 awakenScrollBars(); 11555 } 11556 if (isHoverable()) { 11557 switch (action) { 11558 case MotionEvent.ACTION_HOVER_ENTER: 11559 setHovered(true); 11560 break; 11561 case MotionEvent.ACTION_HOVER_EXIT: 11562 setHovered(false); 11563 break; 11564 } 11565 11566 // Dispatch the event to onGenericMotionEvent before returning true. 11567 // This is to provide compatibility with existing applications that 11568 // handled HOVER_MOVE events in onGenericMotionEvent and that would 11569 // break because of the new default handling for hoverable views 11570 // in onHoverEvent. 11571 // Note that onGenericMotionEvent will be called by default when 11572 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 11573 dispatchGenericMotionEventInternal(event); 11574 // The event was already handled by calling setHovered(), so always 11575 // return true. 11576 return true; 11577 } 11578 11579 return false; 11580 } 11581 11582 /** 11583 * Returns true if the view should handle {@link #onHoverEvent} 11584 * by calling {@link #setHovered} to change its hovered state. 11585 * 11586 * @return True if the view is hoverable. 11587 */ 11588 private boolean isHoverable() { 11589 final int viewFlags = mViewFlags; 11590 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11591 return false; 11592 } 11593 11594 return (viewFlags & CLICKABLE) == CLICKABLE 11595 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 11596 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11597 } 11598 11599 /** 11600 * Returns true if the view is currently hovered. 11601 * 11602 * @return True if the view is currently hovered. 11603 * 11604 * @see #setHovered 11605 * @see #onHoverChanged 11606 */ 11607 @ViewDebug.ExportedProperty 11608 public boolean isHovered() { 11609 return (mPrivateFlags & PFLAG_HOVERED) != 0; 11610 } 11611 11612 /** 11613 * Sets whether the view is currently hovered. 11614 * <p> 11615 * Calling this method also changes the drawable state of the view. This 11616 * enables the view to react to hover by using different drawable resources 11617 * to change its appearance. 11618 * </p><p> 11619 * The {@link #onHoverChanged} method is called when the hovered state changes. 11620 * </p> 11621 * 11622 * @param hovered True if the view is hovered. 11623 * 11624 * @see #isHovered 11625 * @see #onHoverChanged 11626 */ 11627 public void setHovered(boolean hovered) { 11628 if (hovered) { 11629 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 11630 mPrivateFlags |= PFLAG_HOVERED; 11631 refreshDrawableState(); 11632 onHoverChanged(true); 11633 } 11634 } else { 11635 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 11636 mPrivateFlags &= ~PFLAG_HOVERED; 11637 refreshDrawableState(); 11638 onHoverChanged(false); 11639 } 11640 } 11641 } 11642 11643 /** 11644 * Implement this method to handle hover state changes. 11645 * <p> 11646 * This method is called whenever the hover state changes as a result of a 11647 * call to {@link #setHovered}. 11648 * </p> 11649 * 11650 * @param hovered The current hover state, as returned by {@link #isHovered}. 11651 * 11652 * @see #isHovered 11653 * @see #setHovered 11654 */ 11655 public void onHoverChanged(boolean hovered) { 11656 } 11657 11658 /** 11659 * Handles scroll bar dragging by mouse input. 11660 * 11661 * @hide 11662 * @param event The motion event. 11663 * 11664 * @return true if the event was handled as a scroll bar dragging, false otherwise. 11665 */ 11666 protected boolean handleScrollBarDragging(MotionEvent event) { 11667 if (mScrollCache == null) { 11668 return false; 11669 } 11670 final float x = event.getX(); 11671 final float y = event.getY(); 11672 final int action = event.getAction(); 11673 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 11674 && action != MotionEvent.ACTION_DOWN) 11675 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 11676 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 11677 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11678 return false; 11679 } 11680 11681 switch (action) { 11682 case MotionEvent.ACTION_MOVE: 11683 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 11684 return false; 11685 } 11686 if (mScrollCache.mScrollBarDraggingState 11687 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 11688 final Rect bounds = mScrollCache.mScrollBarBounds; 11689 getVerticalScrollBarBounds(bounds); 11690 final int range = computeVerticalScrollRange(); 11691 final int offset = computeVerticalScrollOffset(); 11692 final int extent = computeVerticalScrollExtent(); 11693 11694 final int thumbLength = ScrollBarUtils.getThumbLength( 11695 bounds.height(), bounds.width(), extent, range); 11696 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11697 bounds.height(), thumbLength, extent, range, offset); 11698 11699 final float diff = y - mScrollCache.mScrollBarDraggingPos; 11700 final float maxThumbOffset = bounds.height() - thumbLength; 11701 final float newThumbOffset = 11702 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11703 final int height = getHeight(); 11704 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11705 && height > 0 && extent > 0) { 11706 final int newY = Math.round((range - extent) 11707 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 11708 if (newY != getScrollY()) { 11709 mScrollCache.mScrollBarDraggingPos = y; 11710 setScrollY(newY); 11711 } 11712 } 11713 return true; 11714 } 11715 if (mScrollCache.mScrollBarDraggingState 11716 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 11717 final Rect bounds = mScrollCache.mScrollBarBounds; 11718 getHorizontalScrollBarBounds(bounds); 11719 final int range = computeHorizontalScrollRange(); 11720 final int offset = computeHorizontalScrollOffset(); 11721 final int extent = computeHorizontalScrollExtent(); 11722 11723 final int thumbLength = ScrollBarUtils.getThumbLength( 11724 bounds.width(), bounds.height(), extent, range); 11725 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11726 bounds.width(), thumbLength, extent, range, offset); 11727 11728 final float diff = x - mScrollCache.mScrollBarDraggingPos; 11729 final float maxThumbOffset = bounds.width() - thumbLength; 11730 final float newThumbOffset = 11731 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11732 final int width = getWidth(); 11733 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11734 && width > 0 && extent > 0) { 11735 final int newX = Math.round((range - extent) 11736 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 11737 if (newX != getScrollX()) { 11738 mScrollCache.mScrollBarDraggingPos = x; 11739 setScrollX(newX); 11740 } 11741 } 11742 return true; 11743 } 11744 case MotionEvent.ACTION_DOWN: 11745 if (mScrollCache.state == ScrollabilityCache.OFF) { 11746 return false; 11747 } 11748 if (isOnVerticalScrollbarThumb(x, y)) { 11749 mScrollCache.mScrollBarDraggingState = 11750 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 11751 mScrollCache.mScrollBarDraggingPos = y; 11752 return true; 11753 } 11754 if (isOnHorizontalScrollbarThumb(x, y)) { 11755 mScrollCache.mScrollBarDraggingState = 11756 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 11757 mScrollCache.mScrollBarDraggingPos = x; 11758 return true; 11759 } 11760 } 11761 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11762 return false; 11763 } 11764 11765 /** 11766 * Implement this method to handle touch screen motion events. 11767 * <p> 11768 * If this method is used to detect click actions, it is recommended that 11769 * the actions be performed by implementing and calling 11770 * {@link #performClick()}. This will ensure consistent system behavior, 11771 * including: 11772 * <ul> 11773 * <li>obeying click sound preferences 11774 * <li>dispatching OnClickListener calls 11775 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 11776 * accessibility features are enabled 11777 * </ul> 11778 * 11779 * @param event The motion event. 11780 * @return True if the event was handled, false otherwise. 11781 */ 11782 public boolean onTouchEvent(MotionEvent event) { 11783 final float x = event.getX(); 11784 final float y = event.getY(); 11785 final int viewFlags = mViewFlags; 11786 final int action = event.getAction(); 11787 11788 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 11789 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 11790 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11791 11792 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11793 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 11794 setPressed(false); 11795 } 11796 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11797 // A disabled view that is clickable still consumes the touch 11798 // events, it just doesn't respond to them. 11799 return clickable; 11800 } 11801 if (mTouchDelegate != null) { 11802 if (mTouchDelegate.onTouchEvent(event)) { 11803 return true; 11804 } 11805 } 11806 11807 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 11808 switch (action) { 11809 case MotionEvent.ACTION_UP: 11810 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11811 if ((viewFlags & TOOLTIP) == TOOLTIP) { 11812 handleTooltipUp(); 11813 } 11814 if (!clickable) { 11815 removeTapCallback(); 11816 removeLongPressCallback(); 11817 mInContextButtonPress = false; 11818 mHasPerformedLongPress = false; 11819 mIgnoreNextUpEvent = false; 11820 break; 11821 } 11822 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 11823 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 11824 // take focus if we don't have it already and we should in 11825 // touch mode. 11826 boolean focusTaken = false; 11827 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 11828 focusTaken = requestFocus(); 11829 } 11830 11831 if (prepressed) { 11832 // The button is being released before we actually 11833 // showed it as pressed. Make it show the pressed 11834 // state now (before scheduling the click) to ensure 11835 // the user sees it. 11836 setPressed(true, x, y); 11837 } 11838 11839 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 11840 // This is a tap, so remove the longpress check 11841 removeLongPressCallback(); 11842 11843 // Only perform take click actions if we were in the pressed state 11844 if (!focusTaken) { 11845 // Use a Runnable and post this rather than calling 11846 // performClick directly. This lets other visual state 11847 // of the view update before click actions start. 11848 if (mPerformClick == null) { 11849 mPerformClick = new PerformClick(); 11850 } 11851 if (!post(mPerformClick)) { 11852 performClick(); 11853 } 11854 } 11855 } 11856 11857 if (mUnsetPressedState == null) { 11858 mUnsetPressedState = new UnsetPressedState(); 11859 } 11860 11861 if (prepressed) { 11862 postDelayed(mUnsetPressedState, 11863 ViewConfiguration.getPressedStateDuration()); 11864 } else if (!post(mUnsetPressedState)) { 11865 // If the post failed, unpress right now 11866 mUnsetPressedState.run(); 11867 } 11868 11869 removeTapCallback(); 11870 } 11871 mIgnoreNextUpEvent = false; 11872 break; 11873 11874 case MotionEvent.ACTION_DOWN: 11875 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 11876 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 11877 } 11878 mHasPerformedLongPress = false; 11879 11880 if (!clickable) { 11881 checkForLongClick(0, x, y); 11882 break; 11883 } 11884 11885 if (performButtonActionOnTouchDown(event)) { 11886 break; 11887 } 11888 11889 // Walk up the hierarchy to determine if we're inside a scrolling container. 11890 boolean isInScrollingContainer = isInScrollingContainer(); 11891 11892 // For views inside a scrolling container, delay the pressed feedback for 11893 // a short period in case this is a scroll. 11894 if (isInScrollingContainer) { 11895 mPrivateFlags |= PFLAG_PREPRESSED; 11896 if (mPendingCheckForTap == null) { 11897 mPendingCheckForTap = new CheckForTap(); 11898 } 11899 mPendingCheckForTap.x = event.getX(); 11900 mPendingCheckForTap.y = event.getY(); 11901 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 11902 } else { 11903 // Not inside a scrolling container, so show the feedback right away 11904 setPressed(true, x, y); 11905 checkForLongClick(0, x, y); 11906 } 11907 break; 11908 11909 case MotionEvent.ACTION_CANCEL: 11910 if (clickable) { 11911 setPressed(false); 11912 } 11913 removeTapCallback(); 11914 removeLongPressCallback(); 11915 mInContextButtonPress = false; 11916 mHasPerformedLongPress = false; 11917 mIgnoreNextUpEvent = false; 11918 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11919 break; 11920 11921 case MotionEvent.ACTION_MOVE: 11922 if (clickable) { 11923 drawableHotspotChanged(x, y); 11924 } 11925 11926 // Be lenient about moving outside of buttons 11927 if (!pointInView(x, y, mTouchSlop)) { 11928 // Outside button 11929 // Remove any future long press/tap checks 11930 removeTapCallback(); 11931 removeLongPressCallback(); 11932 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 11933 setPressed(false); 11934 } 11935 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11936 } 11937 break; 11938 } 11939 11940 return true; 11941 } 11942 11943 return false; 11944 } 11945 11946 /** 11947 * @hide 11948 */ 11949 public boolean isInScrollingContainer() { 11950 ViewParent p = getParent(); 11951 while (p != null && p instanceof ViewGroup) { 11952 if (((ViewGroup) p).shouldDelayChildPressedState()) { 11953 return true; 11954 } 11955 p = p.getParent(); 11956 } 11957 return false; 11958 } 11959 11960 /** 11961 * Remove the longpress detection timer. 11962 */ 11963 private void removeLongPressCallback() { 11964 if (mPendingCheckForLongPress != null) { 11965 removeCallbacks(mPendingCheckForLongPress); 11966 } 11967 } 11968 11969 /** 11970 * Remove the pending click action 11971 */ 11972 private void removePerformClickCallback() { 11973 if (mPerformClick != null) { 11974 removeCallbacks(mPerformClick); 11975 } 11976 } 11977 11978 /** 11979 * Remove the prepress detection timer. 11980 */ 11981 private void removeUnsetPressCallback() { 11982 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 11983 setPressed(false); 11984 removeCallbacks(mUnsetPressedState); 11985 } 11986 } 11987 11988 /** 11989 * Remove the tap detection timer. 11990 */ 11991 private void removeTapCallback() { 11992 if (mPendingCheckForTap != null) { 11993 mPrivateFlags &= ~PFLAG_PREPRESSED; 11994 removeCallbacks(mPendingCheckForTap); 11995 } 11996 } 11997 11998 /** 11999 * Cancels a pending long press. Your subclass can use this if you 12000 * want the context menu to come up if the user presses and holds 12001 * at the same place, but you don't want it to come up if they press 12002 * and then move around enough to cause scrolling. 12003 */ 12004 public void cancelLongPress() { 12005 removeLongPressCallback(); 12006 12007 /* 12008 * The prepressed state handled by the tap callback is a display 12009 * construct, but the tap callback will post a long press callback 12010 * less its own timeout. Remove it here. 12011 */ 12012 removeTapCallback(); 12013 } 12014 12015 /** 12016 * Remove the pending callback for sending a 12017 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 12018 */ 12019 private void removeSendViewScrolledAccessibilityEventCallback() { 12020 if (mSendViewScrolledAccessibilityEvent != null) { 12021 removeCallbacks(mSendViewScrolledAccessibilityEvent); 12022 mSendViewScrolledAccessibilityEvent.mIsPending = false; 12023 } 12024 } 12025 12026 /** 12027 * Sets the TouchDelegate for this View. 12028 */ 12029 public void setTouchDelegate(TouchDelegate delegate) { 12030 mTouchDelegate = delegate; 12031 } 12032 12033 /** 12034 * Gets the TouchDelegate for this View. 12035 */ 12036 public TouchDelegate getTouchDelegate() { 12037 return mTouchDelegate; 12038 } 12039 12040 /** 12041 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 12042 * 12043 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 12044 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 12045 * available. This method should only be called for touch events. 12046 * 12047 * <p class="note">This api is not intended for most applications. Buffered dispatch 12048 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 12049 * streams will not improve your input latency. Side effects include: increased latency, 12050 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 12051 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 12052 * you.</p> 12053 */ 12054 public final void requestUnbufferedDispatch(MotionEvent event) { 12055 final int action = event.getAction(); 12056 if (mAttachInfo == null 12057 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 12058 || !event.isTouchEvent()) { 12059 return; 12060 } 12061 mAttachInfo.mUnbufferedDispatchRequested = true; 12062 } 12063 12064 /** 12065 * Set flags controlling behavior of this view. 12066 * 12067 * @param flags Constant indicating the value which should be set 12068 * @param mask Constant indicating the bit range that should be changed 12069 */ 12070 void setFlags(int flags, int mask) { 12071 final boolean accessibilityEnabled = 12072 AccessibilityManager.getInstance(mContext).isEnabled(); 12073 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 12074 12075 int old = mViewFlags; 12076 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 12077 12078 int changed = mViewFlags ^ old; 12079 if (changed == 0) { 12080 return; 12081 } 12082 int privateFlags = mPrivateFlags; 12083 12084 /* Check if the FOCUSABLE bit has changed */ 12085 if (((changed & FOCUSABLE_MASK) != 0) && 12086 ((privateFlags & PFLAG_HAS_BOUNDS) !=0)) { 12087 if (((old & FOCUSABLE_MASK) == FOCUSABLE) 12088 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 12089 /* Give up focus if we are no longer focusable */ 12090 clearFocus(); 12091 } else if (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE) 12092 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 12093 /* 12094 * Tell the view system that we are now available to take focus 12095 * if no one else already has it. 12096 */ 12097 if (mParent != null) mParent.focusableViewAvailable(this); 12098 } 12099 } 12100 12101 final int newVisibility = flags & VISIBILITY_MASK; 12102 if (newVisibility == VISIBLE) { 12103 if ((changed & VISIBILITY_MASK) != 0) { 12104 /* 12105 * If this view is becoming visible, invalidate it in case it changed while 12106 * it was not visible. Marking it drawn ensures that the invalidation will 12107 * go through. 12108 */ 12109 mPrivateFlags |= PFLAG_DRAWN; 12110 invalidate(true); 12111 12112 needGlobalAttributesUpdate(true); 12113 12114 // a view becoming visible is worth notifying the parent 12115 // about in case nothing has focus. even if this specific view 12116 // isn't focusable, it may contain something that is, so let 12117 // the root view try to give this focus if nothing else does. 12118 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 12119 mParent.focusableViewAvailable(this); 12120 } 12121 } 12122 } 12123 12124 /* Check if the GONE bit has changed */ 12125 if ((changed & GONE) != 0) { 12126 needGlobalAttributesUpdate(false); 12127 requestLayout(); 12128 12129 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 12130 if (hasFocus()) clearFocus(); 12131 clearAccessibilityFocus(); 12132 destroyDrawingCache(); 12133 if (mParent instanceof View) { 12134 // GONE views noop invalidation, so invalidate the parent 12135 ((View) mParent).invalidate(true); 12136 } 12137 // Mark the view drawn to ensure that it gets invalidated properly the next 12138 // time it is visible and gets invalidated 12139 mPrivateFlags |= PFLAG_DRAWN; 12140 } 12141 if (mAttachInfo != null) { 12142 mAttachInfo.mViewVisibilityChanged = true; 12143 } 12144 } 12145 12146 /* Check if the VISIBLE bit has changed */ 12147 if ((changed & INVISIBLE) != 0) { 12148 needGlobalAttributesUpdate(false); 12149 /* 12150 * If this view is becoming invisible, set the DRAWN flag so that 12151 * the next invalidate() will not be skipped. 12152 */ 12153 mPrivateFlags |= PFLAG_DRAWN; 12154 12155 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 12156 // root view becoming invisible shouldn't clear focus and accessibility focus 12157 if (getRootView() != this) { 12158 if (hasFocus()) clearFocus(); 12159 clearAccessibilityFocus(); 12160 } 12161 } 12162 if (mAttachInfo != null) { 12163 mAttachInfo.mViewVisibilityChanged = true; 12164 } 12165 } 12166 12167 if ((changed & VISIBILITY_MASK) != 0) { 12168 // If the view is invisible, cleanup its display list to free up resources 12169 if (newVisibility != VISIBLE && mAttachInfo != null) { 12170 cleanupDraw(); 12171 } 12172 12173 if (mParent instanceof ViewGroup) { 12174 ((ViewGroup) mParent).onChildVisibilityChanged(this, 12175 (changed & VISIBILITY_MASK), newVisibility); 12176 ((View) mParent).invalidate(true); 12177 } else if (mParent != null) { 12178 mParent.invalidateChild(this, null); 12179 } 12180 12181 if (mAttachInfo != null) { 12182 dispatchVisibilityChanged(this, newVisibility); 12183 12184 // Aggregated visibility changes are dispatched to attached views 12185 // in visible windows where the parent is currently shown/drawn 12186 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 12187 // discounting clipping or overlapping. This makes it a good place 12188 // to change animation states. 12189 if (mParent != null && getWindowVisibility() == VISIBLE && 12190 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 12191 dispatchVisibilityAggregated(newVisibility == VISIBLE); 12192 } 12193 notifySubtreeAccessibilityStateChangedIfNeeded(); 12194 } 12195 } 12196 12197 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 12198 destroyDrawingCache(); 12199 } 12200 12201 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 12202 destroyDrawingCache(); 12203 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12204 invalidateParentCaches(); 12205 } 12206 12207 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 12208 destroyDrawingCache(); 12209 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12210 } 12211 12212 if ((changed & DRAW_MASK) != 0) { 12213 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 12214 if (mBackground != null 12215 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 12216 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12217 } else { 12218 mPrivateFlags |= PFLAG_SKIP_DRAW; 12219 } 12220 } else { 12221 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12222 } 12223 requestLayout(); 12224 invalidate(true); 12225 } 12226 12227 if ((changed & KEEP_SCREEN_ON) != 0) { 12228 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 12229 mParent.recomputeViewAttributes(this); 12230 } 12231 } 12232 12233 if (accessibilityEnabled) { 12234 if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0 12235 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 12236 || (changed & CONTEXT_CLICKABLE) != 0) { 12237 if (oldIncludeForAccessibility != includeForAccessibility()) { 12238 notifySubtreeAccessibilityStateChangedIfNeeded(); 12239 } else { 12240 notifyViewAccessibilityStateChangedIfNeeded( 12241 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12242 } 12243 } else if ((changed & ENABLED_MASK) != 0) { 12244 notifyViewAccessibilityStateChangedIfNeeded( 12245 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12246 } 12247 } 12248 } 12249 12250 /** 12251 * Change the view's z order in the tree, so it's on top of other sibling 12252 * views. This ordering change may affect layout, if the parent container 12253 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 12254 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 12255 * method should be followed by calls to {@link #requestLayout()} and 12256 * {@link View#invalidate()} on the view's parent to force the parent to redraw 12257 * with the new child ordering. 12258 * 12259 * @see ViewGroup#bringChildToFront(View) 12260 */ 12261 public void bringToFront() { 12262 if (mParent != null) { 12263 mParent.bringChildToFront(this); 12264 } 12265 } 12266 12267 /** 12268 * This is called in response to an internal scroll in this view (i.e., the 12269 * view scrolled its own contents). This is typically as a result of 12270 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 12271 * called. 12272 * 12273 * @param l Current horizontal scroll origin. 12274 * @param t Current vertical scroll origin. 12275 * @param oldl Previous horizontal scroll origin. 12276 * @param oldt Previous vertical scroll origin. 12277 */ 12278 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 12279 notifySubtreeAccessibilityStateChangedIfNeeded(); 12280 12281 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 12282 postSendViewScrolledAccessibilityEventCallback(); 12283 } 12284 12285 mBackgroundSizeChanged = true; 12286 if (mForegroundInfo != null) { 12287 mForegroundInfo.mBoundsChanged = true; 12288 } 12289 12290 final AttachInfo ai = mAttachInfo; 12291 if (ai != null) { 12292 ai.mViewScrollChanged = true; 12293 } 12294 12295 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 12296 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 12297 } 12298 } 12299 12300 /** 12301 * Interface definition for a callback to be invoked when the scroll 12302 * X or Y positions of a view change. 12303 * <p> 12304 * <b>Note:</b> Some views handle scrolling independently from View and may 12305 * have their own separate listeners for scroll-type events. For example, 12306 * {@link android.widget.ListView ListView} allows clients to register an 12307 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 12308 * to listen for changes in list scroll position. 12309 * 12310 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 12311 */ 12312 public interface OnScrollChangeListener { 12313 /** 12314 * Called when the scroll position of a view changes. 12315 * 12316 * @param v The view whose scroll position has changed. 12317 * @param scrollX Current horizontal scroll origin. 12318 * @param scrollY Current vertical scroll origin. 12319 * @param oldScrollX Previous horizontal scroll origin. 12320 * @param oldScrollY Previous vertical scroll origin. 12321 */ 12322 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 12323 } 12324 12325 /** 12326 * Interface definition for a callback to be invoked when the layout bounds of a view 12327 * changes due to layout processing. 12328 */ 12329 public interface OnLayoutChangeListener { 12330 /** 12331 * Called when the layout bounds of a view changes due to layout processing. 12332 * 12333 * @param v The view whose bounds have changed. 12334 * @param left The new value of the view's left property. 12335 * @param top The new value of the view's top property. 12336 * @param right The new value of the view's right property. 12337 * @param bottom The new value of the view's bottom property. 12338 * @param oldLeft The previous value of the view's left property. 12339 * @param oldTop The previous value of the view's top property. 12340 * @param oldRight The previous value of the view's right property. 12341 * @param oldBottom The previous value of the view's bottom property. 12342 */ 12343 void onLayoutChange(View v, int left, int top, int right, int bottom, 12344 int oldLeft, int oldTop, int oldRight, int oldBottom); 12345 } 12346 12347 /** 12348 * This is called during layout when the size of this view has changed. If 12349 * you were just added to the view hierarchy, you're called with the old 12350 * values of 0. 12351 * 12352 * @param w Current width of this view. 12353 * @param h Current height of this view. 12354 * @param oldw Old width of this view. 12355 * @param oldh Old height of this view. 12356 */ 12357 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 12358 } 12359 12360 /** 12361 * Called by draw to draw the child views. This may be overridden 12362 * by derived classes to gain control just before its children are drawn 12363 * (but after its own view has been drawn). 12364 * @param canvas the canvas on which to draw the view 12365 */ 12366 protected void dispatchDraw(Canvas canvas) { 12367 12368 } 12369 12370 /** 12371 * Gets the parent of this view. Note that the parent is a 12372 * ViewParent and not necessarily a View. 12373 * 12374 * @return Parent of this view. 12375 */ 12376 public final ViewParent getParent() { 12377 return mParent; 12378 } 12379 12380 /** 12381 * Set the horizontal scrolled position of your view. This will cause a call to 12382 * {@link #onScrollChanged(int, int, int, int)} and the view will be 12383 * invalidated. 12384 * @param value the x position to scroll to 12385 */ 12386 public void setScrollX(int value) { 12387 scrollTo(value, mScrollY); 12388 } 12389 12390 /** 12391 * Set the vertical scrolled position of your view. This will cause a call to 12392 * {@link #onScrollChanged(int, int, int, int)} and the view will be 12393 * invalidated. 12394 * @param value the y position to scroll to 12395 */ 12396 public void setScrollY(int value) { 12397 scrollTo(mScrollX, value); 12398 } 12399 12400 /** 12401 * Return the scrolled left position of this view. This is the left edge of 12402 * the displayed part of your view. You do not need to draw any pixels 12403 * farther left, since those are outside of the frame of your view on 12404 * screen. 12405 * 12406 * @return The left edge of the displayed part of your view, in pixels. 12407 */ 12408 public final int getScrollX() { 12409 return mScrollX; 12410 } 12411 12412 /** 12413 * Return the scrolled top position of this view. This is the top edge of 12414 * the displayed part of your view. You do not need to draw any pixels above 12415 * it, since those are outside of the frame of your view on screen. 12416 * 12417 * @return The top edge of the displayed part of your view, in pixels. 12418 */ 12419 public final int getScrollY() { 12420 return mScrollY; 12421 } 12422 12423 /** 12424 * Return the width of the your view. 12425 * 12426 * @return The width of your view, in pixels. 12427 */ 12428 @ViewDebug.ExportedProperty(category = "layout") 12429 public final int getWidth() { 12430 return mRight - mLeft; 12431 } 12432 12433 /** 12434 * Return the height of your view. 12435 * 12436 * @return The height of your view, in pixels. 12437 */ 12438 @ViewDebug.ExportedProperty(category = "layout") 12439 public final int getHeight() { 12440 return mBottom - mTop; 12441 } 12442 12443 /** 12444 * Return the visible drawing bounds of your view. Fills in the output 12445 * rectangle with the values from getScrollX(), getScrollY(), 12446 * getWidth(), and getHeight(). These bounds do not account for any 12447 * transformation properties currently set on the view, such as 12448 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 12449 * 12450 * @param outRect The (scrolled) drawing bounds of the view. 12451 */ 12452 public void getDrawingRect(Rect outRect) { 12453 outRect.left = mScrollX; 12454 outRect.top = mScrollY; 12455 outRect.right = mScrollX + (mRight - mLeft); 12456 outRect.bottom = mScrollY + (mBottom - mTop); 12457 } 12458 12459 /** 12460 * Like {@link #getMeasuredWidthAndState()}, but only returns the 12461 * raw width component (that is the result is masked by 12462 * {@link #MEASURED_SIZE_MASK}). 12463 * 12464 * @return The raw measured width of this view. 12465 */ 12466 public final int getMeasuredWidth() { 12467 return mMeasuredWidth & MEASURED_SIZE_MASK; 12468 } 12469 12470 /** 12471 * Return the full width measurement information for this view as computed 12472 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 12473 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 12474 * This should be used during measurement and layout calculations only. Use 12475 * {@link #getWidth()} to see how wide a view is after layout. 12476 * 12477 * @return The measured width of this view as a bit mask. 12478 */ 12479 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 12480 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 12481 name = "MEASURED_STATE_TOO_SMALL"), 12482 }) 12483 public final int getMeasuredWidthAndState() { 12484 return mMeasuredWidth; 12485 } 12486 12487 /** 12488 * Like {@link #getMeasuredHeightAndState()}, but only returns the 12489 * raw height component (that is the result is masked by 12490 * {@link #MEASURED_SIZE_MASK}). 12491 * 12492 * @return The raw measured height of this view. 12493 */ 12494 public final int getMeasuredHeight() { 12495 return mMeasuredHeight & MEASURED_SIZE_MASK; 12496 } 12497 12498 /** 12499 * Return the full height measurement information for this view as computed 12500 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 12501 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 12502 * This should be used during measurement and layout calculations only. Use 12503 * {@link #getHeight()} to see how wide a view is after layout. 12504 * 12505 * @return The measured height of this view as a bit mask. 12506 */ 12507 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 12508 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 12509 name = "MEASURED_STATE_TOO_SMALL"), 12510 }) 12511 public final int getMeasuredHeightAndState() { 12512 return mMeasuredHeight; 12513 } 12514 12515 /** 12516 * Return only the state bits of {@link #getMeasuredWidthAndState()} 12517 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 12518 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 12519 * and the height component is at the shifted bits 12520 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 12521 */ 12522 public final int getMeasuredState() { 12523 return (mMeasuredWidth&MEASURED_STATE_MASK) 12524 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 12525 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 12526 } 12527 12528 /** 12529 * The transform matrix of this view, which is calculated based on the current 12530 * rotation, scale, and pivot properties. 12531 * 12532 * @see #getRotation() 12533 * @see #getScaleX() 12534 * @see #getScaleY() 12535 * @see #getPivotX() 12536 * @see #getPivotY() 12537 * @return The current transform matrix for the view 12538 */ 12539 public Matrix getMatrix() { 12540 ensureTransformationInfo(); 12541 final Matrix matrix = mTransformationInfo.mMatrix; 12542 mRenderNode.getMatrix(matrix); 12543 return matrix; 12544 } 12545 12546 /** 12547 * Returns true if the transform matrix is the identity matrix. 12548 * Recomputes the matrix if necessary. 12549 * 12550 * @return True if the transform matrix is the identity matrix, false otherwise. 12551 */ 12552 final boolean hasIdentityMatrix() { 12553 return mRenderNode.hasIdentityMatrix(); 12554 } 12555 12556 void ensureTransformationInfo() { 12557 if (mTransformationInfo == null) { 12558 mTransformationInfo = new TransformationInfo(); 12559 } 12560 } 12561 12562 /** 12563 * Utility method to retrieve the inverse of the current mMatrix property. 12564 * We cache the matrix to avoid recalculating it when transform properties 12565 * have not changed. 12566 * 12567 * @return The inverse of the current matrix of this view. 12568 * @hide 12569 */ 12570 public final Matrix getInverseMatrix() { 12571 ensureTransformationInfo(); 12572 if (mTransformationInfo.mInverseMatrix == null) { 12573 mTransformationInfo.mInverseMatrix = new Matrix(); 12574 } 12575 final Matrix matrix = mTransformationInfo.mInverseMatrix; 12576 mRenderNode.getInverseMatrix(matrix); 12577 return matrix; 12578 } 12579 12580 /** 12581 * Gets the distance along the Z axis from the camera to this view. 12582 * 12583 * @see #setCameraDistance(float) 12584 * 12585 * @return The distance along the Z axis. 12586 */ 12587 public float getCameraDistance() { 12588 final float dpi = mResources.getDisplayMetrics().densityDpi; 12589 return -(mRenderNode.getCameraDistance() * dpi); 12590 } 12591 12592 /** 12593 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 12594 * views are drawn) from the camera to this view. The camera's distance 12595 * affects 3D transformations, for instance rotations around the X and Y 12596 * axis. If the rotationX or rotationY properties are changed and this view is 12597 * large (more than half the size of the screen), it is recommended to always 12598 * use a camera distance that's greater than the height (X axis rotation) or 12599 * the width (Y axis rotation) of this view.</p> 12600 * 12601 * <p>The distance of the camera from the view plane can have an affect on the 12602 * perspective distortion of the view when it is rotated around the x or y axis. 12603 * For example, a large distance will result in a large viewing angle, and there 12604 * will not be much perspective distortion of the view as it rotates. A short 12605 * distance may cause much more perspective distortion upon rotation, and can 12606 * also result in some drawing artifacts if the rotated view ends up partially 12607 * behind the camera (which is why the recommendation is to use a distance at 12608 * least as far as the size of the view, if the view is to be rotated.)</p> 12609 * 12610 * <p>The distance is expressed in "depth pixels." The default distance depends 12611 * on the screen density. For instance, on a medium density display, the 12612 * default distance is 1280. On a high density display, the default distance 12613 * is 1920.</p> 12614 * 12615 * <p>If you want to specify a distance that leads to visually consistent 12616 * results across various densities, use the following formula:</p> 12617 * <pre> 12618 * float scale = context.getResources().getDisplayMetrics().density; 12619 * view.setCameraDistance(distance * scale); 12620 * </pre> 12621 * 12622 * <p>The density scale factor of a high density display is 1.5, 12623 * and 1920 = 1280 * 1.5.</p> 12624 * 12625 * @param distance The distance in "depth pixels", if negative the opposite 12626 * value is used 12627 * 12628 * @see #setRotationX(float) 12629 * @see #setRotationY(float) 12630 */ 12631 public void setCameraDistance(float distance) { 12632 final float dpi = mResources.getDisplayMetrics().densityDpi; 12633 12634 invalidateViewProperty(true, false); 12635 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 12636 invalidateViewProperty(false, false); 12637 12638 invalidateParentIfNeededAndWasQuickRejected(); 12639 } 12640 12641 /** 12642 * The degrees that the view is rotated around the pivot point. 12643 * 12644 * @see #setRotation(float) 12645 * @see #getPivotX() 12646 * @see #getPivotY() 12647 * 12648 * @return The degrees of rotation. 12649 */ 12650 @ViewDebug.ExportedProperty(category = "drawing") 12651 public float getRotation() { 12652 return mRenderNode.getRotation(); 12653 } 12654 12655 /** 12656 * Sets the degrees that the view is rotated around the pivot point. Increasing values 12657 * result in clockwise rotation. 12658 * 12659 * @param rotation The degrees of rotation. 12660 * 12661 * @see #getRotation() 12662 * @see #getPivotX() 12663 * @see #getPivotY() 12664 * @see #setRotationX(float) 12665 * @see #setRotationY(float) 12666 * 12667 * @attr ref android.R.styleable#View_rotation 12668 */ 12669 public void setRotation(float rotation) { 12670 if (rotation != getRotation()) { 12671 // Double-invalidation is necessary to capture view's old and new areas 12672 invalidateViewProperty(true, false); 12673 mRenderNode.setRotation(rotation); 12674 invalidateViewProperty(false, true); 12675 12676 invalidateParentIfNeededAndWasQuickRejected(); 12677 notifySubtreeAccessibilityStateChangedIfNeeded(); 12678 } 12679 } 12680 12681 /** 12682 * The degrees that the view is rotated around the vertical axis through the pivot point. 12683 * 12684 * @see #getPivotX() 12685 * @see #getPivotY() 12686 * @see #setRotationY(float) 12687 * 12688 * @return The degrees of Y rotation. 12689 */ 12690 @ViewDebug.ExportedProperty(category = "drawing") 12691 public float getRotationY() { 12692 return mRenderNode.getRotationY(); 12693 } 12694 12695 /** 12696 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 12697 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 12698 * down the y axis. 12699 * 12700 * When rotating large views, it is recommended to adjust the camera distance 12701 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12702 * 12703 * @param rotationY The degrees of Y rotation. 12704 * 12705 * @see #getRotationY() 12706 * @see #getPivotX() 12707 * @see #getPivotY() 12708 * @see #setRotation(float) 12709 * @see #setRotationX(float) 12710 * @see #setCameraDistance(float) 12711 * 12712 * @attr ref android.R.styleable#View_rotationY 12713 */ 12714 public void setRotationY(float rotationY) { 12715 if (rotationY != getRotationY()) { 12716 invalidateViewProperty(true, false); 12717 mRenderNode.setRotationY(rotationY); 12718 invalidateViewProperty(false, true); 12719 12720 invalidateParentIfNeededAndWasQuickRejected(); 12721 notifySubtreeAccessibilityStateChangedIfNeeded(); 12722 } 12723 } 12724 12725 /** 12726 * The degrees that the view is rotated around the horizontal axis through the pivot point. 12727 * 12728 * @see #getPivotX() 12729 * @see #getPivotY() 12730 * @see #setRotationX(float) 12731 * 12732 * @return The degrees of X rotation. 12733 */ 12734 @ViewDebug.ExportedProperty(category = "drawing") 12735 public float getRotationX() { 12736 return mRenderNode.getRotationX(); 12737 } 12738 12739 /** 12740 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 12741 * Increasing values result in clockwise rotation from the viewpoint of looking down the 12742 * x axis. 12743 * 12744 * When rotating large views, it is recommended to adjust the camera distance 12745 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12746 * 12747 * @param rotationX The degrees of X rotation. 12748 * 12749 * @see #getRotationX() 12750 * @see #getPivotX() 12751 * @see #getPivotY() 12752 * @see #setRotation(float) 12753 * @see #setRotationY(float) 12754 * @see #setCameraDistance(float) 12755 * 12756 * @attr ref android.R.styleable#View_rotationX 12757 */ 12758 public void setRotationX(float rotationX) { 12759 if (rotationX != getRotationX()) { 12760 invalidateViewProperty(true, false); 12761 mRenderNode.setRotationX(rotationX); 12762 invalidateViewProperty(false, true); 12763 12764 invalidateParentIfNeededAndWasQuickRejected(); 12765 notifySubtreeAccessibilityStateChangedIfNeeded(); 12766 } 12767 } 12768 12769 /** 12770 * The amount that the view is scaled in x around the pivot point, as a proportion of 12771 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 12772 * 12773 * <p>By default, this is 1.0f. 12774 * 12775 * @see #getPivotX() 12776 * @see #getPivotY() 12777 * @return The scaling factor. 12778 */ 12779 @ViewDebug.ExportedProperty(category = "drawing") 12780 public float getScaleX() { 12781 return mRenderNode.getScaleX(); 12782 } 12783 12784 /** 12785 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 12786 * the view's unscaled width. A value of 1 means that no scaling is applied. 12787 * 12788 * @param scaleX The scaling factor. 12789 * @see #getPivotX() 12790 * @see #getPivotY() 12791 * 12792 * @attr ref android.R.styleable#View_scaleX 12793 */ 12794 public void setScaleX(float scaleX) { 12795 if (scaleX != getScaleX()) { 12796 invalidateViewProperty(true, false); 12797 mRenderNode.setScaleX(scaleX); 12798 invalidateViewProperty(false, true); 12799 12800 invalidateParentIfNeededAndWasQuickRejected(); 12801 notifySubtreeAccessibilityStateChangedIfNeeded(); 12802 } 12803 } 12804 12805 /** 12806 * The amount that the view is scaled in y around the pivot point, as a proportion of 12807 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 12808 * 12809 * <p>By default, this is 1.0f. 12810 * 12811 * @see #getPivotX() 12812 * @see #getPivotY() 12813 * @return The scaling factor. 12814 */ 12815 @ViewDebug.ExportedProperty(category = "drawing") 12816 public float getScaleY() { 12817 return mRenderNode.getScaleY(); 12818 } 12819 12820 /** 12821 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 12822 * the view's unscaled width. A value of 1 means that no scaling is applied. 12823 * 12824 * @param scaleY The scaling factor. 12825 * @see #getPivotX() 12826 * @see #getPivotY() 12827 * 12828 * @attr ref android.R.styleable#View_scaleY 12829 */ 12830 public void setScaleY(float scaleY) { 12831 if (scaleY != getScaleY()) { 12832 invalidateViewProperty(true, false); 12833 mRenderNode.setScaleY(scaleY); 12834 invalidateViewProperty(false, true); 12835 12836 invalidateParentIfNeededAndWasQuickRejected(); 12837 notifySubtreeAccessibilityStateChangedIfNeeded(); 12838 } 12839 } 12840 12841 /** 12842 * The x location of the point around which the view is {@link #setRotation(float) rotated} 12843 * and {@link #setScaleX(float) scaled}. 12844 * 12845 * @see #getRotation() 12846 * @see #getScaleX() 12847 * @see #getScaleY() 12848 * @see #getPivotY() 12849 * @return The x location of the pivot point. 12850 * 12851 * @attr ref android.R.styleable#View_transformPivotX 12852 */ 12853 @ViewDebug.ExportedProperty(category = "drawing") 12854 public float getPivotX() { 12855 return mRenderNode.getPivotX(); 12856 } 12857 12858 /** 12859 * Sets the x location of the point around which the view is 12860 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 12861 * By default, the pivot point is centered on the object. 12862 * Setting this property disables this behavior and causes the view to use only the 12863 * explicitly set pivotX and pivotY values. 12864 * 12865 * @param pivotX The x location of the pivot point. 12866 * @see #getRotation() 12867 * @see #getScaleX() 12868 * @see #getScaleY() 12869 * @see #getPivotY() 12870 * 12871 * @attr ref android.R.styleable#View_transformPivotX 12872 */ 12873 public void setPivotX(float pivotX) { 12874 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 12875 invalidateViewProperty(true, false); 12876 mRenderNode.setPivotX(pivotX); 12877 invalidateViewProperty(false, true); 12878 12879 invalidateParentIfNeededAndWasQuickRejected(); 12880 } 12881 } 12882 12883 /** 12884 * The y location of the point around which the view is {@link #setRotation(float) rotated} 12885 * and {@link #setScaleY(float) scaled}. 12886 * 12887 * @see #getRotation() 12888 * @see #getScaleX() 12889 * @see #getScaleY() 12890 * @see #getPivotY() 12891 * @return The y location of the pivot point. 12892 * 12893 * @attr ref android.R.styleable#View_transformPivotY 12894 */ 12895 @ViewDebug.ExportedProperty(category = "drawing") 12896 public float getPivotY() { 12897 return mRenderNode.getPivotY(); 12898 } 12899 12900 /** 12901 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 12902 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 12903 * Setting this property disables this behavior and causes the view to use only the 12904 * explicitly set pivotX and pivotY values. 12905 * 12906 * @param pivotY The y location of the pivot point. 12907 * @see #getRotation() 12908 * @see #getScaleX() 12909 * @see #getScaleY() 12910 * @see #getPivotY() 12911 * 12912 * @attr ref android.R.styleable#View_transformPivotY 12913 */ 12914 public void setPivotY(float pivotY) { 12915 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 12916 invalidateViewProperty(true, false); 12917 mRenderNode.setPivotY(pivotY); 12918 invalidateViewProperty(false, true); 12919 12920 invalidateParentIfNeededAndWasQuickRejected(); 12921 } 12922 } 12923 12924 /** 12925 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 12926 * completely transparent and 1 means the view is completely opaque. 12927 * 12928 * <p>By default this is 1.0f. 12929 * @return The opacity of the view. 12930 */ 12931 @ViewDebug.ExportedProperty(category = "drawing") 12932 public float getAlpha() { 12933 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 12934 } 12935 12936 /** 12937 * Sets the behavior for overlapping rendering for this view (see {@link 12938 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 12939 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 12940 * providing the value which is then used internally. That is, when {@link 12941 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 12942 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 12943 * instead. 12944 * 12945 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 12946 * instead of that returned by {@link #hasOverlappingRendering()}. 12947 * 12948 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 12949 */ 12950 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 12951 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 12952 if (hasOverlappingRendering) { 12953 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 12954 } else { 12955 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 12956 } 12957 } 12958 12959 /** 12960 * Returns the value for overlapping rendering that is used internally. This is either 12961 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 12962 * the return value of {@link #hasOverlappingRendering()}, otherwise. 12963 * 12964 * @return The value for overlapping rendering being used internally. 12965 */ 12966 public final boolean getHasOverlappingRendering() { 12967 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 12968 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 12969 hasOverlappingRendering(); 12970 } 12971 12972 /** 12973 * Returns whether this View has content which overlaps. 12974 * 12975 * <p>This function, intended to be overridden by specific View types, is an optimization when 12976 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 12977 * an offscreen buffer and then composited into place, which can be expensive. If the view has 12978 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 12979 * directly. An example of overlapping rendering is a TextView with a background image, such as 12980 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 12981 * ImageView with only the foreground image. The default implementation returns true; subclasses 12982 * should override if they have cases which can be optimized.</p> 12983 * 12984 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 12985 * necessitates that a View return true if it uses the methods internally without passing the 12986 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 12987 * 12988 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 12989 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 12990 * 12991 * @return true if the content in this view might overlap, false otherwise. 12992 */ 12993 @ViewDebug.ExportedProperty(category = "drawing") 12994 public boolean hasOverlappingRendering() { 12995 return true; 12996 } 12997 12998 /** 12999 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 13000 * completely transparent and 1 means the view is completely opaque. 13001 * 13002 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 13003 * can have significant performance implications, especially for large views. It is best to use 13004 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 13005 * 13006 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 13007 * strongly recommended for performance reasons to either override 13008 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 13009 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 13010 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 13011 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 13012 * of rendering cost, even for simple or small views. Starting with 13013 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 13014 * applied to the view at the rendering level.</p> 13015 * 13016 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 13017 * responsible for applying the opacity itself.</p> 13018 * 13019 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 13020 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 13021 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 13022 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 13023 * 13024 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 13025 * value will clip a View to its bounds, unless the View returns <code>false</code> from 13026 * {@link #hasOverlappingRendering}.</p> 13027 * 13028 * @param alpha The opacity of the view. 13029 * 13030 * @see #hasOverlappingRendering() 13031 * @see #setLayerType(int, android.graphics.Paint) 13032 * 13033 * @attr ref android.R.styleable#View_alpha 13034 */ 13035 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 13036 ensureTransformationInfo(); 13037 if (mTransformationInfo.mAlpha != alpha) { 13038 // Report visibility changes, which can affect children, to accessibility 13039 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 13040 notifySubtreeAccessibilityStateChangedIfNeeded(); 13041 } 13042 mTransformationInfo.mAlpha = alpha; 13043 if (onSetAlpha((int) (alpha * 255))) { 13044 mPrivateFlags |= PFLAG_ALPHA_SET; 13045 // subclass is handling alpha - don't optimize rendering cache invalidation 13046 invalidateParentCaches(); 13047 invalidate(true); 13048 } else { 13049 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13050 invalidateViewProperty(true, false); 13051 mRenderNode.setAlpha(getFinalAlpha()); 13052 } 13053 } 13054 } 13055 13056 /** 13057 * Faster version of setAlpha() which performs the same steps except there are 13058 * no calls to invalidate(). The caller of this function should perform proper invalidation 13059 * on the parent and this object. The return value indicates whether the subclass handles 13060 * alpha (the return value for onSetAlpha()). 13061 * 13062 * @param alpha The new value for the alpha property 13063 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 13064 * the new value for the alpha property is different from the old value 13065 */ 13066 boolean setAlphaNoInvalidation(float alpha) { 13067 ensureTransformationInfo(); 13068 if (mTransformationInfo.mAlpha != alpha) { 13069 mTransformationInfo.mAlpha = alpha; 13070 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 13071 if (subclassHandlesAlpha) { 13072 mPrivateFlags |= PFLAG_ALPHA_SET; 13073 return true; 13074 } else { 13075 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13076 mRenderNode.setAlpha(getFinalAlpha()); 13077 } 13078 } 13079 return false; 13080 } 13081 13082 /** 13083 * This property is hidden and intended only for use by the Fade transition, which 13084 * animates it to produce a visual translucency that does not side-effect (or get 13085 * affected by) the real alpha property. This value is composited with the other 13086 * alpha value (and the AlphaAnimation value, when that is present) to produce 13087 * a final visual translucency result, which is what is passed into the DisplayList. 13088 * 13089 * @hide 13090 */ 13091 public void setTransitionAlpha(float alpha) { 13092 ensureTransformationInfo(); 13093 if (mTransformationInfo.mTransitionAlpha != alpha) { 13094 mTransformationInfo.mTransitionAlpha = alpha; 13095 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13096 invalidateViewProperty(true, false); 13097 mRenderNode.setAlpha(getFinalAlpha()); 13098 } 13099 } 13100 13101 /** 13102 * Calculates the visual alpha of this view, which is a combination of the actual 13103 * alpha value and the transitionAlpha value (if set). 13104 */ 13105 private float getFinalAlpha() { 13106 if (mTransformationInfo != null) { 13107 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 13108 } 13109 return 1; 13110 } 13111 13112 /** 13113 * This property is hidden and intended only for use by the Fade transition, which 13114 * animates it to produce a visual translucency that does not side-effect (or get 13115 * affected by) the real alpha property. This value is composited with the other 13116 * alpha value (and the AlphaAnimation value, when that is present) to produce 13117 * a final visual translucency result, which is what is passed into the DisplayList. 13118 * 13119 * @hide 13120 */ 13121 @ViewDebug.ExportedProperty(category = "drawing") 13122 public float getTransitionAlpha() { 13123 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 13124 } 13125 13126 /** 13127 * Top position of this view relative to its parent. 13128 * 13129 * @return The top of this view, in pixels. 13130 */ 13131 @ViewDebug.CapturedViewProperty 13132 public final int getTop() { 13133 return mTop; 13134 } 13135 13136 /** 13137 * Sets the top position of this view relative to its parent. This method is meant to be called 13138 * by the layout system and should not generally be called otherwise, because the property 13139 * may be changed at any time by the layout. 13140 * 13141 * @param top The top of this view, in pixels. 13142 */ 13143 public final void setTop(int top) { 13144 if (top != mTop) { 13145 final boolean matrixIsIdentity = hasIdentityMatrix(); 13146 if (matrixIsIdentity) { 13147 if (mAttachInfo != null) { 13148 int minTop; 13149 int yLoc; 13150 if (top < mTop) { 13151 minTop = top; 13152 yLoc = top - mTop; 13153 } else { 13154 minTop = mTop; 13155 yLoc = 0; 13156 } 13157 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 13158 } 13159 } else { 13160 // Double-invalidation is necessary to capture view's old and new areas 13161 invalidate(true); 13162 } 13163 13164 int width = mRight - mLeft; 13165 int oldHeight = mBottom - mTop; 13166 13167 mTop = top; 13168 mRenderNode.setTop(mTop); 13169 13170 sizeChange(width, mBottom - mTop, width, oldHeight); 13171 13172 if (!matrixIsIdentity) { 13173 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13174 invalidate(true); 13175 } 13176 mBackgroundSizeChanged = true; 13177 if (mForegroundInfo != null) { 13178 mForegroundInfo.mBoundsChanged = true; 13179 } 13180 invalidateParentIfNeeded(); 13181 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13182 // View was rejected last time it was drawn by its parent; this may have changed 13183 invalidateParentIfNeeded(); 13184 } 13185 } 13186 } 13187 13188 /** 13189 * Bottom position of this view relative to its parent. 13190 * 13191 * @return The bottom of this view, in pixels. 13192 */ 13193 @ViewDebug.CapturedViewProperty 13194 public final int getBottom() { 13195 return mBottom; 13196 } 13197 13198 /** 13199 * True if this view has changed since the last time being drawn. 13200 * 13201 * @return The dirty state of this view. 13202 */ 13203 public boolean isDirty() { 13204 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 13205 } 13206 13207 /** 13208 * Sets the bottom position of this view relative to its parent. This method is meant to be 13209 * called by the layout system and should not generally be called otherwise, because the 13210 * property may be changed at any time by the layout. 13211 * 13212 * @param bottom The bottom of this view, in pixels. 13213 */ 13214 public final void setBottom(int bottom) { 13215 if (bottom != mBottom) { 13216 final boolean matrixIsIdentity = hasIdentityMatrix(); 13217 if (matrixIsIdentity) { 13218 if (mAttachInfo != null) { 13219 int maxBottom; 13220 if (bottom < mBottom) { 13221 maxBottom = mBottom; 13222 } else { 13223 maxBottom = bottom; 13224 } 13225 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 13226 } 13227 } else { 13228 // Double-invalidation is necessary to capture view's old and new areas 13229 invalidate(true); 13230 } 13231 13232 int width = mRight - mLeft; 13233 int oldHeight = mBottom - mTop; 13234 13235 mBottom = bottom; 13236 mRenderNode.setBottom(mBottom); 13237 13238 sizeChange(width, mBottom - mTop, width, oldHeight); 13239 13240 if (!matrixIsIdentity) { 13241 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13242 invalidate(true); 13243 } 13244 mBackgroundSizeChanged = true; 13245 if (mForegroundInfo != null) { 13246 mForegroundInfo.mBoundsChanged = true; 13247 } 13248 invalidateParentIfNeeded(); 13249 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13250 // View was rejected last time it was drawn by its parent; this may have changed 13251 invalidateParentIfNeeded(); 13252 } 13253 } 13254 } 13255 13256 /** 13257 * Left position of this view relative to its parent. 13258 * 13259 * @return The left edge of this view, in pixels. 13260 */ 13261 @ViewDebug.CapturedViewProperty 13262 public final int getLeft() { 13263 return mLeft; 13264 } 13265 13266 /** 13267 * Sets the left position of this view relative to its parent. This method is meant to be called 13268 * by the layout system and should not generally be called otherwise, because the property 13269 * may be changed at any time by the layout. 13270 * 13271 * @param left The left of this view, in pixels. 13272 */ 13273 public final void setLeft(int left) { 13274 if (left != mLeft) { 13275 final boolean matrixIsIdentity = hasIdentityMatrix(); 13276 if (matrixIsIdentity) { 13277 if (mAttachInfo != null) { 13278 int minLeft; 13279 int xLoc; 13280 if (left < mLeft) { 13281 minLeft = left; 13282 xLoc = left - mLeft; 13283 } else { 13284 minLeft = mLeft; 13285 xLoc = 0; 13286 } 13287 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 13288 } 13289 } else { 13290 // Double-invalidation is necessary to capture view's old and new areas 13291 invalidate(true); 13292 } 13293 13294 int oldWidth = mRight - mLeft; 13295 int height = mBottom - mTop; 13296 13297 mLeft = left; 13298 mRenderNode.setLeft(left); 13299 13300 sizeChange(mRight - mLeft, height, oldWidth, height); 13301 13302 if (!matrixIsIdentity) { 13303 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13304 invalidate(true); 13305 } 13306 mBackgroundSizeChanged = true; 13307 if (mForegroundInfo != null) { 13308 mForegroundInfo.mBoundsChanged = true; 13309 } 13310 invalidateParentIfNeeded(); 13311 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13312 // View was rejected last time it was drawn by its parent; this may have changed 13313 invalidateParentIfNeeded(); 13314 } 13315 } 13316 } 13317 13318 /** 13319 * Right position of this view relative to its parent. 13320 * 13321 * @return The right edge of this view, in pixels. 13322 */ 13323 @ViewDebug.CapturedViewProperty 13324 public final int getRight() { 13325 return mRight; 13326 } 13327 13328 /** 13329 * Sets the right position of this view relative to its parent. This method is meant to be called 13330 * by the layout system and should not generally be called otherwise, because the property 13331 * may be changed at any time by the layout. 13332 * 13333 * @param right The right of this view, in pixels. 13334 */ 13335 public final void setRight(int right) { 13336 if (right != mRight) { 13337 final boolean matrixIsIdentity = hasIdentityMatrix(); 13338 if (matrixIsIdentity) { 13339 if (mAttachInfo != null) { 13340 int maxRight; 13341 if (right < mRight) { 13342 maxRight = mRight; 13343 } else { 13344 maxRight = right; 13345 } 13346 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 13347 } 13348 } else { 13349 // Double-invalidation is necessary to capture view's old and new areas 13350 invalidate(true); 13351 } 13352 13353 int oldWidth = mRight - mLeft; 13354 int height = mBottom - mTop; 13355 13356 mRight = right; 13357 mRenderNode.setRight(mRight); 13358 13359 sizeChange(mRight - mLeft, height, oldWidth, height); 13360 13361 if (!matrixIsIdentity) { 13362 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13363 invalidate(true); 13364 } 13365 mBackgroundSizeChanged = true; 13366 if (mForegroundInfo != null) { 13367 mForegroundInfo.mBoundsChanged = true; 13368 } 13369 invalidateParentIfNeeded(); 13370 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13371 // View was rejected last time it was drawn by its parent; this may have changed 13372 invalidateParentIfNeeded(); 13373 } 13374 } 13375 } 13376 13377 /** 13378 * The visual x position of this view, in pixels. This is equivalent to the 13379 * {@link #setTranslationX(float) translationX} property plus the current 13380 * {@link #getLeft() left} property. 13381 * 13382 * @return The visual x position of this view, in pixels. 13383 */ 13384 @ViewDebug.ExportedProperty(category = "drawing") 13385 public float getX() { 13386 return mLeft + getTranslationX(); 13387 } 13388 13389 /** 13390 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 13391 * {@link #setTranslationX(float) translationX} property to be the difference between 13392 * the x value passed in and the current {@link #getLeft() left} property. 13393 * 13394 * @param x The visual x position of this view, in pixels. 13395 */ 13396 public void setX(float x) { 13397 setTranslationX(x - mLeft); 13398 } 13399 13400 /** 13401 * The visual y position of this view, in pixels. This is equivalent to the 13402 * {@link #setTranslationY(float) translationY} property plus the current 13403 * {@link #getTop() top} property. 13404 * 13405 * @return The visual y position of this view, in pixels. 13406 */ 13407 @ViewDebug.ExportedProperty(category = "drawing") 13408 public float getY() { 13409 return mTop + getTranslationY(); 13410 } 13411 13412 /** 13413 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 13414 * {@link #setTranslationY(float) translationY} property to be the difference between 13415 * the y value passed in and the current {@link #getTop() top} property. 13416 * 13417 * @param y The visual y position of this view, in pixels. 13418 */ 13419 public void setY(float y) { 13420 setTranslationY(y - mTop); 13421 } 13422 13423 /** 13424 * The visual z position of this view, in pixels. This is equivalent to the 13425 * {@link #setTranslationZ(float) translationZ} property plus the current 13426 * {@link #getElevation() elevation} property. 13427 * 13428 * @return The visual z position of this view, in pixels. 13429 */ 13430 @ViewDebug.ExportedProperty(category = "drawing") 13431 public float getZ() { 13432 return getElevation() + getTranslationZ(); 13433 } 13434 13435 /** 13436 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 13437 * {@link #setTranslationZ(float) translationZ} property to be the difference between 13438 * the x value passed in and the current {@link #getElevation() elevation} property. 13439 * 13440 * @param z The visual z position of this view, in pixels. 13441 */ 13442 public void setZ(float z) { 13443 setTranslationZ(z - getElevation()); 13444 } 13445 13446 /** 13447 * The base elevation of this view relative to its parent, in pixels. 13448 * 13449 * @return The base depth position of the view, in pixels. 13450 */ 13451 @ViewDebug.ExportedProperty(category = "drawing") 13452 public float getElevation() { 13453 return mRenderNode.getElevation(); 13454 } 13455 13456 /** 13457 * Sets the base elevation of this view, in pixels. 13458 * 13459 * @attr ref android.R.styleable#View_elevation 13460 */ 13461 public void setElevation(float elevation) { 13462 if (elevation != getElevation()) { 13463 invalidateViewProperty(true, false); 13464 mRenderNode.setElevation(elevation); 13465 invalidateViewProperty(false, true); 13466 13467 invalidateParentIfNeededAndWasQuickRejected(); 13468 } 13469 } 13470 13471 /** 13472 * The horizontal location of this view relative to its {@link #getLeft() left} position. 13473 * This position is post-layout, in addition to wherever the object's 13474 * layout placed it. 13475 * 13476 * @return The horizontal position of this view relative to its left position, in pixels. 13477 */ 13478 @ViewDebug.ExportedProperty(category = "drawing") 13479 public float getTranslationX() { 13480 return mRenderNode.getTranslationX(); 13481 } 13482 13483 /** 13484 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 13485 * This effectively positions the object post-layout, in addition to wherever the object's 13486 * layout placed it. 13487 * 13488 * @param translationX The horizontal position of this view relative to its left position, 13489 * in pixels. 13490 * 13491 * @attr ref android.R.styleable#View_translationX 13492 */ 13493 public void setTranslationX(float translationX) { 13494 if (translationX != getTranslationX()) { 13495 invalidateViewProperty(true, false); 13496 mRenderNode.setTranslationX(translationX); 13497 invalidateViewProperty(false, true); 13498 13499 invalidateParentIfNeededAndWasQuickRejected(); 13500 notifySubtreeAccessibilityStateChangedIfNeeded(); 13501 } 13502 } 13503 13504 /** 13505 * The vertical location of this view relative to its {@link #getTop() top} position. 13506 * This position is post-layout, in addition to wherever the object's 13507 * layout placed it. 13508 * 13509 * @return The vertical position of this view relative to its top position, 13510 * in pixels. 13511 */ 13512 @ViewDebug.ExportedProperty(category = "drawing") 13513 public float getTranslationY() { 13514 return mRenderNode.getTranslationY(); 13515 } 13516 13517 /** 13518 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 13519 * This effectively positions the object post-layout, in addition to wherever the object's 13520 * layout placed it. 13521 * 13522 * @param translationY The vertical position of this view relative to its top position, 13523 * in pixels. 13524 * 13525 * @attr ref android.R.styleable#View_translationY 13526 */ 13527 public void setTranslationY(float translationY) { 13528 if (translationY != getTranslationY()) { 13529 invalidateViewProperty(true, false); 13530 mRenderNode.setTranslationY(translationY); 13531 invalidateViewProperty(false, true); 13532 13533 invalidateParentIfNeededAndWasQuickRejected(); 13534 notifySubtreeAccessibilityStateChangedIfNeeded(); 13535 } 13536 } 13537 13538 /** 13539 * The depth location of this view relative to its {@link #getElevation() elevation}. 13540 * 13541 * @return The depth of this view relative to its elevation. 13542 */ 13543 @ViewDebug.ExportedProperty(category = "drawing") 13544 public float getTranslationZ() { 13545 return mRenderNode.getTranslationZ(); 13546 } 13547 13548 /** 13549 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 13550 * 13551 * @attr ref android.R.styleable#View_translationZ 13552 */ 13553 public void setTranslationZ(float translationZ) { 13554 if (translationZ != getTranslationZ()) { 13555 invalidateViewProperty(true, false); 13556 mRenderNode.setTranslationZ(translationZ); 13557 invalidateViewProperty(false, true); 13558 13559 invalidateParentIfNeededAndWasQuickRejected(); 13560 } 13561 } 13562 13563 /** @hide */ 13564 public void setAnimationMatrix(Matrix matrix) { 13565 invalidateViewProperty(true, false); 13566 mRenderNode.setAnimationMatrix(matrix); 13567 invalidateViewProperty(false, true); 13568 13569 invalidateParentIfNeededAndWasQuickRejected(); 13570 } 13571 13572 /** 13573 * Returns the current StateListAnimator if exists. 13574 * 13575 * @return StateListAnimator or null if it does not exists 13576 * @see #setStateListAnimator(android.animation.StateListAnimator) 13577 */ 13578 public StateListAnimator getStateListAnimator() { 13579 return mStateListAnimator; 13580 } 13581 13582 /** 13583 * Attaches the provided StateListAnimator to this View. 13584 * <p> 13585 * Any previously attached StateListAnimator will be detached. 13586 * 13587 * @param stateListAnimator The StateListAnimator to update the view 13588 * @see {@link android.animation.StateListAnimator} 13589 */ 13590 public void setStateListAnimator(StateListAnimator stateListAnimator) { 13591 if (mStateListAnimator == stateListAnimator) { 13592 return; 13593 } 13594 if (mStateListAnimator != null) { 13595 mStateListAnimator.setTarget(null); 13596 } 13597 mStateListAnimator = stateListAnimator; 13598 if (stateListAnimator != null) { 13599 stateListAnimator.setTarget(this); 13600 if (isAttachedToWindow()) { 13601 stateListAnimator.setState(getDrawableState()); 13602 } 13603 } 13604 } 13605 13606 /** 13607 * Returns whether the Outline should be used to clip the contents of the View. 13608 * <p> 13609 * Note that this flag will only be respected if the View's Outline returns true from 13610 * {@link Outline#canClip()}. 13611 * 13612 * @see #setOutlineProvider(ViewOutlineProvider) 13613 * @see #setClipToOutline(boolean) 13614 */ 13615 public final boolean getClipToOutline() { 13616 return mRenderNode.getClipToOutline(); 13617 } 13618 13619 /** 13620 * Sets whether the View's Outline should be used to clip the contents of the View. 13621 * <p> 13622 * Only a single non-rectangular clip can be applied on a View at any time. 13623 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 13624 * circular reveal} animation take priority over Outline clipping, and 13625 * child Outline clipping takes priority over Outline clipping done by a 13626 * parent. 13627 * <p> 13628 * Note that this flag will only be respected if the View's Outline returns true from 13629 * {@link Outline#canClip()}. 13630 * 13631 * @see #setOutlineProvider(ViewOutlineProvider) 13632 * @see #getClipToOutline() 13633 */ 13634 public void setClipToOutline(boolean clipToOutline) { 13635 damageInParent(); 13636 if (getClipToOutline() != clipToOutline) { 13637 mRenderNode.setClipToOutline(clipToOutline); 13638 } 13639 } 13640 13641 // correspond to the enum values of View_outlineProvider 13642 private static final int PROVIDER_BACKGROUND = 0; 13643 private static final int PROVIDER_NONE = 1; 13644 private static final int PROVIDER_BOUNDS = 2; 13645 private static final int PROVIDER_PADDED_BOUNDS = 3; 13646 private void setOutlineProviderFromAttribute(int providerInt) { 13647 switch (providerInt) { 13648 case PROVIDER_BACKGROUND: 13649 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 13650 break; 13651 case PROVIDER_NONE: 13652 setOutlineProvider(null); 13653 break; 13654 case PROVIDER_BOUNDS: 13655 setOutlineProvider(ViewOutlineProvider.BOUNDS); 13656 break; 13657 case PROVIDER_PADDED_BOUNDS: 13658 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 13659 break; 13660 } 13661 } 13662 13663 /** 13664 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 13665 * the shape of the shadow it casts, and enables outline clipping. 13666 * <p> 13667 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 13668 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 13669 * outline provider with this method allows this behavior to be overridden. 13670 * <p> 13671 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 13672 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 13673 * <p> 13674 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 13675 * 13676 * @see #setClipToOutline(boolean) 13677 * @see #getClipToOutline() 13678 * @see #getOutlineProvider() 13679 */ 13680 public void setOutlineProvider(ViewOutlineProvider provider) { 13681 mOutlineProvider = provider; 13682 invalidateOutline(); 13683 } 13684 13685 /** 13686 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 13687 * that defines the shape of the shadow it casts, and enables outline clipping. 13688 * 13689 * @see #setOutlineProvider(ViewOutlineProvider) 13690 */ 13691 public ViewOutlineProvider getOutlineProvider() { 13692 return mOutlineProvider; 13693 } 13694 13695 /** 13696 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 13697 * 13698 * @see #setOutlineProvider(ViewOutlineProvider) 13699 */ 13700 public void invalidateOutline() { 13701 rebuildOutline(); 13702 13703 notifySubtreeAccessibilityStateChangedIfNeeded(); 13704 invalidateViewProperty(false, false); 13705 } 13706 13707 /** 13708 * Internal version of {@link #invalidateOutline()} which invalidates the 13709 * outline without invalidating the view itself. This is intended to be called from 13710 * within methods in the View class itself which are the result of the view being 13711 * invalidated already. For example, when we are drawing the background of a View, 13712 * we invalidate the outline in case it changed in the meantime, but we do not 13713 * need to invalidate the view because we're already drawing the background as part 13714 * of drawing the view in response to an earlier invalidation of the view. 13715 */ 13716 private void rebuildOutline() { 13717 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 13718 if (mAttachInfo == null) return; 13719 13720 if (mOutlineProvider == null) { 13721 // no provider, remove outline 13722 mRenderNode.setOutline(null); 13723 } else { 13724 final Outline outline = mAttachInfo.mTmpOutline; 13725 outline.setEmpty(); 13726 outline.setAlpha(1.0f); 13727 13728 mOutlineProvider.getOutline(this, outline); 13729 mRenderNode.setOutline(outline); 13730 } 13731 } 13732 13733 /** 13734 * HierarchyViewer only 13735 * 13736 * @hide 13737 */ 13738 @ViewDebug.ExportedProperty(category = "drawing") 13739 public boolean hasShadow() { 13740 return mRenderNode.hasShadow(); 13741 } 13742 13743 13744 /** @hide */ 13745 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 13746 mRenderNode.setRevealClip(shouldClip, x, y, radius); 13747 invalidateViewProperty(false, false); 13748 } 13749 13750 /** 13751 * Hit rectangle in parent's coordinates 13752 * 13753 * @param outRect The hit rectangle of the view. 13754 */ 13755 public void getHitRect(Rect outRect) { 13756 if (hasIdentityMatrix() || mAttachInfo == null) { 13757 outRect.set(mLeft, mTop, mRight, mBottom); 13758 } else { 13759 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 13760 tmpRect.set(0, 0, getWidth(), getHeight()); 13761 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 13762 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 13763 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 13764 } 13765 } 13766 13767 /** 13768 * Determines whether the given point, in local coordinates is inside the view. 13769 */ 13770 /*package*/ final boolean pointInView(float localX, float localY) { 13771 return pointInView(localX, localY, 0); 13772 } 13773 13774 /** 13775 * Utility method to determine whether the given point, in local coordinates, 13776 * is inside the view, where the area of the view is expanded by the slop factor. 13777 * This method is called while processing touch-move events to determine if the event 13778 * is still within the view. 13779 * 13780 * @hide 13781 */ 13782 public boolean pointInView(float localX, float localY, float slop) { 13783 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 13784 localY < ((mBottom - mTop) + slop); 13785 } 13786 13787 /** 13788 * When a view has focus and the user navigates away from it, the next view is searched for 13789 * starting from the rectangle filled in by this method. 13790 * 13791 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 13792 * of the view. However, if your view maintains some idea of internal selection, 13793 * such as a cursor, or a selected row or column, you should override this method and 13794 * fill in a more specific rectangle. 13795 * 13796 * @param r The rectangle to fill in, in this view's coordinates. 13797 */ 13798 public void getFocusedRect(Rect r) { 13799 getDrawingRect(r); 13800 } 13801 13802 /** 13803 * If some part of this view is not clipped by any of its parents, then 13804 * return that area in r in global (root) coordinates. To convert r to local 13805 * coordinates (without taking possible View rotations into account), offset 13806 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 13807 * If the view is completely clipped or translated out, return false. 13808 * 13809 * @param r If true is returned, r holds the global coordinates of the 13810 * visible portion of this view. 13811 * @param globalOffset If true is returned, globalOffset holds the dx,dy 13812 * between this view and its root. globalOffet may be null. 13813 * @return true if r is non-empty (i.e. part of the view is visible at the 13814 * root level. 13815 */ 13816 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 13817 int width = mRight - mLeft; 13818 int height = mBottom - mTop; 13819 if (width > 0 && height > 0) { 13820 r.set(0, 0, width, height); 13821 if (globalOffset != null) { 13822 globalOffset.set(-mScrollX, -mScrollY); 13823 } 13824 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 13825 } 13826 return false; 13827 } 13828 13829 public final boolean getGlobalVisibleRect(Rect r) { 13830 return getGlobalVisibleRect(r, null); 13831 } 13832 13833 public final boolean getLocalVisibleRect(Rect r) { 13834 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 13835 if (getGlobalVisibleRect(r, offset)) { 13836 r.offset(-offset.x, -offset.y); // make r local 13837 return true; 13838 } 13839 return false; 13840 } 13841 13842 /** 13843 * Offset this view's vertical location by the specified number of pixels. 13844 * 13845 * @param offset the number of pixels to offset the view by 13846 */ 13847 public void offsetTopAndBottom(int offset) { 13848 if (offset != 0) { 13849 final boolean matrixIsIdentity = hasIdentityMatrix(); 13850 if (matrixIsIdentity) { 13851 if (isHardwareAccelerated()) { 13852 invalidateViewProperty(false, false); 13853 } else { 13854 final ViewParent p = mParent; 13855 if (p != null && mAttachInfo != null) { 13856 final Rect r = mAttachInfo.mTmpInvalRect; 13857 int minTop; 13858 int maxBottom; 13859 int yLoc; 13860 if (offset < 0) { 13861 minTop = mTop + offset; 13862 maxBottom = mBottom; 13863 yLoc = offset; 13864 } else { 13865 minTop = mTop; 13866 maxBottom = mBottom + offset; 13867 yLoc = 0; 13868 } 13869 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 13870 p.invalidateChild(this, r); 13871 } 13872 } 13873 } else { 13874 invalidateViewProperty(false, false); 13875 } 13876 13877 mTop += offset; 13878 mBottom += offset; 13879 mRenderNode.offsetTopAndBottom(offset); 13880 if (isHardwareAccelerated()) { 13881 invalidateViewProperty(false, false); 13882 invalidateParentIfNeededAndWasQuickRejected(); 13883 } else { 13884 if (!matrixIsIdentity) { 13885 invalidateViewProperty(false, true); 13886 } 13887 invalidateParentIfNeeded(); 13888 } 13889 notifySubtreeAccessibilityStateChangedIfNeeded(); 13890 } 13891 } 13892 13893 /** 13894 * Offset this view's horizontal location by the specified amount of pixels. 13895 * 13896 * @param offset the number of pixels to offset the view by 13897 */ 13898 public void offsetLeftAndRight(int offset) { 13899 if (offset != 0) { 13900 final boolean matrixIsIdentity = hasIdentityMatrix(); 13901 if (matrixIsIdentity) { 13902 if (isHardwareAccelerated()) { 13903 invalidateViewProperty(false, false); 13904 } else { 13905 final ViewParent p = mParent; 13906 if (p != null && mAttachInfo != null) { 13907 final Rect r = mAttachInfo.mTmpInvalRect; 13908 int minLeft; 13909 int maxRight; 13910 if (offset < 0) { 13911 minLeft = mLeft + offset; 13912 maxRight = mRight; 13913 } else { 13914 minLeft = mLeft; 13915 maxRight = mRight + offset; 13916 } 13917 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 13918 p.invalidateChild(this, r); 13919 } 13920 } 13921 } else { 13922 invalidateViewProperty(false, false); 13923 } 13924 13925 mLeft += offset; 13926 mRight += offset; 13927 mRenderNode.offsetLeftAndRight(offset); 13928 if (isHardwareAccelerated()) { 13929 invalidateViewProperty(false, false); 13930 invalidateParentIfNeededAndWasQuickRejected(); 13931 } else { 13932 if (!matrixIsIdentity) { 13933 invalidateViewProperty(false, true); 13934 } 13935 invalidateParentIfNeeded(); 13936 } 13937 notifySubtreeAccessibilityStateChangedIfNeeded(); 13938 } 13939 } 13940 13941 /** 13942 * Get the LayoutParams associated with this view. All views should have 13943 * layout parameters. These supply parameters to the <i>parent</i> of this 13944 * view specifying how it should be arranged. There are many subclasses of 13945 * ViewGroup.LayoutParams, and these correspond to the different subclasses 13946 * of ViewGroup that are responsible for arranging their children. 13947 * 13948 * This method may return null if this View is not attached to a parent 13949 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 13950 * was not invoked successfully. When a View is attached to a parent 13951 * ViewGroup, this method must not return null. 13952 * 13953 * @return The LayoutParams associated with this view, or null if no 13954 * parameters have been set yet 13955 */ 13956 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 13957 public ViewGroup.LayoutParams getLayoutParams() { 13958 return mLayoutParams; 13959 } 13960 13961 /** 13962 * Set the layout parameters associated with this view. These supply 13963 * parameters to the <i>parent</i> of this view specifying how it should be 13964 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 13965 * correspond to the different subclasses of ViewGroup that are responsible 13966 * for arranging their children. 13967 * 13968 * @param params The layout parameters for this view, cannot be null 13969 */ 13970 public void setLayoutParams(ViewGroup.LayoutParams params) { 13971 if (params == null) { 13972 throw new NullPointerException("Layout parameters cannot be null"); 13973 } 13974 mLayoutParams = params; 13975 resolveLayoutParams(); 13976 if (mParent instanceof ViewGroup) { 13977 ((ViewGroup) mParent).onSetLayoutParams(this, params); 13978 } 13979 requestLayout(); 13980 } 13981 13982 /** 13983 * Resolve the layout parameters depending on the resolved layout direction 13984 * 13985 * @hide 13986 */ 13987 public void resolveLayoutParams() { 13988 if (mLayoutParams != null) { 13989 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 13990 } 13991 } 13992 13993 /** 13994 * Set the scrolled position of your view. This will cause a call to 13995 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13996 * invalidated. 13997 * @param x the x position to scroll to 13998 * @param y the y position to scroll to 13999 */ 14000 public void scrollTo(int x, int y) { 14001 if (mScrollX != x || mScrollY != y) { 14002 int oldX = mScrollX; 14003 int oldY = mScrollY; 14004 mScrollX = x; 14005 mScrollY = y; 14006 invalidateParentCaches(); 14007 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 14008 if (!awakenScrollBars()) { 14009 postInvalidateOnAnimation(); 14010 } 14011 } 14012 } 14013 14014 /** 14015 * Move the scrolled position of your view. This will cause a call to 14016 * {@link #onScrollChanged(int, int, int, int)} and the view will be 14017 * invalidated. 14018 * @param x the amount of pixels to scroll by horizontally 14019 * @param y the amount of pixels to scroll by vertically 14020 */ 14021 public void scrollBy(int x, int y) { 14022 scrollTo(mScrollX + x, mScrollY + y); 14023 } 14024 14025 /** 14026 * <p>Trigger the scrollbars to draw. When invoked this method starts an 14027 * animation to fade the scrollbars out after a default delay. If a subclass 14028 * provides animated scrolling, the start delay should equal the duration 14029 * of the scrolling animation.</p> 14030 * 14031 * <p>The animation starts only if at least one of the scrollbars is 14032 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 14033 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14034 * this method returns true, and false otherwise. If the animation is 14035 * started, this method calls {@link #invalidate()}; in that case the 14036 * caller should not call {@link #invalidate()}.</p> 14037 * 14038 * <p>This method should be invoked every time a subclass directly updates 14039 * the scroll parameters.</p> 14040 * 14041 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 14042 * and {@link #scrollTo(int, int)}.</p> 14043 * 14044 * @return true if the animation is played, false otherwise 14045 * 14046 * @see #awakenScrollBars(int) 14047 * @see #scrollBy(int, int) 14048 * @see #scrollTo(int, int) 14049 * @see #isHorizontalScrollBarEnabled() 14050 * @see #isVerticalScrollBarEnabled() 14051 * @see #setHorizontalScrollBarEnabled(boolean) 14052 * @see #setVerticalScrollBarEnabled(boolean) 14053 */ 14054 protected boolean awakenScrollBars() { 14055 return mScrollCache != null && 14056 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 14057 } 14058 14059 /** 14060 * Trigger the scrollbars to draw. 14061 * This method differs from awakenScrollBars() only in its default duration. 14062 * initialAwakenScrollBars() will show the scroll bars for longer than 14063 * usual to give the user more of a chance to notice them. 14064 * 14065 * @return true if the animation is played, false otherwise. 14066 */ 14067 private boolean initialAwakenScrollBars() { 14068 return mScrollCache != null && 14069 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 14070 } 14071 14072 /** 14073 * <p> 14074 * Trigger the scrollbars to draw. When invoked this method starts an 14075 * animation to fade the scrollbars out after a fixed delay. If a subclass 14076 * provides animated scrolling, the start delay should equal the duration of 14077 * the scrolling animation. 14078 * </p> 14079 * 14080 * <p> 14081 * The animation starts only if at least one of the scrollbars is enabled, 14082 * as specified by {@link #isHorizontalScrollBarEnabled()} and 14083 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14084 * this method returns true, and false otherwise. If the animation is 14085 * started, this method calls {@link #invalidate()}; in that case the caller 14086 * should not call {@link #invalidate()}. 14087 * </p> 14088 * 14089 * <p> 14090 * This method should be invoked every time a subclass directly updates the 14091 * scroll parameters. 14092 * </p> 14093 * 14094 * @param startDelay the delay, in milliseconds, after which the animation 14095 * should start; when the delay is 0, the animation starts 14096 * immediately 14097 * @return true if the animation is played, false otherwise 14098 * 14099 * @see #scrollBy(int, int) 14100 * @see #scrollTo(int, int) 14101 * @see #isHorizontalScrollBarEnabled() 14102 * @see #isVerticalScrollBarEnabled() 14103 * @see #setHorizontalScrollBarEnabled(boolean) 14104 * @see #setVerticalScrollBarEnabled(boolean) 14105 */ 14106 protected boolean awakenScrollBars(int startDelay) { 14107 return awakenScrollBars(startDelay, true); 14108 } 14109 14110 /** 14111 * <p> 14112 * Trigger the scrollbars to draw. When invoked this method starts an 14113 * animation to fade the scrollbars out after a fixed delay. If a subclass 14114 * provides animated scrolling, the start delay should equal the duration of 14115 * the scrolling animation. 14116 * </p> 14117 * 14118 * <p> 14119 * The animation starts only if at least one of the scrollbars is enabled, 14120 * as specified by {@link #isHorizontalScrollBarEnabled()} and 14121 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14122 * this method returns true, and false otherwise. If the animation is 14123 * started, this method calls {@link #invalidate()} if the invalidate parameter 14124 * is set to true; in that case the caller 14125 * should not call {@link #invalidate()}. 14126 * </p> 14127 * 14128 * <p> 14129 * This method should be invoked every time a subclass directly updates the 14130 * scroll parameters. 14131 * </p> 14132 * 14133 * @param startDelay the delay, in milliseconds, after which the animation 14134 * should start; when the delay is 0, the animation starts 14135 * immediately 14136 * 14137 * @param invalidate Whether this method should call invalidate 14138 * 14139 * @return true if the animation is played, false otherwise 14140 * 14141 * @see #scrollBy(int, int) 14142 * @see #scrollTo(int, int) 14143 * @see #isHorizontalScrollBarEnabled() 14144 * @see #isVerticalScrollBarEnabled() 14145 * @see #setHorizontalScrollBarEnabled(boolean) 14146 * @see #setVerticalScrollBarEnabled(boolean) 14147 */ 14148 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 14149 final ScrollabilityCache scrollCache = mScrollCache; 14150 14151 if (scrollCache == null || !scrollCache.fadeScrollBars) { 14152 return false; 14153 } 14154 14155 if (scrollCache.scrollBar == null) { 14156 scrollCache.scrollBar = new ScrollBarDrawable(); 14157 scrollCache.scrollBar.setState(getDrawableState()); 14158 scrollCache.scrollBar.setCallback(this); 14159 } 14160 14161 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 14162 14163 if (invalidate) { 14164 // Invalidate to show the scrollbars 14165 postInvalidateOnAnimation(); 14166 } 14167 14168 if (scrollCache.state == ScrollabilityCache.OFF) { 14169 // FIXME: this is copied from WindowManagerService. 14170 // We should get this value from the system when it 14171 // is possible to do so. 14172 final int KEY_REPEAT_FIRST_DELAY = 750; 14173 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 14174 } 14175 14176 // Tell mScrollCache when we should start fading. This may 14177 // extend the fade start time if one was already scheduled 14178 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 14179 scrollCache.fadeStartTime = fadeStartTime; 14180 scrollCache.state = ScrollabilityCache.ON; 14181 14182 // Schedule our fader to run, unscheduling any old ones first 14183 if (mAttachInfo != null) { 14184 mAttachInfo.mHandler.removeCallbacks(scrollCache); 14185 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 14186 } 14187 14188 return true; 14189 } 14190 14191 return false; 14192 } 14193 14194 /** 14195 * Do not invalidate views which are not visible and which are not running an animation. They 14196 * will not get drawn and they should not set dirty flags as if they will be drawn 14197 */ 14198 private boolean skipInvalidate() { 14199 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 14200 (!(mParent instanceof ViewGroup) || 14201 !((ViewGroup) mParent).isViewTransitioning(this)); 14202 } 14203 14204 /** 14205 * Mark the area defined by dirty as needing to be drawn. If the view is 14206 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14207 * point in the future. 14208 * <p> 14209 * This must be called from a UI thread. To call from a non-UI thread, call 14210 * {@link #postInvalidate()}. 14211 * <p> 14212 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 14213 * {@code dirty}. 14214 * 14215 * @param dirty the rectangle representing the bounds of the dirty region 14216 */ 14217 public void invalidate(Rect dirty) { 14218 final int scrollX = mScrollX; 14219 final int scrollY = mScrollY; 14220 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 14221 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 14222 } 14223 14224 /** 14225 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 14226 * coordinates of the dirty rect are relative to the view. If the view is 14227 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14228 * point in the future. 14229 * <p> 14230 * This must be called from a UI thread. To call from a non-UI thread, call 14231 * {@link #postInvalidate()}. 14232 * 14233 * @param l the left position of the dirty region 14234 * @param t the top position of the dirty region 14235 * @param r the right position of the dirty region 14236 * @param b the bottom position of the dirty region 14237 */ 14238 public void invalidate(int l, int t, int r, int b) { 14239 final int scrollX = mScrollX; 14240 final int scrollY = mScrollY; 14241 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 14242 } 14243 14244 /** 14245 * Invalidate the whole view. If the view is visible, 14246 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 14247 * the future. 14248 * <p> 14249 * This must be called from a UI thread. To call from a non-UI thread, call 14250 * {@link #postInvalidate()}. 14251 */ 14252 public void invalidate() { 14253 invalidate(true); 14254 } 14255 14256 /** 14257 * This is where the invalidate() work actually happens. A full invalidate() 14258 * causes the drawing cache to be invalidated, but this function can be 14259 * called with invalidateCache set to false to skip that invalidation step 14260 * for cases that do not need it (for example, a component that remains at 14261 * the same dimensions with the same content). 14262 * 14263 * @param invalidateCache Whether the drawing cache for this view should be 14264 * invalidated as well. This is usually true for a full 14265 * invalidate, but may be set to false if the View's contents or 14266 * dimensions have not changed. 14267 * @hide 14268 */ 14269 public void invalidate(boolean invalidateCache) { 14270 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 14271 } 14272 14273 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 14274 boolean fullInvalidate) { 14275 if (mGhostView != null) { 14276 mGhostView.invalidate(true); 14277 return; 14278 } 14279 14280 if (skipInvalidate()) { 14281 return; 14282 } 14283 14284 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 14285 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 14286 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 14287 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 14288 if (fullInvalidate) { 14289 mLastIsOpaque = isOpaque(); 14290 mPrivateFlags &= ~PFLAG_DRAWN; 14291 } 14292 14293 mPrivateFlags |= PFLAG_DIRTY; 14294 14295 if (invalidateCache) { 14296 mPrivateFlags |= PFLAG_INVALIDATED; 14297 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 14298 } 14299 14300 // Propagate the damage rectangle to the parent view. 14301 final AttachInfo ai = mAttachInfo; 14302 final ViewParent p = mParent; 14303 if (p != null && ai != null && l < r && t < b) { 14304 final Rect damage = ai.mTmpInvalRect; 14305 damage.set(l, t, r, b); 14306 p.invalidateChild(this, damage); 14307 } 14308 14309 // Damage the entire projection receiver, if necessary. 14310 if (mBackground != null && mBackground.isProjected()) { 14311 final View receiver = getProjectionReceiver(); 14312 if (receiver != null) { 14313 receiver.damageInParent(); 14314 } 14315 } 14316 } 14317 } 14318 14319 /** 14320 * @return this view's projection receiver, or {@code null} if none exists 14321 */ 14322 private View getProjectionReceiver() { 14323 ViewParent p = getParent(); 14324 while (p != null && p instanceof View) { 14325 final View v = (View) p; 14326 if (v.isProjectionReceiver()) { 14327 return v; 14328 } 14329 p = p.getParent(); 14330 } 14331 14332 return null; 14333 } 14334 14335 /** 14336 * @return whether the view is a projection receiver 14337 */ 14338 private boolean isProjectionReceiver() { 14339 return mBackground != null; 14340 } 14341 14342 /** 14343 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 14344 * set any flags or handle all of the cases handled by the default invalidation methods. 14345 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 14346 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 14347 * walk up the hierarchy, transforming the dirty rect as necessary. 14348 * 14349 * The method also handles normal invalidation logic if display list properties are not 14350 * being used in this view. The invalidateParent and forceRedraw flags are used by that 14351 * backup approach, to handle these cases used in the various property-setting methods. 14352 * 14353 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 14354 * are not being used in this view 14355 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 14356 * list properties are not being used in this view 14357 */ 14358 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 14359 if (!isHardwareAccelerated() 14360 || !mRenderNode.isValid() 14361 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 14362 if (invalidateParent) { 14363 invalidateParentCaches(); 14364 } 14365 if (forceRedraw) { 14366 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14367 } 14368 invalidate(false); 14369 } else { 14370 damageInParent(); 14371 } 14372 } 14373 14374 /** 14375 * Tells the parent view to damage this view's bounds. 14376 * 14377 * @hide 14378 */ 14379 protected void damageInParent() { 14380 final AttachInfo ai = mAttachInfo; 14381 final ViewParent p = mParent; 14382 if (p != null && ai != null) { 14383 final Rect r = ai.mTmpInvalRect; 14384 r.set(0, 0, mRight - mLeft, mBottom - mTop); 14385 if (mParent instanceof ViewGroup) { 14386 ((ViewGroup) mParent).damageChild(this, r); 14387 } else { 14388 mParent.invalidateChild(this, r); 14389 } 14390 } 14391 } 14392 14393 /** 14394 * Utility method to transform a given Rect by the current matrix of this view. 14395 */ 14396 void transformRect(final Rect rect) { 14397 if (!getMatrix().isIdentity()) { 14398 RectF boundingRect = mAttachInfo.mTmpTransformRect; 14399 boundingRect.set(rect); 14400 getMatrix().mapRect(boundingRect); 14401 rect.set((int) Math.floor(boundingRect.left), 14402 (int) Math.floor(boundingRect.top), 14403 (int) Math.ceil(boundingRect.right), 14404 (int) Math.ceil(boundingRect.bottom)); 14405 } 14406 } 14407 14408 /** 14409 * Used to indicate that the parent of this view should clear its caches. This functionality 14410 * is used to force the parent to rebuild its display list (when hardware-accelerated), 14411 * which is necessary when various parent-managed properties of the view change, such as 14412 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 14413 * clears the parent caches and does not causes an invalidate event. 14414 * 14415 * @hide 14416 */ 14417 protected void invalidateParentCaches() { 14418 if (mParent instanceof View) { 14419 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 14420 } 14421 } 14422 14423 /** 14424 * Used to indicate that the parent of this view should be invalidated. This functionality 14425 * is used to force the parent to rebuild its display list (when hardware-accelerated), 14426 * which is necessary when various parent-managed properties of the view change, such as 14427 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 14428 * an invalidation event to the parent. 14429 * 14430 * @hide 14431 */ 14432 protected void invalidateParentIfNeeded() { 14433 if (isHardwareAccelerated() && mParent instanceof View) { 14434 ((View) mParent).invalidate(true); 14435 } 14436 } 14437 14438 /** 14439 * @hide 14440 */ 14441 protected void invalidateParentIfNeededAndWasQuickRejected() { 14442 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 14443 // View was rejected last time it was drawn by its parent; this may have changed 14444 invalidateParentIfNeeded(); 14445 } 14446 } 14447 14448 /** 14449 * Indicates whether this View is opaque. An opaque View guarantees that it will 14450 * draw all the pixels overlapping its bounds using a fully opaque color. 14451 * 14452 * Subclasses of View should override this method whenever possible to indicate 14453 * whether an instance is opaque. Opaque Views are treated in a special way by 14454 * the View hierarchy, possibly allowing it to perform optimizations during 14455 * invalidate/draw passes. 14456 * 14457 * @return True if this View is guaranteed to be fully opaque, false otherwise. 14458 */ 14459 @ViewDebug.ExportedProperty(category = "drawing") 14460 public boolean isOpaque() { 14461 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 14462 getFinalAlpha() >= 1.0f; 14463 } 14464 14465 /** 14466 * @hide 14467 */ 14468 protected void computeOpaqueFlags() { 14469 // Opaque if: 14470 // - Has a background 14471 // - Background is opaque 14472 // - Doesn't have scrollbars or scrollbars overlay 14473 14474 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 14475 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 14476 } else { 14477 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 14478 } 14479 14480 final int flags = mViewFlags; 14481 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 14482 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 14483 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 14484 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 14485 } else { 14486 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 14487 } 14488 } 14489 14490 /** 14491 * @hide 14492 */ 14493 protected boolean hasOpaqueScrollbars() { 14494 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 14495 } 14496 14497 /** 14498 * @return A handler associated with the thread running the View. This 14499 * handler can be used to pump events in the UI events queue. 14500 */ 14501 public Handler getHandler() { 14502 final AttachInfo attachInfo = mAttachInfo; 14503 if (attachInfo != null) { 14504 return attachInfo.mHandler; 14505 } 14506 return null; 14507 } 14508 14509 /** 14510 * Returns the queue of runnable for this view. 14511 * 14512 * @return the queue of runnables for this view 14513 */ 14514 private HandlerActionQueue getRunQueue() { 14515 if (mRunQueue == null) { 14516 mRunQueue = new HandlerActionQueue(); 14517 } 14518 return mRunQueue; 14519 } 14520 14521 /** 14522 * Gets the view root associated with the View. 14523 * @return The view root, or null if none. 14524 * @hide 14525 */ 14526 public ViewRootImpl getViewRootImpl() { 14527 if (mAttachInfo != null) { 14528 return mAttachInfo.mViewRootImpl; 14529 } 14530 return null; 14531 } 14532 14533 /** 14534 * @hide 14535 */ 14536 public ThreadedRenderer getThreadedRenderer() { 14537 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 14538 } 14539 14540 /** 14541 * <p>Causes the Runnable to be added to the message queue. 14542 * The runnable will be run on the user interface thread.</p> 14543 * 14544 * @param action The Runnable that will be executed. 14545 * 14546 * @return Returns true if the Runnable was successfully placed in to the 14547 * message queue. Returns false on failure, usually because the 14548 * looper processing the message queue is exiting. 14549 * 14550 * @see #postDelayed 14551 * @see #removeCallbacks 14552 */ 14553 public boolean post(Runnable action) { 14554 final AttachInfo attachInfo = mAttachInfo; 14555 if (attachInfo != null) { 14556 return attachInfo.mHandler.post(action); 14557 } 14558 14559 // Postpone the runnable until we know on which thread it needs to run. 14560 // Assume that the runnable will be successfully placed after attach. 14561 getRunQueue().post(action); 14562 return true; 14563 } 14564 14565 /** 14566 * <p>Causes the Runnable to be added to the message queue, to be run 14567 * after the specified amount of time elapses. 14568 * The runnable will be run on the user interface thread.</p> 14569 * 14570 * @param action The Runnable that will be executed. 14571 * @param delayMillis The delay (in milliseconds) until the Runnable 14572 * will be executed. 14573 * 14574 * @return true if the Runnable was successfully placed in to the 14575 * message queue. Returns false on failure, usually because the 14576 * looper processing the message queue is exiting. Note that a 14577 * result of true does not mean the Runnable will be processed -- 14578 * if the looper is quit before the delivery time of the message 14579 * occurs then the message will be dropped. 14580 * 14581 * @see #post 14582 * @see #removeCallbacks 14583 */ 14584 public boolean postDelayed(Runnable action, long delayMillis) { 14585 final AttachInfo attachInfo = mAttachInfo; 14586 if (attachInfo != null) { 14587 return attachInfo.mHandler.postDelayed(action, delayMillis); 14588 } 14589 14590 // Postpone the runnable until we know on which thread it needs to run. 14591 // Assume that the runnable will be successfully placed after attach. 14592 getRunQueue().postDelayed(action, delayMillis); 14593 return true; 14594 } 14595 14596 /** 14597 * <p>Causes the Runnable to execute on the next animation time step. 14598 * The runnable will be run on the user interface thread.</p> 14599 * 14600 * @param action The Runnable that will be executed. 14601 * 14602 * @see #postOnAnimationDelayed 14603 * @see #removeCallbacks 14604 */ 14605 public void postOnAnimation(Runnable action) { 14606 final AttachInfo attachInfo = mAttachInfo; 14607 if (attachInfo != null) { 14608 attachInfo.mViewRootImpl.mChoreographer.postCallback( 14609 Choreographer.CALLBACK_ANIMATION, action, null); 14610 } else { 14611 // Postpone the runnable until we know 14612 // on which thread it needs to run. 14613 getRunQueue().post(action); 14614 } 14615 } 14616 14617 /** 14618 * <p>Causes the Runnable to execute on the next animation time step, 14619 * after the specified amount of time elapses. 14620 * The runnable will be run on the user interface thread.</p> 14621 * 14622 * @param action The Runnable that will be executed. 14623 * @param delayMillis The delay (in milliseconds) until the Runnable 14624 * will be executed. 14625 * 14626 * @see #postOnAnimation 14627 * @see #removeCallbacks 14628 */ 14629 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 14630 final AttachInfo attachInfo = mAttachInfo; 14631 if (attachInfo != null) { 14632 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 14633 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 14634 } else { 14635 // Postpone the runnable until we know 14636 // on which thread it needs to run. 14637 getRunQueue().postDelayed(action, delayMillis); 14638 } 14639 } 14640 14641 /** 14642 * <p>Removes the specified Runnable from the message queue.</p> 14643 * 14644 * @param action The Runnable to remove from the message handling queue 14645 * 14646 * @return true if this view could ask the Handler to remove the Runnable, 14647 * false otherwise. When the returned value is true, the Runnable 14648 * may or may not have been actually removed from the message queue 14649 * (for instance, if the Runnable was not in the queue already.) 14650 * 14651 * @see #post 14652 * @see #postDelayed 14653 * @see #postOnAnimation 14654 * @see #postOnAnimationDelayed 14655 */ 14656 public boolean removeCallbacks(Runnable action) { 14657 if (action != null) { 14658 final AttachInfo attachInfo = mAttachInfo; 14659 if (attachInfo != null) { 14660 attachInfo.mHandler.removeCallbacks(action); 14661 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 14662 Choreographer.CALLBACK_ANIMATION, action, null); 14663 } 14664 getRunQueue().removeCallbacks(action); 14665 } 14666 return true; 14667 } 14668 14669 /** 14670 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 14671 * Use this to invalidate the View from a non-UI thread.</p> 14672 * 14673 * <p>This method can be invoked from outside of the UI thread 14674 * only when this View is attached to a window.</p> 14675 * 14676 * @see #invalidate() 14677 * @see #postInvalidateDelayed(long) 14678 */ 14679 public void postInvalidate() { 14680 postInvalidateDelayed(0); 14681 } 14682 14683 /** 14684 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14685 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 14686 * 14687 * <p>This method can be invoked from outside of the UI thread 14688 * only when this View is attached to a window.</p> 14689 * 14690 * @param left The left coordinate of the rectangle to invalidate. 14691 * @param top The top coordinate of the rectangle to invalidate. 14692 * @param right The right coordinate of the rectangle to invalidate. 14693 * @param bottom The bottom coordinate of the rectangle to invalidate. 14694 * 14695 * @see #invalidate(int, int, int, int) 14696 * @see #invalidate(Rect) 14697 * @see #postInvalidateDelayed(long, int, int, int, int) 14698 */ 14699 public void postInvalidate(int left, int top, int right, int bottom) { 14700 postInvalidateDelayed(0, left, top, right, bottom); 14701 } 14702 14703 /** 14704 * <p>Cause an invalidate to happen on a subsequent cycle through the event 14705 * loop. Waits for the specified amount of time.</p> 14706 * 14707 * <p>This method can be invoked from outside of the UI thread 14708 * only when this View is attached to a window.</p> 14709 * 14710 * @param delayMilliseconds the duration in milliseconds to delay the 14711 * invalidation by 14712 * 14713 * @see #invalidate() 14714 * @see #postInvalidate() 14715 */ 14716 public void postInvalidateDelayed(long delayMilliseconds) { 14717 // We try only with the AttachInfo because there's no point in invalidating 14718 // if we are not attached to our window 14719 final AttachInfo attachInfo = mAttachInfo; 14720 if (attachInfo != null) { 14721 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 14722 } 14723 } 14724 14725 /** 14726 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14727 * through the event loop. Waits for the specified amount of time.</p> 14728 * 14729 * <p>This method can be invoked from outside of the UI thread 14730 * only when this View is attached to a window.</p> 14731 * 14732 * @param delayMilliseconds the duration in milliseconds to delay the 14733 * invalidation by 14734 * @param left The left coordinate of the rectangle to invalidate. 14735 * @param top The top coordinate of the rectangle to invalidate. 14736 * @param right The right coordinate of the rectangle to invalidate. 14737 * @param bottom The bottom coordinate of the rectangle to invalidate. 14738 * 14739 * @see #invalidate(int, int, int, int) 14740 * @see #invalidate(Rect) 14741 * @see #postInvalidate(int, int, int, int) 14742 */ 14743 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 14744 int right, int bottom) { 14745 14746 // We try only with the AttachInfo because there's no point in invalidating 14747 // if we are not attached to our window 14748 final AttachInfo attachInfo = mAttachInfo; 14749 if (attachInfo != null) { 14750 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14751 info.target = this; 14752 info.left = left; 14753 info.top = top; 14754 info.right = right; 14755 info.bottom = bottom; 14756 14757 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 14758 } 14759 } 14760 14761 /** 14762 * <p>Cause an invalidate to happen on the next animation time step, typically the 14763 * next display frame.</p> 14764 * 14765 * <p>This method can be invoked from outside of the UI thread 14766 * only when this View is attached to a window.</p> 14767 * 14768 * @see #invalidate() 14769 */ 14770 public void postInvalidateOnAnimation() { 14771 // We try only with the AttachInfo because there's no point in invalidating 14772 // if we are not attached to our window 14773 final AttachInfo attachInfo = mAttachInfo; 14774 if (attachInfo != null) { 14775 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 14776 } 14777 } 14778 14779 /** 14780 * <p>Cause an invalidate of the specified area to happen on the next animation 14781 * time step, typically the next display frame.</p> 14782 * 14783 * <p>This method can be invoked from outside of the UI thread 14784 * only when this View is attached to a window.</p> 14785 * 14786 * @param left The left coordinate of the rectangle to invalidate. 14787 * @param top The top coordinate of the rectangle to invalidate. 14788 * @param right The right coordinate of the rectangle to invalidate. 14789 * @param bottom The bottom coordinate of the rectangle to invalidate. 14790 * 14791 * @see #invalidate(int, int, int, int) 14792 * @see #invalidate(Rect) 14793 */ 14794 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 14795 // We try only with the AttachInfo because there's no point in invalidating 14796 // if we are not attached to our window 14797 final AttachInfo attachInfo = mAttachInfo; 14798 if (attachInfo != null) { 14799 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14800 info.target = this; 14801 info.left = left; 14802 info.top = top; 14803 info.right = right; 14804 info.bottom = bottom; 14805 14806 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 14807 } 14808 } 14809 14810 /** 14811 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 14812 * This event is sent at most once every 14813 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 14814 */ 14815 private void postSendViewScrolledAccessibilityEventCallback() { 14816 if (mSendViewScrolledAccessibilityEvent == null) { 14817 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 14818 } 14819 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 14820 mSendViewScrolledAccessibilityEvent.mIsPending = true; 14821 postDelayed(mSendViewScrolledAccessibilityEvent, 14822 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 14823 } 14824 } 14825 14826 /** 14827 * Called by a parent to request that a child update its values for mScrollX 14828 * and mScrollY if necessary. This will typically be done if the child is 14829 * animating a scroll using a {@link android.widget.Scroller Scroller} 14830 * object. 14831 */ 14832 public void computeScroll() { 14833 } 14834 14835 /** 14836 * <p>Indicate whether the horizontal edges are faded when the view is 14837 * scrolled horizontally.</p> 14838 * 14839 * @return true if the horizontal edges should are faded on scroll, false 14840 * otherwise 14841 * 14842 * @see #setHorizontalFadingEdgeEnabled(boolean) 14843 * 14844 * @attr ref android.R.styleable#View_requiresFadingEdge 14845 */ 14846 public boolean isHorizontalFadingEdgeEnabled() { 14847 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 14848 } 14849 14850 /** 14851 * <p>Define whether the horizontal edges should be faded when this view 14852 * is scrolled horizontally.</p> 14853 * 14854 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 14855 * be faded when the view is scrolled 14856 * horizontally 14857 * 14858 * @see #isHorizontalFadingEdgeEnabled() 14859 * 14860 * @attr ref android.R.styleable#View_requiresFadingEdge 14861 */ 14862 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 14863 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 14864 if (horizontalFadingEdgeEnabled) { 14865 initScrollCache(); 14866 } 14867 14868 mViewFlags ^= FADING_EDGE_HORIZONTAL; 14869 } 14870 } 14871 14872 /** 14873 * <p>Indicate whether the vertical edges are faded when the view is 14874 * scrolled horizontally.</p> 14875 * 14876 * @return true if the vertical edges should are faded on scroll, false 14877 * otherwise 14878 * 14879 * @see #setVerticalFadingEdgeEnabled(boolean) 14880 * 14881 * @attr ref android.R.styleable#View_requiresFadingEdge 14882 */ 14883 public boolean isVerticalFadingEdgeEnabled() { 14884 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 14885 } 14886 14887 /** 14888 * <p>Define whether the vertical edges should be faded when this view 14889 * is scrolled vertically.</p> 14890 * 14891 * @param verticalFadingEdgeEnabled true if the vertical edges should 14892 * be faded when the view is scrolled 14893 * vertically 14894 * 14895 * @see #isVerticalFadingEdgeEnabled() 14896 * 14897 * @attr ref android.R.styleable#View_requiresFadingEdge 14898 */ 14899 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 14900 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 14901 if (verticalFadingEdgeEnabled) { 14902 initScrollCache(); 14903 } 14904 14905 mViewFlags ^= FADING_EDGE_VERTICAL; 14906 } 14907 } 14908 14909 /** 14910 * Returns the strength, or intensity, of the top faded edge. The strength is 14911 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14912 * returns 0.0 or 1.0 but no value in between. 14913 * 14914 * Subclasses should override this method to provide a smoother fade transition 14915 * when scrolling occurs. 14916 * 14917 * @return the intensity of the top fade as a float between 0.0f and 1.0f 14918 */ 14919 protected float getTopFadingEdgeStrength() { 14920 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 14921 } 14922 14923 /** 14924 * Returns the strength, or intensity, of the bottom faded edge. The strength is 14925 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14926 * returns 0.0 or 1.0 but no value in between. 14927 * 14928 * Subclasses should override this method to provide a smoother fade transition 14929 * when scrolling occurs. 14930 * 14931 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 14932 */ 14933 protected float getBottomFadingEdgeStrength() { 14934 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 14935 computeVerticalScrollRange() ? 1.0f : 0.0f; 14936 } 14937 14938 /** 14939 * Returns the strength, or intensity, of the left faded edge. The strength is 14940 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14941 * returns 0.0 or 1.0 but no value in between. 14942 * 14943 * Subclasses should override this method to provide a smoother fade transition 14944 * when scrolling occurs. 14945 * 14946 * @return the intensity of the left fade as a float between 0.0f and 1.0f 14947 */ 14948 protected float getLeftFadingEdgeStrength() { 14949 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 14950 } 14951 14952 /** 14953 * Returns the strength, or intensity, of the right faded edge. The strength is 14954 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14955 * returns 0.0 or 1.0 but no value in between. 14956 * 14957 * Subclasses should override this method to provide a smoother fade transition 14958 * when scrolling occurs. 14959 * 14960 * @return the intensity of the right fade as a float between 0.0f and 1.0f 14961 */ 14962 protected float getRightFadingEdgeStrength() { 14963 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 14964 computeHorizontalScrollRange() ? 1.0f : 0.0f; 14965 } 14966 14967 /** 14968 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 14969 * scrollbar is not drawn by default.</p> 14970 * 14971 * @return true if the horizontal scrollbar should be painted, false 14972 * otherwise 14973 * 14974 * @see #setHorizontalScrollBarEnabled(boolean) 14975 */ 14976 public boolean isHorizontalScrollBarEnabled() { 14977 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 14978 } 14979 14980 /** 14981 * <p>Define whether the horizontal scrollbar should be drawn or not. The 14982 * scrollbar is not drawn by default.</p> 14983 * 14984 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 14985 * be painted 14986 * 14987 * @see #isHorizontalScrollBarEnabled() 14988 */ 14989 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 14990 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 14991 mViewFlags ^= SCROLLBARS_HORIZONTAL; 14992 computeOpaqueFlags(); 14993 resolvePadding(); 14994 } 14995 } 14996 14997 /** 14998 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 14999 * scrollbar is not drawn by default.</p> 15000 * 15001 * @return true if the vertical scrollbar should be painted, false 15002 * otherwise 15003 * 15004 * @see #setVerticalScrollBarEnabled(boolean) 15005 */ 15006 public boolean isVerticalScrollBarEnabled() { 15007 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 15008 } 15009 15010 /** 15011 * <p>Define whether the vertical scrollbar should be drawn or not. The 15012 * scrollbar is not drawn by default.</p> 15013 * 15014 * @param verticalScrollBarEnabled true if the vertical scrollbar should 15015 * be painted 15016 * 15017 * @see #isVerticalScrollBarEnabled() 15018 */ 15019 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 15020 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 15021 mViewFlags ^= SCROLLBARS_VERTICAL; 15022 computeOpaqueFlags(); 15023 resolvePadding(); 15024 } 15025 } 15026 15027 /** 15028 * @hide 15029 */ 15030 protected void recomputePadding() { 15031 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 15032 } 15033 15034 /** 15035 * Define whether scrollbars will fade when the view is not scrolling. 15036 * 15037 * @param fadeScrollbars whether to enable fading 15038 * 15039 * @attr ref android.R.styleable#View_fadeScrollbars 15040 */ 15041 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 15042 initScrollCache(); 15043 final ScrollabilityCache scrollabilityCache = mScrollCache; 15044 scrollabilityCache.fadeScrollBars = fadeScrollbars; 15045 if (fadeScrollbars) { 15046 scrollabilityCache.state = ScrollabilityCache.OFF; 15047 } else { 15048 scrollabilityCache.state = ScrollabilityCache.ON; 15049 } 15050 } 15051 15052 /** 15053 * 15054 * Returns true if scrollbars will fade when this view is not scrolling 15055 * 15056 * @return true if scrollbar fading is enabled 15057 * 15058 * @attr ref android.R.styleable#View_fadeScrollbars 15059 */ 15060 public boolean isScrollbarFadingEnabled() { 15061 return mScrollCache != null && mScrollCache.fadeScrollBars; 15062 } 15063 15064 /** 15065 * 15066 * Returns the delay before scrollbars fade. 15067 * 15068 * @return the delay before scrollbars fade 15069 * 15070 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 15071 */ 15072 public int getScrollBarDefaultDelayBeforeFade() { 15073 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 15074 mScrollCache.scrollBarDefaultDelayBeforeFade; 15075 } 15076 15077 /** 15078 * Define the delay before scrollbars fade. 15079 * 15080 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 15081 * 15082 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 15083 */ 15084 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 15085 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 15086 } 15087 15088 /** 15089 * 15090 * Returns the scrollbar fade duration. 15091 * 15092 * @return the scrollbar fade duration, in milliseconds 15093 * 15094 * @attr ref android.R.styleable#View_scrollbarFadeDuration 15095 */ 15096 public int getScrollBarFadeDuration() { 15097 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 15098 mScrollCache.scrollBarFadeDuration; 15099 } 15100 15101 /** 15102 * Define the scrollbar fade duration. 15103 * 15104 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 15105 * 15106 * @attr ref android.R.styleable#View_scrollbarFadeDuration 15107 */ 15108 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 15109 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 15110 } 15111 15112 /** 15113 * 15114 * Returns the scrollbar size. 15115 * 15116 * @return the scrollbar size 15117 * 15118 * @attr ref android.R.styleable#View_scrollbarSize 15119 */ 15120 public int getScrollBarSize() { 15121 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 15122 mScrollCache.scrollBarSize; 15123 } 15124 15125 /** 15126 * Define the scrollbar size. 15127 * 15128 * @param scrollBarSize - the scrollbar size 15129 * 15130 * @attr ref android.R.styleable#View_scrollbarSize 15131 */ 15132 public void setScrollBarSize(int scrollBarSize) { 15133 getScrollCache().scrollBarSize = scrollBarSize; 15134 } 15135 15136 /** 15137 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 15138 * inset. When inset, they add to the padding of the view. And the scrollbars 15139 * can be drawn inside the padding area or on the edge of the view. For example, 15140 * if a view has a background drawable and you want to draw the scrollbars 15141 * inside the padding specified by the drawable, you can use 15142 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 15143 * appear at the edge of the view, ignoring the padding, then you can use 15144 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 15145 * @param style the style of the scrollbars. Should be one of 15146 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 15147 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 15148 * @see #SCROLLBARS_INSIDE_OVERLAY 15149 * @see #SCROLLBARS_INSIDE_INSET 15150 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15151 * @see #SCROLLBARS_OUTSIDE_INSET 15152 * 15153 * @attr ref android.R.styleable#View_scrollbarStyle 15154 */ 15155 public void setScrollBarStyle(@ScrollBarStyle int style) { 15156 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 15157 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 15158 computeOpaqueFlags(); 15159 resolvePadding(); 15160 } 15161 } 15162 15163 /** 15164 * <p>Returns the current scrollbar style.</p> 15165 * @return the current scrollbar style 15166 * @see #SCROLLBARS_INSIDE_OVERLAY 15167 * @see #SCROLLBARS_INSIDE_INSET 15168 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15169 * @see #SCROLLBARS_OUTSIDE_INSET 15170 * 15171 * @attr ref android.R.styleable#View_scrollbarStyle 15172 */ 15173 @ViewDebug.ExportedProperty(mapping = { 15174 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 15175 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 15176 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 15177 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 15178 }) 15179 @ScrollBarStyle 15180 public int getScrollBarStyle() { 15181 return mViewFlags & SCROLLBARS_STYLE_MASK; 15182 } 15183 15184 /** 15185 * <p>Compute the horizontal range that the horizontal scrollbar 15186 * represents.</p> 15187 * 15188 * <p>The range is expressed in arbitrary units that must be the same as the 15189 * units used by {@link #computeHorizontalScrollExtent()} and 15190 * {@link #computeHorizontalScrollOffset()}.</p> 15191 * 15192 * <p>The default range is the drawing width of this view.</p> 15193 * 15194 * @return the total horizontal range represented by the horizontal 15195 * scrollbar 15196 * 15197 * @see #computeHorizontalScrollExtent() 15198 * @see #computeHorizontalScrollOffset() 15199 * @see android.widget.ScrollBarDrawable 15200 */ 15201 protected int computeHorizontalScrollRange() { 15202 return getWidth(); 15203 } 15204 15205 /** 15206 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 15207 * within the horizontal range. This value is used to compute the position 15208 * of the thumb within the scrollbar's track.</p> 15209 * 15210 * <p>The range is expressed in arbitrary units that must be the same as the 15211 * units used by {@link #computeHorizontalScrollRange()} and 15212 * {@link #computeHorizontalScrollExtent()}.</p> 15213 * 15214 * <p>The default offset is the scroll offset of this view.</p> 15215 * 15216 * @return the horizontal offset of the scrollbar's thumb 15217 * 15218 * @see #computeHorizontalScrollRange() 15219 * @see #computeHorizontalScrollExtent() 15220 * @see android.widget.ScrollBarDrawable 15221 */ 15222 protected int computeHorizontalScrollOffset() { 15223 return mScrollX; 15224 } 15225 15226 /** 15227 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 15228 * within the horizontal range. This value is used to compute the length 15229 * of the thumb within the scrollbar's track.</p> 15230 * 15231 * <p>The range is expressed in arbitrary units that must be the same as the 15232 * units used by {@link #computeHorizontalScrollRange()} and 15233 * {@link #computeHorizontalScrollOffset()}.</p> 15234 * 15235 * <p>The default extent is the drawing width of this view.</p> 15236 * 15237 * @return the horizontal extent of the scrollbar's thumb 15238 * 15239 * @see #computeHorizontalScrollRange() 15240 * @see #computeHorizontalScrollOffset() 15241 * @see android.widget.ScrollBarDrawable 15242 */ 15243 protected int computeHorizontalScrollExtent() { 15244 return getWidth(); 15245 } 15246 15247 /** 15248 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 15249 * 15250 * <p>The range is expressed in arbitrary units that must be the same as the 15251 * units used by {@link #computeVerticalScrollExtent()} and 15252 * {@link #computeVerticalScrollOffset()}.</p> 15253 * 15254 * @return the total vertical range represented by the vertical scrollbar 15255 * 15256 * <p>The default range is the drawing height of this view.</p> 15257 * 15258 * @see #computeVerticalScrollExtent() 15259 * @see #computeVerticalScrollOffset() 15260 * @see android.widget.ScrollBarDrawable 15261 */ 15262 protected int computeVerticalScrollRange() { 15263 return getHeight(); 15264 } 15265 15266 /** 15267 * <p>Compute the vertical offset of the vertical scrollbar's thumb 15268 * within the horizontal range. This value is used to compute the position 15269 * of the thumb within the scrollbar's track.</p> 15270 * 15271 * <p>The range is expressed in arbitrary units that must be the same as the 15272 * units used by {@link #computeVerticalScrollRange()} and 15273 * {@link #computeVerticalScrollExtent()}.</p> 15274 * 15275 * <p>The default offset is the scroll offset of this view.</p> 15276 * 15277 * @return the vertical offset of the scrollbar's thumb 15278 * 15279 * @see #computeVerticalScrollRange() 15280 * @see #computeVerticalScrollExtent() 15281 * @see android.widget.ScrollBarDrawable 15282 */ 15283 protected int computeVerticalScrollOffset() { 15284 return mScrollY; 15285 } 15286 15287 /** 15288 * <p>Compute the vertical extent of the vertical scrollbar's thumb 15289 * within the vertical range. This value is used to compute the length 15290 * of the thumb within the scrollbar's track.</p> 15291 * 15292 * <p>The range is expressed in arbitrary units that must be the same as the 15293 * units used by {@link #computeVerticalScrollRange()} and 15294 * {@link #computeVerticalScrollOffset()}.</p> 15295 * 15296 * <p>The default extent is the drawing height of this view.</p> 15297 * 15298 * @return the vertical extent of the scrollbar's thumb 15299 * 15300 * @see #computeVerticalScrollRange() 15301 * @see #computeVerticalScrollOffset() 15302 * @see android.widget.ScrollBarDrawable 15303 */ 15304 protected int computeVerticalScrollExtent() { 15305 return getHeight(); 15306 } 15307 15308 /** 15309 * Check if this view can be scrolled horizontally in a certain direction. 15310 * 15311 * @param direction Negative to check scrolling left, positive to check scrolling right. 15312 * @return true if this view can be scrolled in the specified direction, false otherwise. 15313 */ 15314 public boolean canScrollHorizontally(int direction) { 15315 final int offset = computeHorizontalScrollOffset(); 15316 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 15317 if (range == 0) return false; 15318 if (direction < 0) { 15319 return offset > 0; 15320 } else { 15321 return offset < range - 1; 15322 } 15323 } 15324 15325 /** 15326 * Check if this view can be scrolled vertically in a certain direction. 15327 * 15328 * @param direction Negative to check scrolling up, positive to check scrolling down. 15329 * @return true if this view can be scrolled in the specified direction, false otherwise. 15330 */ 15331 public boolean canScrollVertically(int direction) { 15332 final int offset = computeVerticalScrollOffset(); 15333 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 15334 if (range == 0) return false; 15335 if (direction < 0) { 15336 return offset > 0; 15337 } else { 15338 return offset < range - 1; 15339 } 15340 } 15341 15342 void getScrollIndicatorBounds(@NonNull Rect out) { 15343 out.left = mScrollX; 15344 out.right = mScrollX + mRight - mLeft; 15345 out.top = mScrollY; 15346 out.bottom = mScrollY + mBottom - mTop; 15347 } 15348 15349 private void onDrawScrollIndicators(Canvas c) { 15350 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 15351 // No scroll indicators enabled. 15352 return; 15353 } 15354 15355 final Drawable dr = mScrollIndicatorDrawable; 15356 if (dr == null) { 15357 // Scroll indicators aren't supported here. 15358 return; 15359 } 15360 15361 final int h = dr.getIntrinsicHeight(); 15362 final int w = dr.getIntrinsicWidth(); 15363 final Rect rect = mAttachInfo.mTmpInvalRect; 15364 getScrollIndicatorBounds(rect); 15365 15366 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 15367 final boolean canScrollUp = canScrollVertically(-1); 15368 if (canScrollUp) { 15369 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 15370 dr.draw(c); 15371 } 15372 } 15373 15374 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 15375 final boolean canScrollDown = canScrollVertically(1); 15376 if (canScrollDown) { 15377 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 15378 dr.draw(c); 15379 } 15380 } 15381 15382 final int leftRtl; 15383 final int rightRtl; 15384 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15385 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 15386 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 15387 } else { 15388 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 15389 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 15390 } 15391 15392 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 15393 if ((mPrivateFlags3 & leftMask) != 0) { 15394 final boolean canScrollLeft = canScrollHorizontally(-1); 15395 if (canScrollLeft) { 15396 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 15397 dr.draw(c); 15398 } 15399 } 15400 15401 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 15402 if ((mPrivateFlags3 & rightMask) != 0) { 15403 final boolean canScrollRight = canScrollHorizontally(1); 15404 if (canScrollRight) { 15405 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 15406 dr.draw(c); 15407 } 15408 } 15409 } 15410 15411 private void getHorizontalScrollBarBounds(Rect bounds) { 15412 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 15413 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 15414 && !isVerticalScrollBarHidden(); 15415 final int size = getHorizontalScrollbarHeight(); 15416 final int verticalScrollBarGap = drawVerticalScrollBar ? 15417 getVerticalScrollbarWidth() : 0; 15418 final int width = mRight - mLeft; 15419 final int height = mBottom - mTop; 15420 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 15421 bounds.left = mScrollX + (mPaddingLeft & inside); 15422 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 15423 bounds.bottom = bounds.top + size; 15424 } 15425 15426 private void getVerticalScrollBarBounds(Rect bounds) { 15427 if (mRoundScrollbarRenderer == null) { 15428 getStraightVerticalScrollBarBounds(bounds); 15429 } else { 15430 getRoundVerticalScrollBarBounds(bounds); 15431 } 15432 } 15433 15434 private void getRoundVerticalScrollBarBounds(Rect bounds) { 15435 final int width = mRight - mLeft; 15436 final int height = mBottom - mTop; 15437 // Do not take padding into account as we always want the scrollbars 15438 // to hug the screen for round wearable devices. 15439 bounds.left = mScrollX; 15440 bounds.top = mScrollY; 15441 bounds.right = bounds.left + width; 15442 bounds.bottom = mScrollY + height; 15443 } 15444 15445 private void getStraightVerticalScrollBarBounds(Rect bounds) { 15446 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 15447 final int size = getVerticalScrollbarWidth(); 15448 int verticalScrollbarPosition = mVerticalScrollbarPosition; 15449 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 15450 verticalScrollbarPosition = isLayoutRtl() ? 15451 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 15452 } 15453 final int width = mRight - mLeft; 15454 final int height = mBottom - mTop; 15455 switch (verticalScrollbarPosition) { 15456 default: 15457 case SCROLLBAR_POSITION_RIGHT: 15458 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 15459 break; 15460 case SCROLLBAR_POSITION_LEFT: 15461 bounds.left = mScrollX + (mUserPaddingLeft & inside); 15462 break; 15463 } 15464 bounds.top = mScrollY + (mPaddingTop & inside); 15465 bounds.right = bounds.left + size; 15466 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 15467 } 15468 15469 /** 15470 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 15471 * scrollbars are painted only if they have been awakened first.</p> 15472 * 15473 * @param canvas the canvas on which to draw the scrollbars 15474 * 15475 * @see #awakenScrollBars(int) 15476 */ 15477 protected final void onDrawScrollBars(Canvas canvas) { 15478 // scrollbars are drawn only when the animation is running 15479 final ScrollabilityCache cache = mScrollCache; 15480 15481 if (cache != null) { 15482 15483 int state = cache.state; 15484 15485 if (state == ScrollabilityCache.OFF) { 15486 return; 15487 } 15488 15489 boolean invalidate = false; 15490 15491 if (state == ScrollabilityCache.FADING) { 15492 // We're fading -- get our fade interpolation 15493 if (cache.interpolatorValues == null) { 15494 cache.interpolatorValues = new float[1]; 15495 } 15496 15497 float[] values = cache.interpolatorValues; 15498 15499 // Stops the animation if we're done 15500 if (cache.scrollBarInterpolator.timeToValues(values) == 15501 Interpolator.Result.FREEZE_END) { 15502 cache.state = ScrollabilityCache.OFF; 15503 } else { 15504 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 15505 } 15506 15507 // This will make the scroll bars inval themselves after 15508 // drawing. We only want this when we're fading so that 15509 // we prevent excessive redraws 15510 invalidate = true; 15511 } else { 15512 // We're just on -- but we may have been fading before so 15513 // reset alpha 15514 cache.scrollBar.mutate().setAlpha(255); 15515 } 15516 15517 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 15518 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 15519 && !isVerticalScrollBarHidden(); 15520 15521 // Fork out the scroll bar drawing for round wearable devices. 15522 if (mRoundScrollbarRenderer != null) { 15523 if (drawVerticalScrollBar) { 15524 final Rect bounds = cache.mScrollBarBounds; 15525 getVerticalScrollBarBounds(bounds); 15526 mRoundScrollbarRenderer.drawRoundScrollbars( 15527 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 15528 if (invalidate) { 15529 invalidate(); 15530 } 15531 } 15532 // Do not draw horizontal scroll bars for round wearable devices. 15533 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 15534 final ScrollBarDrawable scrollBar = cache.scrollBar; 15535 15536 if (drawHorizontalScrollBar) { 15537 scrollBar.setParameters(computeHorizontalScrollRange(), 15538 computeHorizontalScrollOffset(), 15539 computeHorizontalScrollExtent(), false); 15540 final Rect bounds = cache.mScrollBarBounds; 15541 getHorizontalScrollBarBounds(bounds); 15542 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 15543 bounds.right, bounds.bottom); 15544 if (invalidate) { 15545 invalidate(bounds); 15546 } 15547 } 15548 15549 if (drawVerticalScrollBar) { 15550 scrollBar.setParameters(computeVerticalScrollRange(), 15551 computeVerticalScrollOffset(), 15552 computeVerticalScrollExtent(), true); 15553 final Rect bounds = cache.mScrollBarBounds; 15554 getVerticalScrollBarBounds(bounds); 15555 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 15556 bounds.right, bounds.bottom); 15557 if (invalidate) { 15558 invalidate(bounds); 15559 } 15560 } 15561 } 15562 } 15563 } 15564 15565 /** 15566 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 15567 * FastScroller is visible. 15568 * @return whether to temporarily hide the vertical scrollbar 15569 * @hide 15570 */ 15571 protected boolean isVerticalScrollBarHidden() { 15572 return false; 15573 } 15574 15575 /** 15576 * <p>Draw the horizontal scrollbar if 15577 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 15578 * 15579 * @param canvas the canvas on which to draw the scrollbar 15580 * @param scrollBar the scrollbar's drawable 15581 * 15582 * @see #isHorizontalScrollBarEnabled() 15583 * @see #computeHorizontalScrollRange() 15584 * @see #computeHorizontalScrollExtent() 15585 * @see #computeHorizontalScrollOffset() 15586 * @see android.widget.ScrollBarDrawable 15587 * @hide 15588 */ 15589 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 15590 int l, int t, int r, int b) { 15591 scrollBar.setBounds(l, t, r, b); 15592 scrollBar.draw(canvas); 15593 } 15594 15595 /** 15596 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 15597 * returns true.</p> 15598 * 15599 * @param canvas the canvas on which to draw the scrollbar 15600 * @param scrollBar the scrollbar's drawable 15601 * 15602 * @see #isVerticalScrollBarEnabled() 15603 * @see #computeVerticalScrollRange() 15604 * @see #computeVerticalScrollExtent() 15605 * @see #computeVerticalScrollOffset() 15606 * @see android.widget.ScrollBarDrawable 15607 * @hide 15608 */ 15609 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 15610 int l, int t, int r, int b) { 15611 scrollBar.setBounds(l, t, r, b); 15612 scrollBar.draw(canvas); 15613 } 15614 15615 /** 15616 * Implement this to do your drawing. 15617 * 15618 * @param canvas the canvas on which the background will be drawn 15619 */ 15620 protected void onDraw(Canvas canvas) { 15621 } 15622 15623 /* 15624 * Caller is responsible for calling requestLayout if necessary. 15625 * (This allows addViewInLayout to not request a new layout.) 15626 */ 15627 void assignParent(ViewParent parent) { 15628 if (mParent == null) { 15629 mParent = parent; 15630 } else if (parent == null) { 15631 mParent = null; 15632 } else { 15633 throw new RuntimeException("view " + this + " being added, but" 15634 + " it already has a parent"); 15635 } 15636 } 15637 15638 /** 15639 * This is called when the view is attached to a window. At this point it 15640 * has a Surface and will start drawing. Note that this function is 15641 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 15642 * however it may be called any time before the first onDraw -- including 15643 * before or after {@link #onMeasure(int, int)}. 15644 * 15645 * @see #onDetachedFromWindow() 15646 */ 15647 @CallSuper 15648 protected void onAttachedToWindow() { 15649 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 15650 mParent.requestTransparentRegion(this); 15651 } 15652 15653 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15654 15655 jumpDrawablesToCurrentState(); 15656 15657 resetSubtreeAccessibilityStateChanged(); 15658 15659 // rebuild, since Outline not maintained while View is detached 15660 rebuildOutline(); 15661 15662 if (isFocused()) { 15663 InputMethodManager imm = InputMethodManager.peekInstance(); 15664 if (imm != null) { 15665 imm.focusIn(this); 15666 } 15667 } 15668 } 15669 15670 /** 15671 * Resolve all RTL related properties. 15672 * 15673 * @return true if resolution of RTL properties has been done 15674 * 15675 * @hide 15676 */ 15677 public boolean resolveRtlPropertiesIfNeeded() { 15678 if (!needRtlPropertiesResolution()) return false; 15679 15680 // Order is important here: LayoutDirection MUST be resolved first 15681 if (!isLayoutDirectionResolved()) { 15682 resolveLayoutDirection(); 15683 resolveLayoutParams(); 15684 } 15685 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 15686 if (!isTextDirectionResolved()) { 15687 resolveTextDirection(); 15688 } 15689 if (!isTextAlignmentResolved()) { 15690 resolveTextAlignment(); 15691 } 15692 // Should resolve Drawables before Padding because we need the layout direction of the 15693 // Drawable to correctly resolve Padding. 15694 if (!areDrawablesResolved()) { 15695 resolveDrawables(); 15696 } 15697 if (!isPaddingResolved()) { 15698 resolvePadding(); 15699 } 15700 onRtlPropertiesChanged(getLayoutDirection()); 15701 return true; 15702 } 15703 15704 /** 15705 * Reset resolution of all RTL related properties. 15706 * 15707 * @hide 15708 */ 15709 public void resetRtlProperties() { 15710 resetResolvedLayoutDirection(); 15711 resetResolvedTextDirection(); 15712 resetResolvedTextAlignment(); 15713 resetResolvedPadding(); 15714 resetResolvedDrawables(); 15715 } 15716 15717 /** 15718 * @see #onScreenStateChanged(int) 15719 */ 15720 void dispatchScreenStateChanged(int screenState) { 15721 onScreenStateChanged(screenState); 15722 } 15723 15724 /** 15725 * This method is called whenever the state of the screen this view is 15726 * attached to changes. A state change will usually occurs when the screen 15727 * turns on or off (whether it happens automatically or the user does it 15728 * manually.) 15729 * 15730 * @param screenState The new state of the screen. Can be either 15731 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 15732 */ 15733 public void onScreenStateChanged(int screenState) { 15734 } 15735 15736 /** 15737 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 15738 */ 15739 private boolean hasRtlSupport() { 15740 return mContext.getApplicationInfo().hasRtlSupport(); 15741 } 15742 15743 /** 15744 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 15745 * RTL not supported) 15746 */ 15747 private boolean isRtlCompatibilityMode() { 15748 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 15749 return targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport(); 15750 } 15751 15752 /** 15753 * @return true if RTL properties need resolution. 15754 * 15755 */ 15756 private boolean needRtlPropertiesResolution() { 15757 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 15758 } 15759 15760 /** 15761 * Called when any RTL property (layout direction or text direction or text alignment) has 15762 * been changed. 15763 * 15764 * Subclasses need to override this method to take care of cached information that depends on the 15765 * resolved layout direction, or to inform child views that inherit their layout direction. 15766 * 15767 * The default implementation does nothing. 15768 * 15769 * @param layoutDirection the direction of the layout 15770 * 15771 * @see #LAYOUT_DIRECTION_LTR 15772 * @see #LAYOUT_DIRECTION_RTL 15773 */ 15774 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 15775 } 15776 15777 /** 15778 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 15779 * that the parent directionality can and will be resolved before its children. 15780 * 15781 * @return true if resolution has been done, false otherwise. 15782 * 15783 * @hide 15784 */ 15785 public boolean resolveLayoutDirection() { 15786 // Clear any previous layout direction resolution 15787 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15788 15789 if (hasRtlSupport()) { 15790 // Set resolved depending on layout direction 15791 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 15792 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 15793 case LAYOUT_DIRECTION_INHERIT: 15794 // We cannot resolve yet. LTR is by default and let the resolution happen again 15795 // later to get the correct resolved value 15796 if (!canResolveLayoutDirection()) return false; 15797 15798 // Parent has not yet resolved, LTR is still the default 15799 try { 15800 if (!mParent.isLayoutDirectionResolved()) return false; 15801 15802 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15803 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15804 } 15805 } catch (AbstractMethodError e) { 15806 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15807 " does not fully implement ViewParent", e); 15808 } 15809 break; 15810 case LAYOUT_DIRECTION_RTL: 15811 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15812 break; 15813 case LAYOUT_DIRECTION_LOCALE: 15814 if((LAYOUT_DIRECTION_RTL == 15815 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 15816 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15817 } 15818 break; 15819 default: 15820 // Nothing to do, LTR by default 15821 } 15822 } 15823 15824 // Set to resolved 15825 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 15826 return true; 15827 } 15828 15829 /** 15830 * Check if layout direction resolution can be done. 15831 * 15832 * @return true if layout direction resolution can be done otherwise return false. 15833 */ 15834 public boolean canResolveLayoutDirection() { 15835 switch (getRawLayoutDirection()) { 15836 case LAYOUT_DIRECTION_INHERIT: 15837 if (mParent != null) { 15838 try { 15839 return mParent.canResolveLayoutDirection(); 15840 } catch (AbstractMethodError e) { 15841 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15842 " does not fully implement ViewParent", e); 15843 } 15844 } 15845 return false; 15846 15847 default: 15848 return true; 15849 } 15850 } 15851 15852 /** 15853 * Reset the resolved layout direction. Layout direction will be resolved during a call to 15854 * {@link #onMeasure(int, int)}. 15855 * 15856 * @hide 15857 */ 15858 public void resetResolvedLayoutDirection() { 15859 // Reset the current resolved bits 15860 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15861 } 15862 15863 /** 15864 * @return true if the layout direction is inherited. 15865 * 15866 * @hide 15867 */ 15868 public boolean isLayoutDirectionInherited() { 15869 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 15870 } 15871 15872 /** 15873 * @return true if layout direction has been resolved. 15874 */ 15875 public boolean isLayoutDirectionResolved() { 15876 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 15877 } 15878 15879 /** 15880 * Return if padding has been resolved 15881 * 15882 * @hide 15883 */ 15884 boolean isPaddingResolved() { 15885 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 15886 } 15887 15888 /** 15889 * Resolves padding depending on layout direction, if applicable, and 15890 * recomputes internal padding values to adjust for scroll bars. 15891 * 15892 * @hide 15893 */ 15894 public void resolvePadding() { 15895 final int resolvedLayoutDirection = getLayoutDirection(); 15896 15897 if (!isRtlCompatibilityMode()) { 15898 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 15899 // If start / end padding are defined, they will be resolved (hence overriding) to 15900 // left / right or right / left depending on the resolved layout direction. 15901 // If start / end padding are not defined, use the left / right ones. 15902 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 15903 Rect padding = sThreadLocal.get(); 15904 if (padding == null) { 15905 padding = new Rect(); 15906 sThreadLocal.set(padding); 15907 } 15908 mBackground.getPadding(padding); 15909 if (!mLeftPaddingDefined) { 15910 mUserPaddingLeftInitial = padding.left; 15911 } 15912 if (!mRightPaddingDefined) { 15913 mUserPaddingRightInitial = padding.right; 15914 } 15915 } 15916 switch (resolvedLayoutDirection) { 15917 case LAYOUT_DIRECTION_RTL: 15918 if (mUserPaddingStart != UNDEFINED_PADDING) { 15919 mUserPaddingRight = mUserPaddingStart; 15920 } else { 15921 mUserPaddingRight = mUserPaddingRightInitial; 15922 } 15923 if (mUserPaddingEnd != UNDEFINED_PADDING) { 15924 mUserPaddingLeft = mUserPaddingEnd; 15925 } else { 15926 mUserPaddingLeft = mUserPaddingLeftInitial; 15927 } 15928 break; 15929 case LAYOUT_DIRECTION_LTR: 15930 default: 15931 if (mUserPaddingStart != UNDEFINED_PADDING) { 15932 mUserPaddingLeft = mUserPaddingStart; 15933 } else { 15934 mUserPaddingLeft = mUserPaddingLeftInitial; 15935 } 15936 if (mUserPaddingEnd != UNDEFINED_PADDING) { 15937 mUserPaddingRight = mUserPaddingEnd; 15938 } else { 15939 mUserPaddingRight = mUserPaddingRightInitial; 15940 } 15941 } 15942 15943 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 15944 } 15945 15946 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 15947 onRtlPropertiesChanged(resolvedLayoutDirection); 15948 15949 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 15950 } 15951 15952 /** 15953 * Reset the resolved layout direction. 15954 * 15955 * @hide 15956 */ 15957 public void resetResolvedPadding() { 15958 resetResolvedPaddingInternal(); 15959 } 15960 15961 /** 15962 * Used when we only want to reset *this* view's padding and not trigger overrides 15963 * in ViewGroup that reset children too. 15964 */ 15965 void resetResolvedPaddingInternal() { 15966 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 15967 } 15968 15969 /** 15970 * This is called when the view is detached from a window. At this point it 15971 * no longer has a surface for drawing. 15972 * 15973 * @see #onAttachedToWindow() 15974 */ 15975 @CallSuper 15976 protected void onDetachedFromWindow() { 15977 } 15978 15979 /** 15980 * This is a framework-internal mirror of onDetachedFromWindow() that's called 15981 * after onDetachedFromWindow(). 15982 * 15983 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 15984 * The super method should be called at the end of the overridden method to ensure 15985 * subclasses are destroyed first 15986 * 15987 * @hide 15988 */ 15989 @CallSuper 15990 protected void onDetachedFromWindowInternal() { 15991 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 15992 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15993 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 15994 15995 removeUnsetPressCallback(); 15996 removeLongPressCallback(); 15997 removePerformClickCallback(); 15998 removeSendViewScrolledAccessibilityEventCallback(); 15999 stopNestedScroll(); 16000 16001 // Anything that started animating right before detach should already 16002 // be in its final state when re-attached. 16003 jumpDrawablesToCurrentState(); 16004 16005 destroyDrawingCache(); 16006 16007 cleanupDraw(); 16008 mCurrentAnimation = null; 16009 16010 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 16011 hideTooltip(); 16012 } 16013 } 16014 16015 private void cleanupDraw() { 16016 resetDisplayList(); 16017 if (mAttachInfo != null) { 16018 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 16019 } 16020 } 16021 16022 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 16023 } 16024 16025 /** 16026 * @return The number of times this view has been attached to a window 16027 */ 16028 protected int getWindowAttachCount() { 16029 return mWindowAttachCount; 16030 } 16031 16032 /** 16033 * Retrieve a unique token identifying the window this view is attached to. 16034 * @return Return the window's token for use in 16035 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 16036 */ 16037 public IBinder getWindowToken() { 16038 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 16039 } 16040 16041 /** 16042 * Retrieve the {@link WindowId} for the window this view is 16043 * currently attached to. 16044 */ 16045 public WindowId getWindowId() { 16046 if (mAttachInfo == null) { 16047 return null; 16048 } 16049 if (mAttachInfo.mWindowId == null) { 16050 try { 16051 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 16052 mAttachInfo.mWindowToken); 16053 mAttachInfo.mWindowId = new WindowId( 16054 mAttachInfo.mIWindowId); 16055 } catch (RemoteException e) { 16056 } 16057 } 16058 return mAttachInfo.mWindowId; 16059 } 16060 16061 /** 16062 * Retrieve a unique token identifying the top-level "real" window of 16063 * the window that this view is attached to. That is, this is like 16064 * {@link #getWindowToken}, except if the window this view in is a panel 16065 * window (attached to another containing window), then the token of 16066 * the containing window is returned instead. 16067 * 16068 * @return Returns the associated window token, either 16069 * {@link #getWindowToken()} or the containing window's token. 16070 */ 16071 public IBinder getApplicationWindowToken() { 16072 AttachInfo ai = mAttachInfo; 16073 if (ai != null) { 16074 IBinder appWindowToken = ai.mPanelParentWindowToken; 16075 if (appWindowToken == null) { 16076 appWindowToken = ai.mWindowToken; 16077 } 16078 return appWindowToken; 16079 } 16080 return null; 16081 } 16082 16083 /** 16084 * Gets the logical display to which the view's window has been attached. 16085 * 16086 * @return The logical display, or null if the view is not currently attached to a window. 16087 */ 16088 public Display getDisplay() { 16089 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 16090 } 16091 16092 /** 16093 * Retrieve private session object this view hierarchy is using to 16094 * communicate with the window manager. 16095 * @return the session object to communicate with the window manager 16096 */ 16097 /*package*/ IWindowSession getWindowSession() { 16098 return mAttachInfo != null ? mAttachInfo.mSession : null; 16099 } 16100 16101 /** 16102 * Return the visibility value of the least visible component passed. 16103 */ 16104 int combineVisibility(int vis1, int vis2) { 16105 // This works because VISIBLE < INVISIBLE < GONE. 16106 return Math.max(vis1, vis2); 16107 } 16108 16109 /** 16110 * @param info the {@link android.view.View.AttachInfo} to associated with 16111 * this view 16112 */ 16113 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 16114 mAttachInfo = info; 16115 if (mOverlay != null) { 16116 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 16117 } 16118 mWindowAttachCount++; 16119 // We will need to evaluate the drawable state at least once. 16120 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 16121 if (mFloatingTreeObserver != null) { 16122 info.mTreeObserver.merge(mFloatingTreeObserver); 16123 mFloatingTreeObserver = null; 16124 } 16125 16126 registerPendingFrameMetricsObservers(); 16127 16128 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 16129 mAttachInfo.mScrollContainers.add(this); 16130 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 16131 } 16132 // Transfer all pending runnables. 16133 if (mRunQueue != null) { 16134 mRunQueue.executeActions(info.mHandler); 16135 mRunQueue = null; 16136 } 16137 performCollectViewAttributes(mAttachInfo, visibility); 16138 onAttachedToWindow(); 16139 16140 ListenerInfo li = mListenerInfo; 16141 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 16142 li != null ? li.mOnAttachStateChangeListeners : null; 16143 if (listeners != null && listeners.size() > 0) { 16144 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 16145 // perform the dispatching. The iterator is a safe guard against listeners that 16146 // could mutate the list by calling the various add/remove methods. This prevents 16147 // the array from being modified while we iterate it. 16148 for (OnAttachStateChangeListener listener : listeners) { 16149 listener.onViewAttachedToWindow(this); 16150 } 16151 } 16152 16153 int vis = info.mWindowVisibility; 16154 if (vis != GONE) { 16155 onWindowVisibilityChanged(vis); 16156 if (isShown()) { 16157 // Calling onVisibilityAggregated directly here since the subtree will also 16158 // receive dispatchAttachedToWindow and this same call 16159 onVisibilityAggregated(vis == VISIBLE); 16160 } 16161 } 16162 16163 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 16164 // As all views in the subtree will already receive dispatchAttachedToWindow 16165 // traversing the subtree again here is not desired. 16166 onVisibilityChanged(this, visibility); 16167 16168 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 16169 // If nobody has evaluated the drawable state yet, then do it now. 16170 refreshDrawableState(); 16171 } 16172 needGlobalAttributesUpdate(false); 16173 } 16174 16175 void dispatchDetachedFromWindow() { 16176 AttachInfo info = mAttachInfo; 16177 if (info != null) { 16178 int vis = info.mWindowVisibility; 16179 if (vis != GONE) { 16180 onWindowVisibilityChanged(GONE); 16181 if (isShown()) { 16182 // Invoking onVisibilityAggregated directly here since the subtree 16183 // will also receive detached from window 16184 onVisibilityAggregated(false); 16185 } 16186 } 16187 } 16188 16189 onDetachedFromWindow(); 16190 onDetachedFromWindowInternal(); 16191 16192 InputMethodManager imm = InputMethodManager.peekInstance(); 16193 if (imm != null) { 16194 imm.onViewDetachedFromWindow(this); 16195 } 16196 16197 ListenerInfo li = mListenerInfo; 16198 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 16199 li != null ? li.mOnAttachStateChangeListeners : null; 16200 if (listeners != null && listeners.size() > 0) { 16201 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 16202 // perform the dispatching. The iterator is a safe guard against listeners that 16203 // could mutate the list by calling the various add/remove methods. This prevents 16204 // the array from being modified while we iterate it. 16205 for (OnAttachStateChangeListener listener : listeners) { 16206 listener.onViewDetachedFromWindow(this); 16207 } 16208 } 16209 16210 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 16211 mAttachInfo.mScrollContainers.remove(this); 16212 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 16213 } 16214 16215 mAttachInfo = null; 16216 if (mOverlay != null) { 16217 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 16218 } 16219 } 16220 16221 /** 16222 * Cancel any deferred high-level input events that were previously posted to the event queue. 16223 * 16224 * <p>Many views post high-level events such as click handlers to the event queue 16225 * to run deferred in order to preserve a desired user experience - clearing visible 16226 * pressed states before executing, etc. This method will abort any events of this nature 16227 * that are currently in flight.</p> 16228 * 16229 * <p>Custom views that generate their own high-level deferred input events should override 16230 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 16231 * 16232 * <p>This will also cancel pending input events for any child views.</p> 16233 * 16234 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 16235 * This will not impact newer events posted after this call that may occur as a result of 16236 * lower-level input events still waiting in the queue. If you are trying to prevent 16237 * double-submitted events for the duration of some sort of asynchronous transaction 16238 * you should also take other steps to protect against unexpected double inputs e.g. calling 16239 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 16240 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 16241 */ 16242 public final void cancelPendingInputEvents() { 16243 dispatchCancelPendingInputEvents(); 16244 } 16245 16246 /** 16247 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 16248 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 16249 */ 16250 void dispatchCancelPendingInputEvents() { 16251 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 16252 onCancelPendingInputEvents(); 16253 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 16254 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 16255 " did not call through to super.onCancelPendingInputEvents()"); 16256 } 16257 } 16258 16259 /** 16260 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 16261 * a parent view. 16262 * 16263 * <p>This method is responsible for removing any pending high-level input events that were 16264 * posted to the event queue to run later. Custom view classes that post their own deferred 16265 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 16266 * {@link android.os.Handler} should override this method, call 16267 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 16268 * </p> 16269 */ 16270 public void onCancelPendingInputEvents() { 16271 removePerformClickCallback(); 16272 cancelLongPress(); 16273 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 16274 } 16275 16276 /** 16277 * Store this view hierarchy's frozen state into the given container. 16278 * 16279 * @param container The SparseArray in which to save the view's state. 16280 * 16281 * @see #restoreHierarchyState(android.util.SparseArray) 16282 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16283 * @see #onSaveInstanceState() 16284 */ 16285 public void saveHierarchyState(SparseArray<Parcelable> container) { 16286 dispatchSaveInstanceState(container); 16287 } 16288 16289 /** 16290 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 16291 * this view and its children. May be overridden to modify how freezing happens to a 16292 * view's children; for example, some views may want to not store state for their children. 16293 * 16294 * @param container The SparseArray in which to save the view's state. 16295 * 16296 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16297 * @see #saveHierarchyState(android.util.SparseArray) 16298 * @see #onSaveInstanceState() 16299 */ 16300 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 16301 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 16302 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 16303 Parcelable state = onSaveInstanceState(); 16304 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 16305 throw new IllegalStateException( 16306 "Derived class did not call super.onSaveInstanceState()"); 16307 } 16308 if (state != null) { 16309 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 16310 // + ": " + state); 16311 container.put(mID, state); 16312 } 16313 } 16314 } 16315 16316 /** 16317 * Hook allowing a view to generate a representation of its internal state 16318 * that can later be used to create a new instance with that same state. 16319 * This state should only contain information that is not persistent or can 16320 * not be reconstructed later. For example, you will never store your 16321 * current position on screen because that will be computed again when a 16322 * new instance of the view is placed in its view hierarchy. 16323 * <p> 16324 * Some examples of things you may store here: the current cursor position 16325 * in a text view (but usually not the text itself since that is stored in a 16326 * content provider or other persistent storage), the currently selected 16327 * item in a list view. 16328 * 16329 * @return Returns a Parcelable object containing the view's current dynamic 16330 * state, or null if there is nothing interesting to save. The 16331 * default implementation returns null. 16332 * @see #onRestoreInstanceState(android.os.Parcelable) 16333 * @see #saveHierarchyState(android.util.SparseArray) 16334 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16335 * @see #setSaveEnabled(boolean) 16336 */ 16337 @CallSuper 16338 protected Parcelable onSaveInstanceState() { 16339 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 16340 if (mStartActivityRequestWho != null) { 16341 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 16342 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 16343 return state; 16344 } 16345 return BaseSavedState.EMPTY_STATE; 16346 } 16347 16348 /** 16349 * Restore this view hierarchy's frozen state from the given container. 16350 * 16351 * @param container The SparseArray which holds previously frozen states. 16352 * 16353 * @see #saveHierarchyState(android.util.SparseArray) 16354 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16355 * @see #onRestoreInstanceState(android.os.Parcelable) 16356 */ 16357 public void restoreHierarchyState(SparseArray<Parcelable> container) { 16358 dispatchRestoreInstanceState(container); 16359 } 16360 16361 /** 16362 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 16363 * state for this view and its children. May be overridden to modify how restoring 16364 * happens to a view's children; for example, some views may want to not store state 16365 * for their children. 16366 * 16367 * @param container The SparseArray which holds previously saved state. 16368 * 16369 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16370 * @see #restoreHierarchyState(android.util.SparseArray) 16371 * @see #onRestoreInstanceState(android.os.Parcelable) 16372 */ 16373 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 16374 if (mID != NO_ID) { 16375 Parcelable state = container.get(mID); 16376 if (state != null) { 16377 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 16378 // + ": " + state); 16379 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 16380 onRestoreInstanceState(state); 16381 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 16382 throw new IllegalStateException( 16383 "Derived class did not call super.onRestoreInstanceState()"); 16384 } 16385 } 16386 } 16387 } 16388 16389 /** 16390 * Hook allowing a view to re-apply a representation of its internal state that had previously 16391 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 16392 * null state. 16393 * 16394 * @param state The frozen state that had previously been returned by 16395 * {@link #onSaveInstanceState}. 16396 * 16397 * @see #onSaveInstanceState() 16398 * @see #restoreHierarchyState(android.util.SparseArray) 16399 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16400 */ 16401 @CallSuper 16402 protected void onRestoreInstanceState(Parcelable state) { 16403 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 16404 if (state != null && !(state instanceof AbsSavedState)) { 16405 throw new IllegalArgumentException("Wrong state class, expecting View State but " 16406 + "received " + state.getClass().toString() + " instead. This usually happens " 16407 + "when two views of different type have the same id in the same hierarchy. " 16408 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 16409 + "other views do not use the same id."); 16410 } 16411 if (state != null && state instanceof BaseSavedState) { 16412 mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved; 16413 } 16414 } 16415 16416 /** 16417 * <p>Return the time at which the drawing of the view hierarchy started.</p> 16418 * 16419 * @return the drawing start time in milliseconds 16420 */ 16421 public long getDrawingTime() { 16422 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 16423 } 16424 16425 /** 16426 * <p>Enables or disables the duplication of the parent's state into this view. When 16427 * duplication is enabled, this view gets its drawable state from its parent rather 16428 * than from its own internal properties.</p> 16429 * 16430 * <p>Note: in the current implementation, setting this property to true after the 16431 * view was added to a ViewGroup might have no effect at all. This property should 16432 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 16433 * 16434 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 16435 * property is enabled, an exception will be thrown.</p> 16436 * 16437 * <p>Note: if the child view uses and updates additional states which are unknown to the 16438 * parent, these states should not be affected by this method.</p> 16439 * 16440 * @param enabled True to enable duplication of the parent's drawable state, false 16441 * to disable it. 16442 * 16443 * @see #getDrawableState() 16444 * @see #isDuplicateParentStateEnabled() 16445 */ 16446 public void setDuplicateParentStateEnabled(boolean enabled) { 16447 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 16448 } 16449 16450 /** 16451 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 16452 * 16453 * @return True if this view's drawable state is duplicated from the parent, 16454 * false otherwise 16455 * 16456 * @see #getDrawableState() 16457 * @see #setDuplicateParentStateEnabled(boolean) 16458 */ 16459 public boolean isDuplicateParentStateEnabled() { 16460 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 16461 } 16462 16463 /** 16464 * <p>Specifies the type of layer backing this view. The layer can be 16465 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16466 * {@link #LAYER_TYPE_HARDWARE}.</p> 16467 * 16468 * <p>A layer is associated with an optional {@link android.graphics.Paint} 16469 * instance that controls how the layer is composed on screen. The following 16470 * properties of the paint are taken into account when composing the layer:</p> 16471 * <ul> 16472 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 16473 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 16474 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 16475 * </ul> 16476 * 16477 * <p>If this view has an alpha value set to < 1.0 by calling 16478 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 16479 * by this view's alpha value.</p> 16480 * 16481 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 16482 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 16483 * for more information on when and how to use layers.</p> 16484 * 16485 * @param layerType The type of layer to use with this view, must be one of 16486 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16487 * {@link #LAYER_TYPE_HARDWARE} 16488 * @param paint The paint used to compose the layer. This argument is optional 16489 * and can be null. It is ignored when the layer type is 16490 * {@link #LAYER_TYPE_NONE} 16491 * 16492 * @see #getLayerType() 16493 * @see #LAYER_TYPE_NONE 16494 * @see #LAYER_TYPE_SOFTWARE 16495 * @see #LAYER_TYPE_HARDWARE 16496 * @see #setAlpha(float) 16497 * 16498 * @attr ref android.R.styleable#View_layerType 16499 */ 16500 public void setLayerType(int layerType, @Nullable Paint paint) { 16501 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 16502 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 16503 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 16504 } 16505 16506 boolean typeChanged = mRenderNode.setLayerType(layerType); 16507 16508 if (!typeChanged) { 16509 setLayerPaint(paint); 16510 return; 16511 } 16512 16513 if (layerType != LAYER_TYPE_SOFTWARE) { 16514 // Destroy any previous software drawing cache if present 16515 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 16516 // drawing cache created in View#draw when drawing to a SW canvas. 16517 destroyDrawingCache(); 16518 } 16519 16520 mLayerType = layerType; 16521 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 16522 mRenderNode.setLayerPaint(mLayerPaint); 16523 16524 // draw() behaves differently if we are on a layer, so we need to 16525 // invalidate() here 16526 invalidateParentCaches(); 16527 invalidate(true); 16528 } 16529 16530 /** 16531 * Updates the {@link Paint} object used with the current layer (used only if the current 16532 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 16533 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 16534 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 16535 * ensure that the view gets redrawn immediately. 16536 * 16537 * <p>A layer is associated with an optional {@link android.graphics.Paint} 16538 * instance that controls how the layer is composed on screen. The following 16539 * properties of the paint are taken into account when composing the layer:</p> 16540 * <ul> 16541 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 16542 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 16543 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 16544 * </ul> 16545 * 16546 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 16547 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 16548 * 16549 * @param paint The paint used to compose the layer. This argument is optional 16550 * and can be null. It is ignored when the layer type is 16551 * {@link #LAYER_TYPE_NONE} 16552 * 16553 * @see #setLayerType(int, android.graphics.Paint) 16554 */ 16555 public void setLayerPaint(@Nullable Paint paint) { 16556 int layerType = getLayerType(); 16557 if (layerType != LAYER_TYPE_NONE) { 16558 mLayerPaint = paint; 16559 if (layerType == LAYER_TYPE_HARDWARE) { 16560 if (mRenderNode.setLayerPaint(paint)) { 16561 invalidateViewProperty(false, false); 16562 } 16563 } else { 16564 invalidate(); 16565 } 16566 } 16567 } 16568 16569 /** 16570 * Indicates what type of layer is currently associated with this view. By default 16571 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 16572 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 16573 * for more information on the different types of layers. 16574 * 16575 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16576 * {@link #LAYER_TYPE_HARDWARE} 16577 * 16578 * @see #setLayerType(int, android.graphics.Paint) 16579 * @see #buildLayer() 16580 * @see #LAYER_TYPE_NONE 16581 * @see #LAYER_TYPE_SOFTWARE 16582 * @see #LAYER_TYPE_HARDWARE 16583 */ 16584 public int getLayerType() { 16585 return mLayerType; 16586 } 16587 16588 /** 16589 * Forces this view's layer to be created and this view to be rendered 16590 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 16591 * invoking this method will have no effect. 16592 * 16593 * This method can for instance be used to render a view into its layer before 16594 * starting an animation. If this view is complex, rendering into the layer 16595 * before starting the animation will avoid skipping frames. 16596 * 16597 * @throws IllegalStateException If this view is not attached to a window 16598 * 16599 * @see #setLayerType(int, android.graphics.Paint) 16600 */ 16601 public void buildLayer() { 16602 if (mLayerType == LAYER_TYPE_NONE) return; 16603 16604 final AttachInfo attachInfo = mAttachInfo; 16605 if (attachInfo == null) { 16606 throw new IllegalStateException("This view must be attached to a window first"); 16607 } 16608 16609 if (getWidth() == 0 || getHeight() == 0) { 16610 return; 16611 } 16612 16613 switch (mLayerType) { 16614 case LAYER_TYPE_HARDWARE: 16615 updateDisplayListIfDirty(); 16616 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 16617 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 16618 } 16619 break; 16620 case LAYER_TYPE_SOFTWARE: 16621 buildDrawingCache(true); 16622 break; 16623 } 16624 } 16625 16626 /** 16627 * Destroys all hardware rendering resources. This method is invoked 16628 * when the system needs to reclaim resources. Upon execution of this 16629 * method, you should free any OpenGL resources created by the view. 16630 * 16631 * Note: you <strong>must</strong> call 16632 * <code>super.destroyHardwareResources()</code> when overriding 16633 * this method. 16634 * 16635 * @hide 16636 */ 16637 @CallSuper 16638 protected void destroyHardwareResources() { 16639 // Although the Layer will be destroyed by RenderNode, we want to release 16640 // the staging display list, which is also a signal to RenderNode that it's 16641 // safe to free its copy of the display list as it knows that we will 16642 // push an updated DisplayList if we try to draw again 16643 resetDisplayList(); 16644 } 16645 16646 /** 16647 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 16648 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 16649 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 16650 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 16651 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 16652 * null.</p> 16653 * 16654 * <p>Enabling the drawing cache is similar to 16655 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 16656 * acceleration is turned off. When hardware acceleration is turned on, enabling the 16657 * drawing cache has no effect on rendering because the system uses a different mechanism 16658 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 16659 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 16660 * for information on how to enable software and hardware layers.</p> 16661 * 16662 * <p>This API can be used to manually generate 16663 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 16664 * {@link #getDrawingCache()}.</p> 16665 * 16666 * @param enabled true to enable the drawing cache, false otherwise 16667 * 16668 * @see #isDrawingCacheEnabled() 16669 * @see #getDrawingCache() 16670 * @see #buildDrawingCache() 16671 * @see #setLayerType(int, android.graphics.Paint) 16672 */ 16673 public void setDrawingCacheEnabled(boolean enabled) { 16674 mCachingFailed = false; 16675 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 16676 } 16677 16678 /** 16679 * <p>Indicates whether the drawing cache is enabled for this view.</p> 16680 * 16681 * @return true if the drawing cache is enabled 16682 * 16683 * @see #setDrawingCacheEnabled(boolean) 16684 * @see #getDrawingCache() 16685 */ 16686 @ViewDebug.ExportedProperty(category = "drawing") 16687 public boolean isDrawingCacheEnabled() { 16688 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 16689 } 16690 16691 /** 16692 * Debugging utility which recursively outputs the dirty state of a view and its 16693 * descendants. 16694 * 16695 * @hide 16696 */ 16697 @SuppressWarnings({"UnusedDeclaration"}) 16698 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 16699 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 16700 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 16701 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 16702 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 16703 if (clear) { 16704 mPrivateFlags &= clearMask; 16705 } 16706 if (this instanceof ViewGroup) { 16707 ViewGroup parent = (ViewGroup) this; 16708 final int count = parent.getChildCount(); 16709 for (int i = 0; i < count; i++) { 16710 final View child = parent.getChildAt(i); 16711 child.outputDirtyFlags(indent + " ", clear, clearMask); 16712 } 16713 } 16714 } 16715 16716 /** 16717 * This method is used by ViewGroup to cause its children to restore or recreate their 16718 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 16719 * to recreate its own display list, which would happen if it went through the normal 16720 * draw/dispatchDraw mechanisms. 16721 * 16722 * @hide 16723 */ 16724 protected void dispatchGetDisplayList() {} 16725 16726 /** 16727 * A view that is not attached or hardware accelerated cannot create a display list. 16728 * This method checks these conditions and returns the appropriate result. 16729 * 16730 * @return true if view has the ability to create a display list, false otherwise. 16731 * 16732 * @hide 16733 */ 16734 public boolean canHaveDisplayList() { 16735 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 16736 } 16737 16738 /** 16739 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 16740 * @hide 16741 */ 16742 @NonNull 16743 public RenderNode updateDisplayListIfDirty() { 16744 final RenderNode renderNode = mRenderNode; 16745 if (!canHaveDisplayList()) { 16746 // can't populate RenderNode, don't try 16747 return renderNode; 16748 } 16749 16750 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 16751 || !renderNode.isValid() 16752 || (mRecreateDisplayList)) { 16753 // Don't need to recreate the display list, just need to tell our 16754 // children to restore/recreate theirs 16755 if (renderNode.isValid() 16756 && !mRecreateDisplayList) { 16757 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16758 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16759 dispatchGetDisplayList(); 16760 16761 return renderNode; // no work needed 16762 } 16763 16764 // If we got here, we're recreating it. Mark it as such to ensure that 16765 // we copy in child display lists into ours in drawChild() 16766 mRecreateDisplayList = true; 16767 16768 int width = mRight - mLeft; 16769 int height = mBottom - mTop; 16770 int layerType = getLayerType(); 16771 16772 final DisplayListCanvas canvas = renderNode.start(width, height); 16773 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 16774 16775 try { 16776 if (layerType == LAYER_TYPE_SOFTWARE) { 16777 buildDrawingCache(true); 16778 Bitmap cache = getDrawingCache(true); 16779 if (cache != null) { 16780 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 16781 } 16782 } else { 16783 computeScroll(); 16784 16785 canvas.translate(-mScrollX, -mScrollY); 16786 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16787 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16788 16789 // Fast path for layouts with no backgrounds 16790 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16791 dispatchDraw(canvas); 16792 if (mOverlay != null && !mOverlay.isEmpty()) { 16793 mOverlay.getOverlayView().draw(canvas); 16794 } 16795 if (debugDraw()) { 16796 debugDrawFocus(canvas); 16797 } 16798 } else { 16799 draw(canvas); 16800 } 16801 } 16802 } finally { 16803 renderNode.end(canvas); 16804 setDisplayListProperties(renderNode); 16805 } 16806 } else { 16807 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16808 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16809 } 16810 return renderNode; 16811 } 16812 16813 private void resetDisplayList() { 16814 if (mRenderNode.isValid()) { 16815 mRenderNode.discardDisplayList(); 16816 } 16817 16818 if (mBackgroundRenderNode != null && mBackgroundRenderNode.isValid()) { 16819 mBackgroundRenderNode.discardDisplayList(); 16820 } 16821 } 16822 16823 /** 16824 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 16825 * 16826 * @return A non-scaled bitmap representing this view or null if cache is disabled. 16827 * 16828 * @see #getDrawingCache(boolean) 16829 */ 16830 public Bitmap getDrawingCache() { 16831 return getDrawingCache(false); 16832 } 16833 16834 /** 16835 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 16836 * is null when caching is disabled. If caching is enabled and the cache is not ready, 16837 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 16838 * draw from the cache when the cache is enabled. To benefit from the cache, you must 16839 * request the drawing cache by calling this method and draw it on screen if the 16840 * returned bitmap is not null.</p> 16841 * 16842 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16843 * this method will create a bitmap of the same size as this view. Because this bitmap 16844 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16845 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16846 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16847 * size than the view. This implies that your application must be able to handle this 16848 * size.</p> 16849 * 16850 * @param autoScale Indicates whether the generated bitmap should be scaled based on 16851 * the current density of the screen when the application is in compatibility 16852 * mode. 16853 * 16854 * @return A bitmap representing this view or null if cache is disabled. 16855 * 16856 * @see #setDrawingCacheEnabled(boolean) 16857 * @see #isDrawingCacheEnabled() 16858 * @see #buildDrawingCache(boolean) 16859 * @see #destroyDrawingCache() 16860 */ 16861 public Bitmap getDrawingCache(boolean autoScale) { 16862 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 16863 return null; 16864 } 16865 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 16866 buildDrawingCache(autoScale); 16867 } 16868 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 16869 } 16870 16871 /** 16872 * <p>Frees the resources used by the drawing cache. If you call 16873 * {@link #buildDrawingCache()} manually without calling 16874 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16875 * should cleanup the cache with this method afterwards.</p> 16876 * 16877 * @see #setDrawingCacheEnabled(boolean) 16878 * @see #buildDrawingCache() 16879 * @see #getDrawingCache() 16880 */ 16881 public void destroyDrawingCache() { 16882 if (mDrawingCache != null) { 16883 mDrawingCache.recycle(); 16884 mDrawingCache = null; 16885 } 16886 if (mUnscaledDrawingCache != null) { 16887 mUnscaledDrawingCache.recycle(); 16888 mUnscaledDrawingCache = null; 16889 } 16890 } 16891 16892 /** 16893 * Setting a solid background color for the drawing cache's bitmaps will improve 16894 * performance and memory usage. Note, though that this should only be used if this 16895 * view will always be drawn on top of a solid color. 16896 * 16897 * @param color The background color to use for the drawing cache's bitmap 16898 * 16899 * @see #setDrawingCacheEnabled(boolean) 16900 * @see #buildDrawingCache() 16901 * @see #getDrawingCache() 16902 */ 16903 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 16904 if (color != mDrawingCacheBackgroundColor) { 16905 mDrawingCacheBackgroundColor = color; 16906 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16907 } 16908 } 16909 16910 /** 16911 * @see #setDrawingCacheBackgroundColor(int) 16912 * 16913 * @return The background color to used for the drawing cache's bitmap 16914 */ 16915 @ColorInt 16916 public int getDrawingCacheBackgroundColor() { 16917 return mDrawingCacheBackgroundColor; 16918 } 16919 16920 /** 16921 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 16922 * 16923 * @see #buildDrawingCache(boolean) 16924 */ 16925 public void buildDrawingCache() { 16926 buildDrawingCache(false); 16927 } 16928 16929 /** 16930 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 16931 * 16932 * <p>If you call {@link #buildDrawingCache()} manually without calling 16933 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16934 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 16935 * 16936 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16937 * this method will create a bitmap of the same size as this view. Because this bitmap 16938 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16939 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16940 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16941 * size than the view. This implies that your application must be able to handle this 16942 * size.</p> 16943 * 16944 * <p>You should avoid calling this method when hardware acceleration is enabled. If 16945 * you do not need the drawing cache bitmap, calling this method will increase memory 16946 * usage and cause the view to be rendered in software once, thus negatively impacting 16947 * performance.</p> 16948 * 16949 * @see #getDrawingCache() 16950 * @see #destroyDrawingCache() 16951 */ 16952 public void buildDrawingCache(boolean autoScale) { 16953 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 16954 mDrawingCache == null : mUnscaledDrawingCache == null)) { 16955 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 16956 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 16957 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 16958 } 16959 try { 16960 buildDrawingCacheImpl(autoScale); 16961 } finally { 16962 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 16963 } 16964 } 16965 } 16966 16967 /** 16968 * private, internal implementation of buildDrawingCache, used to enable tracing 16969 */ 16970 private void buildDrawingCacheImpl(boolean autoScale) { 16971 mCachingFailed = false; 16972 16973 int width = mRight - mLeft; 16974 int height = mBottom - mTop; 16975 16976 final AttachInfo attachInfo = mAttachInfo; 16977 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 16978 16979 if (autoScale && scalingRequired) { 16980 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 16981 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 16982 } 16983 16984 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 16985 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 16986 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 16987 16988 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 16989 final long drawingCacheSize = 16990 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 16991 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 16992 if (width > 0 && height > 0) { 16993 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 16994 + " too large to fit into a software layer (or drawing cache), needs " 16995 + projectedBitmapSize + " bytes, only " 16996 + drawingCacheSize + " available"); 16997 } 16998 destroyDrawingCache(); 16999 mCachingFailed = true; 17000 return; 17001 } 17002 17003 boolean clear = true; 17004 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 17005 17006 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 17007 Bitmap.Config quality; 17008 if (!opaque) { 17009 // Never pick ARGB_4444 because it looks awful 17010 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 17011 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 17012 case DRAWING_CACHE_QUALITY_AUTO: 17013 case DRAWING_CACHE_QUALITY_LOW: 17014 case DRAWING_CACHE_QUALITY_HIGH: 17015 default: 17016 quality = Bitmap.Config.ARGB_8888; 17017 break; 17018 } 17019 } else { 17020 // Optimization for translucent windows 17021 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 17022 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 17023 } 17024 17025 // Try to cleanup memory 17026 if (bitmap != null) bitmap.recycle(); 17027 17028 try { 17029 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17030 width, height, quality); 17031 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 17032 if (autoScale) { 17033 mDrawingCache = bitmap; 17034 } else { 17035 mUnscaledDrawingCache = bitmap; 17036 } 17037 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 17038 } catch (OutOfMemoryError e) { 17039 // If there is not enough memory to create the bitmap cache, just 17040 // ignore the issue as bitmap caches are not required to draw the 17041 // view hierarchy 17042 if (autoScale) { 17043 mDrawingCache = null; 17044 } else { 17045 mUnscaledDrawingCache = null; 17046 } 17047 mCachingFailed = true; 17048 return; 17049 } 17050 17051 clear = drawingCacheBackgroundColor != 0; 17052 } 17053 17054 Canvas canvas; 17055 if (attachInfo != null) { 17056 canvas = attachInfo.mCanvas; 17057 if (canvas == null) { 17058 canvas = new Canvas(); 17059 } 17060 canvas.setBitmap(bitmap); 17061 // Temporarily clobber the cached Canvas in case one of our children 17062 // is also using a drawing cache. Without this, the children would 17063 // steal the canvas by attaching their own bitmap to it and bad, bad 17064 // thing would happen (invisible views, corrupted drawings, etc.) 17065 attachInfo.mCanvas = null; 17066 } else { 17067 // This case should hopefully never or seldom happen 17068 canvas = new Canvas(bitmap); 17069 } 17070 17071 if (clear) { 17072 bitmap.eraseColor(drawingCacheBackgroundColor); 17073 } 17074 17075 computeScroll(); 17076 final int restoreCount = canvas.save(); 17077 17078 if (autoScale && scalingRequired) { 17079 final float scale = attachInfo.mApplicationScale; 17080 canvas.scale(scale, scale); 17081 } 17082 17083 canvas.translate(-mScrollX, -mScrollY); 17084 17085 mPrivateFlags |= PFLAG_DRAWN; 17086 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 17087 mLayerType != LAYER_TYPE_NONE) { 17088 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 17089 } 17090 17091 // Fast path for layouts with no backgrounds 17092 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17093 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17094 dispatchDraw(canvas); 17095 if (mOverlay != null && !mOverlay.isEmpty()) { 17096 mOverlay.getOverlayView().draw(canvas); 17097 } 17098 } else { 17099 draw(canvas); 17100 } 17101 17102 canvas.restoreToCount(restoreCount); 17103 canvas.setBitmap(null); 17104 17105 if (attachInfo != null) { 17106 // Restore the cached Canvas for our siblings 17107 attachInfo.mCanvas = canvas; 17108 } 17109 } 17110 17111 /** 17112 * Create a snapshot of the view into a bitmap. We should probably make 17113 * some form of this public, but should think about the API. 17114 * 17115 * @hide 17116 */ 17117 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 17118 int width = mRight - mLeft; 17119 int height = mBottom - mTop; 17120 17121 final AttachInfo attachInfo = mAttachInfo; 17122 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 17123 width = (int) ((width * scale) + 0.5f); 17124 height = (int) ((height * scale) + 0.5f); 17125 17126 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17127 width > 0 ? width : 1, height > 0 ? height : 1, quality); 17128 if (bitmap == null) { 17129 throw new OutOfMemoryError(); 17130 } 17131 17132 Resources resources = getResources(); 17133 if (resources != null) { 17134 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 17135 } 17136 17137 Canvas canvas; 17138 if (attachInfo != null) { 17139 canvas = attachInfo.mCanvas; 17140 if (canvas == null) { 17141 canvas = new Canvas(); 17142 } 17143 canvas.setBitmap(bitmap); 17144 // Temporarily clobber the cached Canvas in case one of our children 17145 // is also using a drawing cache. Without this, the children would 17146 // steal the canvas by attaching their own bitmap to it and bad, bad 17147 // things would happen (invisible views, corrupted drawings, etc.) 17148 attachInfo.mCanvas = null; 17149 } else { 17150 // This case should hopefully never or seldom happen 17151 canvas = new Canvas(bitmap); 17152 } 17153 17154 if ((backgroundColor & 0xff000000) != 0) { 17155 bitmap.eraseColor(backgroundColor); 17156 } 17157 17158 computeScroll(); 17159 final int restoreCount = canvas.save(); 17160 canvas.scale(scale, scale); 17161 canvas.translate(-mScrollX, -mScrollY); 17162 17163 // Temporarily remove the dirty mask 17164 int flags = mPrivateFlags; 17165 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17166 17167 // Fast path for layouts with no backgrounds 17168 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17169 dispatchDraw(canvas); 17170 if (mOverlay != null && !mOverlay.isEmpty()) { 17171 mOverlay.getOverlayView().draw(canvas); 17172 } 17173 } else { 17174 draw(canvas); 17175 } 17176 17177 mPrivateFlags = flags; 17178 17179 canvas.restoreToCount(restoreCount); 17180 canvas.setBitmap(null); 17181 17182 if (attachInfo != null) { 17183 // Restore the cached Canvas for our siblings 17184 attachInfo.mCanvas = canvas; 17185 } 17186 17187 return bitmap; 17188 } 17189 17190 /** 17191 * Indicates whether this View is currently in edit mode. A View is usually 17192 * in edit mode when displayed within a developer tool. For instance, if 17193 * this View is being drawn by a visual user interface builder, this method 17194 * should return true. 17195 * 17196 * Subclasses should check the return value of this method to provide 17197 * different behaviors if their normal behavior might interfere with the 17198 * host environment. For instance: the class spawns a thread in its 17199 * constructor, the drawing code relies on device-specific features, etc. 17200 * 17201 * This method is usually checked in the drawing code of custom widgets. 17202 * 17203 * @return True if this View is in edit mode, false otherwise. 17204 */ 17205 public boolean isInEditMode() { 17206 return false; 17207 } 17208 17209 /** 17210 * If the View draws content inside its padding and enables fading edges, 17211 * it needs to support padding offsets. Padding offsets are added to the 17212 * fading edges to extend the length of the fade so that it covers pixels 17213 * drawn inside the padding. 17214 * 17215 * Subclasses of this class should override this method if they need 17216 * to draw content inside the padding. 17217 * 17218 * @return True if padding offset must be applied, false otherwise. 17219 * 17220 * @see #getLeftPaddingOffset() 17221 * @see #getRightPaddingOffset() 17222 * @see #getTopPaddingOffset() 17223 * @see #getBottomPaddingOffset() 17224 * 17225 * @since CURRENT 17226 */ 17227 protected boolean isPaddingOffsetRequired() { 17228 return false; 17229 } 17230 17231 /** 17232 * Amount by which to extend the left fading region. Called only when 17233 * {@link #isPaddingOffsetRequired()} returns true. 17234 * 17235 * @return The left padding offset in pixels. 17236 * 17237 * @see #isPaddingOffsetRequired() 17238 * 17239 * @since CURRENT 17240 */ 17241 protected int getLeftPaddingOffset() { 17242 return 0; 17243 } 17244 17245 /** 17246 * Amount by which to extend the right fading region. Called only when 17247 * {@link #isPaddingOffsetRequired()} returns true. 17248 * 17249 * @return The right padding offset in pixels. 17250 * 17251 * @see #isPaddingOffsetRequired() 17252 * 17253 * @since CURRENT 17254 */ 17255 protected int getRightPaddingOffset() { 17256 return 0; 17257 } 17258 17259 /** 17260 * Amount by which to extend the top fading region. Called only when 17261 * {@link #isPaddingOffsetRequired()} returns true. 17262 * 17263 * @return The top padding offset in pixels. 17264 * 17265 * @see #isPaddingOffsetRequired() 17266 * 17267 * @since CURRENT 17268 */ 17269 protected int getTopPaddingOffset() { 17270 return 0; 17271 } 17272 17273 /** 17274 * Amount by which to extend the bottom fading region. Called only when 17275 * {@link #isPaddingOffsetRequired()} returns true. 17276 * 17277 * @return The bottom padding offset in pixels. 17278 * 17279 * @see #isPaddingOffsetRequired() 17280 * 17281 * @since CURRENT 17282 */ 17283 protected int getBottomPaddingOffset() { 17284 return 0; 17285 } 17286 17287 /** 17288 * @hide 17289 * @param offsetRequired 17290 */ 17291 protected int getFadeTop(boolean offsetRequired) { 17292 int top = mPaddingTop; 17293 if (offsetRequired) top += getTopPaddingOffset(); 17294 return top; 17295 } 17296 17297 /** 17298 * @hide 17299 * @param offsetRequired 17300 */ 17301 protected int getFadeHeight(boolean offsetRequired) { 17302 int padding = mPaddingTop; 17303 if (offsetRequired) padding += getTopPaddingOffset(); 17304 return mBottom - mTop - mPaddingBottom - padding; 17305 } 17306 17307 /** 17308 * <p>Indicates whether this view is attached to a hardware accelerated 17309 * window or not.</p> 17310 * 17311 * <p>Even if this method returns true, it does not mean that every call 17312 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 17313 * accelerated {@link android.graphics.Canvas}. For instance, if this view 17314 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 17315 * window is hardware accelerated, 17316 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 17317 * return false, and this method will return true.</p> 17318 * 17319 * @return True if the view is attached to a window and the window is 17320 * hardware accelerated; false in any other case. 17321 */ 17322 @ViewDebug.ExportedProperty(category = "drawing") 17323 public boolean isHardwareAccelerated() { 17324 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 17325 } 17326 17327 /** 17328 * Sets a rectangular area on this view to which the view will be clipped 17329 * when it is drawn. Setting the value to null will remove the clip bounds 17330 * and the view will draw normally, using its full bounds. 17331 * 17332 * @param clipBounds The rectangular area, in the local coordinates of 17333 * this view, to which future drawing operations will be clipped. 17334 */ 17335 public void setClipBounds(Rect clipBounds) { 17336 if (clipBounds == mClipBounds 17337 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 17338 return; 17339 } 17340 if (clipBounds != null) { 17341 if (mClipBounds == null) { 17342 mClipBounds = new Rect(clipBounds); 17343 } else { 17344 mClipBounds.set(clipBounds); 17345 } 17346 } else { 17347 mClipBounds = null; 17348 } 17349 mRenderNode.setClipBounds(mClipBounds); 17350 invalidateViewProperty(false, false); 17351 } 17352 17353 /** 17354 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 17355 * 17356 * @return A copy of the current clip bounds if clip bounds are set, 17357 * otherwise null. 17358 */ 17359 public Rect getClipBounds() { 17360 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 17361 } 17362 17363 17364 /** 17365 * Populates an output rectangle with the clip bounds of the view, 17366 * returning {@code true} if successful or {@code false} if the view's 17367 * clip bounds are {@code null}. 17368 * 17369 * @param outRect rectangle in which to place the clip bounds of the view 17370 * @return {@code true} if successful or {@code false} if the view's 17371 * clip bounds are {@code null} 17372 */ 17373 public boolean getClipBounds(Rect outRect) { 17374 if (mClipBounds != null) { 17375 outRect.set(mClipBounds); 17376 return true; 17377 } 17378 return false; 17379 } 17380 17381 /** 17382 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 17383 * case of an active Animation being run on the view. 17384 */ 17385 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 17386 Animation a, boolean scalingRequired) { 17387 Transformation invalidationTransform; 17388 final int flags = parent.mGroupFlags; 17389 final boolean initialized = a.isInitialized(); 17390 if (!initialized) { 17391 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 17392 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 17393 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 17394 onAnimationStart(); 17395 } 17396 17397 final Transformation t = parent.getChildTransformation(); 17398 boolean more = a.getTransformation(drawingTime, t, 1f); 17399 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 17400 if (parent.mInvalidationTransformation == null) { 17401 parent.mInvalidationTransformation = new Transformation(); 17402 } 17403 invalidationTransform = parent.mInvalidationTransformation; 17404 a.getTransformation(drawingTime, invalidationTransform, 1f); 17405 } else { 17406 invalidationTransform = t; 17407 } 17408 17409 if (more) { 17410 if (!a.willChangeBounds()) { 17411 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 17412 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 17413 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 17414 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 17415 // The child need to draw an animation, potentially offscreen, so 17416 // make sure we do not cancel invalidate requests 17417 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17418 parent.invalidate(mLeft, mTop, mRight, mBottom); 17419 } 17420 } else { 17421 if (parent.mInvalidateRegion == null) { 17422 parent.mInvalidateRegion = new RectF(); 17423 } 17424 final RectF region = parent.mInvalidateRegion; 17425 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 17426 invalidationTransform); 17427 17428 // The child need to draw an animation, potentially offscreen, so 17429 // make sure we do not cancel invalidate requests 17430 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17431 17432 final int left = mLeft + (int) region.left; 17433 final int top = mTop + (int) region.top; 17434 parent.invalidate(left, top, left + (int) (region.width() + .5f), 17435 top + (int) (region.height() + .5f)); 17436 } 17437 } 17438 return more; 17439 } 17440 17441 /** 17442 * This method is called by getDisplayList() when a display list is recorded for a View. 17443 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 17444 */ 17445 void setDisplayListProperties(RenderNode renderNode) { 17446 if (renderNode != null) { 17447 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 17448 renderNode.setClipToBounds(mParent instanceof ViewGroup 17449 && ((ViewGroup) mParent).getClipChildren()); 17450 17451 float alpha = 1; 17452 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 17453 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17454 ViewGroup parentVG = (ViewGroup) mParent; 17455 final Transformation t = parentVG.getChildTransformation(); 17456 if (parentVG.getChildStaticTransformation(this, t)) { 17457 final int transformType = t.getTransformationType(); 17458 if (transformType != Transformation.TYPE_IDENTITY) { 17459 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 17460 alpha = t.getAlpha(); 17461 } 17462 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 17463 renderNode.setStaticMatrix(t.getMatrix()); 17464 } 17465 } 17466 } 17467 } 17468 if (mTransformationInfo != null) { 17469 alpha *= getFinalAlpha(); 17470 if (alpha < 1) { 17471 final int multipliedAlpha = (int) (255 * alpha); 17472 if (onSetAlpha(multipliedAlpha)) { 17473 alpha = 1; 17474 } 17475 } 17476 renderNode.setAlpha(alpha); 17477 } else if (alpha < 1) { 17478 renderNode.setAlpha(alpha); 17479 } 17480 } 17481 } 17482 17483 /** 17484 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 17485 * 17486 * This is where the View specializes rendering behavior based on layer type, 17487 * and hardware acceleration. 17488 */ 17489 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 17490 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 17491 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 17492 * 17493 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 17494 * HW accelerated, it can't handle drawing RenderNodes. 17495 */ 17496 boolean drawingWithRenderNode = mAttachInfo != null 17497 && mAttachInfo.mHardwareAccelerated 17498 && hardwareAcceleratedCanvas; 17499 17500 boolean more = false; 17501 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 17502 final int parentFlags = parent.mGroupFlags; 17503 17504 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 17505 parent.getChildTransformation().clear(); 17506 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17507 } 17508 17509 Transformation transformToApply = null; 17510 boolean concatMatrix = false; 17511 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 17512 final Animation a = getAnimation(); 17513 if (a != null) { 17514 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 17515 concatMatrix = a.willChangeTransformationMatrix(); 17516 if (concatMatrix) { 17517 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17518 } 17519 transformToApply = parent.getChildTransformation(); 17520 } else { 17521 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 17522 // No longer animating: clear out old animation matrix 17523 mRenderNode.setAnimationMatrix(null); 17524 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17525 } 17526 if (!drawingWithRenderNode 17527 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17528 final Transformation t = parent.getChildTransformation(); 17529 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 17530 if (hasTransform) { 17531 final int transformType = t.getTransformationType(); 17532 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 17533 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 17534 } 17535 } 17536 } 17537 17538 concatMatrix |= !childHasIdentityMatrix; 17539 17540 // Sets the flag as early as possible to allow draw() implementations 17541 // to call invalidate() successfully when doing animations 17542 mPrivateFlags |= PFLAG_DRAWN; 17543 17544 if (!concatMatrix && 17545 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 17546 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 17547 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 17548 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 17549 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 17550 return more; 17551 } 17552 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 17553 17554 if (hardwareAcceleratedCanvas) { 17555 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 17556 // retain the flag's value temporarily in the mRecreateDisplayList flag 17557 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 17558 mPrivateFlags &= ~PFLAG_INVALIDATED; 17559 } 17560 17561 RenderNode renderNode = null; 17562 Bitmap cache = null; 17563 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 17564 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 17565 if (layerType != LAYER_TYPE_NONE) { 17566 // If not drawing with RenderNode, treat HW layers as SW 17567 layerType = LAYER_TYPE_SOFTWARE; 17568 buildDrawingCache(true); 17569 } 17570 cache = getDrawingCache(true); 17571 } 17572 17573 if (drawingWithRenderNode) { 17574 // Delay getting the display list until animation-driven alpha values are 17575 // set up and possibly passed on to the view 17576 renderNode = updateDisplayListIfDirty(); 17577 if (!renderNode.isValid()) { 17578 // Uncommon, but possible. If a view is removed from the hierarchy during the call 17579 // to getDisplayList(), the display list will be marked invalid and we should not 17580 // try to use it again. 17581 renderNode = null; 17582 drawingWithRenderNode = false; 17583 } 17584 } 17585 17586 int sx = 0; 17587 int sy = 0; 17588 if (!drawingWithRenderNode) { 17589 computeScroll(); 17590 sx = mScrollX; 17591 sy = mScrollY; 17592 } 17593 17594 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 17595 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 17596 17597 int restoreTo = -1; 17598 if (!drawingWithRenderNode || transformToApply != null) { 17599 restoreTo = canvas.save(); 17600 } 17601 if (offsetForScroll) { 17602 canvas.translate(mLeft - sx, mTop - sy); 17603 } else { 17604 if (!drawingWithRenderNode) { 17605 canvas.translate(mLeft, mTop); 17606 } 17607 if (scalingRequired) { 17608 if (drawingWithRenderNode) { 17609 // TODO: Might not need this if we put everything inside the DL 17610 restoreTo = canvas.save(); 17611 } 17612 // mAttachInfo cannot be null, otherwise scalingRequired == false 17613 final float scale = 1.0f / mAttachInfo.mApplicationScale; 17614 canvas.scale(scale, scale); 17615 } 17616 } 17617 17618 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 17619 if (transformToApply != null 17620 || alpha < 1 17621 || !hasIdentityMatrix() 17622 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17623 if (transformToApply != null || !childHasIdentityMatrix) { 17624 int transX = 0; 17625 int transY = 0; 17626 17627 if (offsetForScroll) { 17628 transX = -sx; 17629 transY = -sy; 17630 } 17631 17632 if (transformToApply != null) { 17633 if (concatMatrix) { 17634 if (drawingWithRenderNode) { 17635 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 17636 } else { 17637 // Undo the scroll translation, apply the transformation matrix, 17638 // then redo the scroll translate to get the correct result. 17639 canvas.translate(-transX, -transY); 17640 canvas.concat(transformToApply.getMatrix()); 17641 canvas.translate(transX, transY); 17642 } 17643 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17644 } 17645 17646 float transformAlpha = transformToApply.getAlpha(); 17647 if (transformAlpha < 1) { 17648 alpha *= transformAlpha; 17649 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17650 } 17651 } 17652 17653 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 17654 canvas.translate(-transX, -transY); 17655 canvas.concat(getMatrix()); 17656 canvas.translate(transX, transY); 17657 } 17658 } 17659 17660 // Deal with alpha if it is or used to be <1 17661 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17662 if (alpha < 1) { 17663 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17664 } else { 17665 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17666 } 17667 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17668 if (!drawingWithDrawingCache) { 17669 final int multipliedAlpha = (int) (255 * alpha); 17670 if (!onSetAlpha(multipliedAlpha)) { 17671 if (drawingWithRenderNode) { 17672 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 17673 } else if (layerType == LAYER_TYPE_NONE) { 17674 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 17675 multipliedAlpha); 17676 } 17677 } else { 17678 // Alpha is handled by the child directly, clobber the layer's alpha 17679 mPrivateFlags |= PFLAG_ALPHA_SET; 17680 } 17681 } 17682 } 17683 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17684 onSetAlpha(255); 17685 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17686 } 17687 17688 if (!drawingWithRenderNode) { 17689 // apply clips directly, since RenderNode won't do it for this draw 17690 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 17691 if (offsetForScroll) { 17692 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 17693 } else { 17694 if (!scalingRequired || cache == null) { 17695 canvas.clipRect(0, 0, getWidth(), getHeight()); 17696 } else { 17697 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 17698 } 17699 } 17700 } 17701 17702 if (mClipBounds != null) { 17703 // clip bounds ignore scroll 17704 canvas.clipRect(mClipBounds); 17705 } 17706 } 17707 17708 if (!drawingWithDrawingCache) { 17709 if (drawingWithRenderNode) { 17710 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17711 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 17712 } else { 17713 // Fast path for layouts with no backgrounds 17714 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17715 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17716 dispatchDraw(canvas); 17717 } else { 17718 draw(canvas); 17719 } 17720 } 17721 } else if (cache != null) { 17722 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17723 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 17724 // no layer paint, use temporary paint to draw bitmap 17725 Paint cachePaint = parent.mCachePaint; 17726 if (cachePaint == null) { 17727 cachePaint = new Paint(); 17728 cachePaint.setDither(false); 17729 parent.mCachePaint = cachePaint; 17730 } 17731 cachePaint.setAlpha((int) (alpha * 255)); 17732 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 17733 } else { 17734 // use layer paint to draw the bitmap, merging the two alphas, but also restore 17735 int layerPaintAlpha = mLayerPaint.getAlpha(); 17736 if (alpha < 1) { 17737 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 17738 } 17739 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 17740 if (alpha < 1) { 17741 mLayerPaint.setAlpha(layerPaintAlpha); 17742 } 17743 } 17744 } 17745 17746 if (restoreTo >= 0) { 17747 canvas.restoreToCount(restoreTo); 17748 } 17749 17750 if (a != null && !more) { 17751 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 17752 onSetAlpha(255); 17753 } 17754 parent.finishAnimatingView(this, a); 17755 } 17756 17757 if (more && hardwareAcceleratedCanvas) { 17758 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17759 // alpha animations should cause the child to recreate its display list 17760 invalidate(true); 17761 } 17762 } 17763 17764 mRecreateDisplayList = false; 17765 17766 return more; 17767 } 17768 17769 static Paint getDebugPaint() { 17770 if (sDebugPaint == null) { 17771 sDebugPaint = new Paint(); 17772 sDebugPaint.setAntiAlias(false); 17773 } 17774 return sDebugPaint; 17775 } 17776 17777 final int dipsToPixels(int dips) { 17778 float scale = getContext().getResources().getDisplayMetrics().density; 17779 return (int) (dips * scale + 0.5f); 17780 } 17781 17782 final private void debugDrawFocus(Canvas canvas) { 17783 if (isFocused()) { 17784 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 17785 final int l = mScrollX; 17786 final int r = l + mRight - mLeft; 17787 final int t = mScrollY; 17788 final int b = t + mBottom - mTop; 17789 17790 final Paint paint = getDebugPaint(); 17791 paint.setColor(DEBUG_CORNERS_COLOR); 17792 17793 // Draw squares in corners. 17794 paint.setStyle(Paint.Style.FILL); 17795 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 17796 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 17797 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 17798 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 17799 17800 // Draw big X across the view. 17801 paint.setStyle(Paint.Style.STROKE); 17802 canvas.drawLine(l, t, r, b, paint); 17803 canvas.drawLine(l, b, r, t, paint); 17804 } 17805 } 17806 17807 /** 17808 * Manually render this view (and all of its children) to the given Canvas. 17809 * The view must have already done a full layout before this function is 17810 * called. When implementing a view, implement 17811 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 17812 * If you do need to override this method, call the superclass version. 17813 * 17814 * @param canvas The Canvas to which the View is rendered. 17815 */ 17816 @CallSuper 17817 public void draw(Canvas canvas) { 17818 final int privateFlags = mPrivateFlags; 17819 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 17820 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 17821 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 17822 17823 /* 17824 * Draw traversal performs several drawing steps which must be executed 17825 * in the appropriate order: 17826 * 17827 * 1. Draw the background 17828 * 2. If necessary, save the canvas' layers to prepare for fading 17829 * 3. Draw view's content 17830 * 4. Draw children 17831 * 5. If necessary, draw the fading edges and restore layers 17832 * 6. Draw decorations (scrollbars for instance) 17833 */ 17834 17835 // Step 1, draw the background, if needed 17836 int saveCount; 17837 17838 if (!dirtyOpaque) { 17839 drawBackground(canvas); 17840 } 17841 17842 // skip step 2 & 5 if possible (common case) 17843 final int viewFlags = mViewFlags; 17844 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 17845 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 17846 if (!verticalEdges && !horizontalEdges) { 17847 // Step 3, draw the content 17848 if (!dirtyOpaque) onDraw(canvas); 17849 17850 // Step 4, draw the children 17851 dispatchDraw(canvas); 17852 17853 // Overlay is part of the content and draws beneath Foreground 17854 if (mOverlay != null && !mOverlay.isEmpty()) { 17855 mOverlay.getOverlayView().dispatchDraw(canvas); 17856 } 17857 17858 // Step 6, draw decorations (foreground, scrollbars) 17859 onDrawForeground(canvas); 17860 17861 if (debugDraw()) { 17862 debugDrawFocus(canvas); 17863 } 17864 17865 // we're done... 17866 return; 17867 } 17868 17869 /* 17870 * Here we do the full fledged routine... 17871 * (this is an uncommon case where speed matters less, 17872 * this is why we repeat some of the tests that have been 17873 * done above) 17874 */ 17875 17876 boolean drawTop = false; 17877 boolean drawBottom = false; 17878 boolean drawLeft = false; 17879 boolean drawRight = false; 17880 17881 float topFadeStrength = 0.0f; 17882 float bottomFadeStrength = 0.0f; 17883 float leftFadeStrength = 0.0f; 17884 float rightFadeStrength = 0.0f; 17885 17886 // Step 2, save the canvas' layers 17887 int paddingLeft = mPaddingLeft; 17888 17889 final boolean offsetRequired = isPaddingOffsetRequired(); 17890 if (offsetRequired) { 17891 paddingLeft += getLeftPaddingOffset(); 17892 } 17893 17894 int left = mScrollX + paddingLeft; 17895 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 17896 int top = mScrollY + getFadeTop(offsetRequired); 17897 int bottom = top + getFadeHeight(offsetRequired); 17898 17899 if (offsetRequired) { 17900 right += getRightPaddingOffset(); 17901 bottom += getBottomPaddingOffset(); 17902 } 17903 17904 final ScrollabilityCache scrollabilityCache = mScrollCache; 17905 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 17906 int length = (int) fadeHeight; 17907 17908 // clip the fade length if top and bottom fades overlap 17909 // overlapping fades produce odd-looking artifacts 17910 if (verticalEdges && (top + length > bottom - length)) { 17911 length = (bottom - top) / 2; 17912 } 17913 17914 // also clip horizontal fades if necessary 17915 if (horizontalEdges && (left + length > right - length)) { 17916 length = (right - left) / 2; 17917 } 17918 17919 if (verticalEdges) { 17920 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 17921 drawTop = topFadeStrength * fadeHeight > 1.0f; 17922 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 17923 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 17924 } 17925 17926 if (horizontalEdges) { 17927 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 17928 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 17929 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 17930 drawRight = rightFadeStrength * fadeHeight > 1.0f; 17931 } 17932 17933 saveCount = canvas.getSaveCount(); 17934 17935 int solidColor = getSolidColor(); 17936 if (solidColor == 0) { 17937 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 17938 17939 if (drawTop) { 17940 canvas.saveLayer(left, top, right, top + length, null, flags); 17941 } 17942 17943 if (drawBottom) { 17944 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 17945 } 17946 17947 if (drawLeft) { 17948 canvas.saveLayer(left, top, left + length, bottom, null, flags); 17949 } 17950 17951 if (drawRight) { 17952 canvas.saveLayer(right - length, top, right, bottom, null, flags); 17953 } 17954 } else { 17955 scrollabilityCache.setFadeColor(solidColor); 17956 } 17957 17958 // Step 3, draw the content 17959 if (!dirtyOpaque) onDraw(canvas); 17960 17961 // Step 4, draw the children 17962 dispatchDraw(canvas); 17963 17964 // Step 5, draw the fade effect and restore layers 17965 final Paint p = scrollabilityCache.paint; 17966 final Matrix matrix = scrollabilityCache.matrix; 17967 final Shader fade = scrollabilityCache.shader; 17968 17969 if (drawTop) { 17970 matrix.setScale(1, fadeHeight * topFadeStrength); 17971 matrix.postTranslate(left, top); 17972 fade.setLocalMatrix(matrix); 17973 p.setShader(fade); 17974 canvas.drawRect(left, top, right, top + length, p); 17975 } 17976 17977 if (drawBottom) { 17978 matrix.setScale(1, fadeHeight * bottomFadeStrength); 17979 matrix.postRotate(180); 17980 matrix.postTranslate(left, bottom); 17981 fade.setLocalMatrix(matrix); 17982 p.setShader(fade); 17983 canvas.drawRect(left, bottom - length, right, bottom, p); 17984 } 17985 17986 if (drawLeft) { 17987 matrix.setScale(1, fadeHeight * leftFadeStrength); 17988 matrix.postRotate(-90); 17989 matrix.postTranslate(left, top); 17990 fade.setLocalMatrix(matrix); 17991 p.setShader(fade); 17992 canvas.drawRect(left, top, left + length, bottom, p); 17993 } 17994 17995 if (drawRight) { 17996 matrix.setScale(1, fadeHeight * rightFadeStrength); 17997 matrix.postRotate(90); 17998 matrix.postTranslate(right, top); 17999 fade.setLocalMatrix(matrix); 18000 p.setShader(fade); 18001 canvas.drawRect(right - length, top, right, bottom, p); 18002 } 18003 18004 canvas.restoreToCount(saveCount); 18005 18006 // Overlay is part of the content and draws beneath Foreground 18007 if (mOverlay != null && !mOverlay.isEmpty()) { 18008 mOverlay.getOverlayView().dispatchDraw(canvas); 18009 } 18010 18011 // Step 6, draw decorations (foreground, scrollbars) 18012 onDrawForeground(canvas); 18013 18014 if (debugDraw()) { 18015 debugDrawFocus(canvas); 18016 } 18017 } 18018 18019 /** 18020 * Draws the background onto the specified canvas. 18021 * 18022 * @param canvas Canvas on which to draw the background 18023 */ 18024 private void drawBackground(Canvas canvas) { 18025 final Drawable background = mBackground; 18026 if (background == null) { 18027 return; 18028 } 18029 18030 setBackgroundBounds(); 18031 18032 // Attempt to use a display list if requested. 18033 if (canvas.isHardwareAccelerated() && mAttachInfo != null 18034 && mAttachInfo.mThreadedRenderer != null) { 18035 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 18036 18037 final RenderNode renderNode = mBackgroundRenderNode; 18038 if (renderNode != null && renderNode.isValid()) { 18039 setBackgroundRenderNodeProperties(renderNode); 18040 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18041 return; 18042 } 18043 } 18044 18045 final int scrollX = mScrollX; 18046 final int scrollY = mScrollY; 18047 if ((scrollX | scrollY) == 0) { 18048 background.draw(canvas); 18049 } else { 18050 canvas.translate(scrollX, scrollY); 18051 background.draw(canvas); 18052 canvas.translate(-scrollX, -scrollY); 18053 } 18054 } 18055 18056 /** 18057 * Sets the correct background bounds and rebuilds the outline, if needed. 18058 * <p/> 18059 * This is called by LayoutLib. 18060 */ 18061 void setBackgroundBounds() { 18062 if (mBackgroundSizeChanged && mBackground != null) { 18063 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 18064 mBackgroundSizeChanged = false; 18065 rebuildOutline(); 18066 } 18067 } 18068 18069 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 18070 renderNode.setTranslationX(mScrollX); 18071 renderNode.setTranslationY(mScrollY); 18072 } 18073 18074 /** 18075 * Creates a new display list or updates the existing display list for the 18076 * specified Drawable. 18077 * 18078 * @param drawable Drawable for which to create a display list 18079 * @param renderNode Existing RenderNode, or {@code null} 18080 * @return A valid display list for the specified drawable 18081 */ 18082 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 18083 if (renderNode == null) { 18084 renderNode = RenderNode.create(drawable.getClass().getName(), this); 18085 } 18086 18087 final Rect bounds = drawable.getBounds(); 18088 final int width = bounds.width(); 18089 final int height = bounds.height(); 18090 final DisplayListCanvas canvas = renderNode.start(width, height); 18091 18092 // Reverse left/top translation done by drawable canvas, which will 18093 // instead be applied by rendernode's LTRB bounds below. This way, the 18094 // drawable's bounds match with its rendernode bounds and its content 18095 // will lie within those bounds in the rendernode tree. 18096 canvas.translate(-bounds.left, -bounds.top); 18097 18098 try { 18099 drawable.draw(canvas); 18100 } finally { 18101 renderNode.end(canvas); 18102 } 18103 18104 // Set up drawable properties that are view-independent. 18105 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 18106 renderNode.setProjectBackwards(drawable.isProjected()); 18107 renderNode.setProjectionReceiver(true); 18108 renderNode.setClipToBounds(false); 18109 return renderNode; 18110 } 18111 18112 /** 18113 * Returns the overlay for this view, creating it if it does not yet exist. 18114 * Adding drawables to the overlay will cause them to be displayed whenever 18115 * the view itself is redrawn. Objects in the overlay should be actively 18116 * managed: remove them when they should not be displayed anymore. The 18117 * overlay will always have the same size as its host view. 18118 * 18119 * <p>Note: Overlays do not currently work correctly with {@link 18120 * SurfaceView} or {@link TextureView}; contents in overlays for these 18121 * types of views may not display correctly.</p> 18122 * 18123 * @return The ViewOverlay object for this view. 18124 * @see ViewOverlay 18125 */ 18126 public ViewOverlay getOverlay() { 18127 if (mOverlay == null) { 18128 mOverlay = new ViewOverlay(mContext, this); 18129 } 18130 return mOverlay; 18131 } 18132 18133 /** 18134 * Override this if your view is known to always be drawn on top of a solid color background, 18135 * and needs to draw fading edges. Returning a non-zero color enables the view system to 18136 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 18137 * should be set to 0xFF. 18138 * 18139 * @see #setVerticalFadingEdgeEnabled(boolean) 18140 * @see #setHorizontalFadingEdgeEnabled(boolean) 18141 * 18142 * @return The known solid color background for this view, or 0 if the color may vary 18143 */ 18144 @ViewDebug.ExportedProperty(category = "drawing") 18145 @ColorInt 18146 public int getSolidColor() { 18147 return 0; 18148 } 18149 18150 /** 18151 * Build a human readable string representation of the specified view flags. 18152 * 18153 * @param flags the view flags to convert to a string 18154 * @return a String representing the supplied flags 18155 */ 18156 private static String printFlags(int flags) { 18157 String output = ""; 18158 int numFlags = 0; 18159 if ((flags & FOCUSABLE_MASK) == FOCUSABLE) { 18160 output += "TAKES_FOCUS"; 18161 numFlags++; 18162 } 18163 18164 switch (flags & VISIBILITY_MASK) { 18165 case INVISIBLE: 18166 if (numFlags > 0) { 18167 output += " "; 18168 } 18169 output += "INVISIBLE"; 18170 // USELESS HERE numFlags++; 18171 break; 18172 case GONE: 18173 if (numFlags > 0) { 18174 output += " "; 18175 } 18176 output += "GONE"; 18177 // USELESS HERE numFlags++; 18178 break; 18179 default: 18180 break; 18181 } 18182 return output; 18183 } 18184 18185 /** 18186 * Build a human readable string representation of the specified private 18187 * view flags. 18188 * 18189 * @param privateFlags the private view flags to convert to a string 18190 * @return a String representing the supplied flags 18191 */ 18192 private static String printPrivateFlags(int privateFlags) { 18193 String output = ""; 18194 int numFlags = 0; 18195 18196 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 18197 output += "WANTS_FOCUS"; 18198 numFlags++; 18199 } 18200 18201 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 18202 if (numFlags > 0) { 18203 output += " "; 18204 } 18205 output += "FOCUSED"; 18206 numFlags++; 18207 } 18208 18209 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 18210 if (numFlags > 0) { 18211 output += " "; 18212 } 18213 output += "SELECTED"; 18214 numFlags++; 18215 } 18216 18217 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 18218 if (numFlags > 0) { 18219 output += " "; 18220 } 18221 output += "IS_ROOT_NAMESPACE"; 18222 numFlags++; 18223 } 18224 18225 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 18226 if (numFlags > 0) { 18227 output += " "; 18228 } 18229 output += "HAS_BOUNDS"; 18230 numFlags++; 18231 } 18232 18233 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 18234 if (numFlags > 0) { 18235 output += " "; 18236 } 18237 output += "DRAWN"; 18238 // USELESS HERE numFlags++; 18239 } 18240 return output; 18241 } 18242 18243 /** 18244 * <p>Indicates whether or not this view's layout will be requested during 18245 * the next hierarchy layout pass.</p> 18246 * 18247 * @return true if the layout will be forced during next layout pass 18248 */ 18249 public boolean isLayoutRequested() { 18250 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 18251 } 18252 18253 /** 18254 * Return true if o is a ViewGroup that is laying out using optical bounds. 18255 * @hide 18256 */ 18257 public static boolean isLayoutModeOptical(Object o) { 18258 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 18259 } 18260 18261 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 18262 Insets parentInsets = mParent instanceof View ? 18263 ((View) mParent).getOpticalInsets() : Insets.NONE; 18264 Insets childInsets = getOpticalInsets(); 18265 return setFrame( 18266 left + parentInsets.left - childInsets.left, 18267 top + parentInsets.top - childInsets.top, 18268 right + parentInsets.left + childInsets.right, 18269 bottom + parentInsets.top + childInsets.bottom); 18270 } 18271 18272 /** 18273 * Assign a size and position to a view and all of its 18274 * descendants 18275 * 18276 * <p>This is the second phase of the layout mechanism. 18277 * (The first is measuring). In this phase, each parent calls 18278 * layout on all of its children to position them. 18279 * This is typically done using the child measurements 18280 * that were stored in the measure pass().</p> 18281 * 18282 * <p>Derived classes should not override this method. 18283 * Derived classes with children should override 18284 * onLayout. In that method, they should 18285 * call layout on each of their children.</p> 18286 * 18287 * @param l Left position, relative to parent 18288 * @param t Top position, relative to parent 18289 * @param r Right position, relative to parent 18290 * @param b Bottom position, relative to parent 18291 */ 18292 @SuppressWarnings({"unchecked"}) 18293 public void layout(int l, int t, int r, int b) { 18294 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 18295 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 18296 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 18297 } 18298 18299 int oldL = mLeft; 18300 int oldT = mTop; 18301 int oldB = mBottom; 18302 int oldR = mRight; 18303 18304 boolean changed = isLayoutModeOptical(mParent) ? 18305 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 18306 18307 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 18308 onLayout(changed, l, t, r, b); 18309 18310 if (shouldDrawRoundScrollbar()) { 18311 if(mRoundScrollbarRenderer == null) { 18312 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 18313 } 18314 } else { 18315 mRoundScrollbarRenderer = null; 18316 } 18317 18318 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 18319 18320 ListenerInfo li = mListenerInfo; 18321 if (li != null && li.mOnLayoutChangeListeners != null) { 18322 ArrayList<OnLayoutChangeListener> listenersCopy = 18323 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 18324 int numListeners = listenersCopy.size(); 18325 for (int i = 0; i < numListeners; ++i) { 18326 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 18327 } 18328 } 18329 } 18330 18331 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 18332 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 18333 } 18334 18335 /** 18336 * Called from layout when this view should 18337 * assign a size and position to each of its children. 18338 * 18339 * Derived classes with children should override 18340 * this method and call layout on each of 18341 * their children. 18342 * @param changed This is a new size or position for this view 18343 * @param left Left position, relative to parent 18344 * @param top Top position, relative to parent 18345 * @param right Right position, relative to parent 18346 * @param bottom Bottom position, relative to parent 18347 */ 18348 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 18349 } 18350 18351 /** 18352 * Assign a size and position to this view. 18353 * 18354 * This is called from layout. 18355 * 18356 * @param left Left position, relative to parent 18357 * @param top Top position, relative to parent 18358 * @param right Right position, relative to parent 18359 * @param bottom Bottom position, relative to parent 18360 * @return true if the new size and position are different than the 18361 * previous ones 18362 * {@hide} 18363 */ 18364 protected boolean setFrame(int left, int top, int right, int bottom) { 18365 boolean changed = false; 18366 18367 if (DBG) { 18368 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 18369 + right + "," + bottom + ")"); 18370 } 18371 18372 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 18373 changed = true; 18374 18375 // Remember our drawn bit 18376 int drawn = mPrivateFlags & PFLAG_DRAWN; 18377 18378 int oldWidth = mRight - mLeft; 18379 int oldHeight = mBottom - mTop; 18380 int newWidth = right - left; 18381 int newHeight = bottom - top; 18382 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 18383 18384 // Invalidate our old position 18385 invalidate(sizeChanged); 18386 18387 mLeft = left; 18388 mTop = top; 18389 mRight = right; 18390 mBottom = bottom; 18391 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 18392 18393 mPrivateFlags |= PFLAG_HAS_BOUNDS; 18394 18395 18396 if (sizeChanged) { 18397 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 18398 } 18399 18400 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 18401 // If we are visible, force the DRAWN bit to on so that 18402 // this invalidate will go through (at least to our parent). 18403 // This is because someone may have invalidated this view 18404 // before this call to setFrame came in, thereby clearing 18405 // the DRAWN bit. 18406 mPrivateFlags |= PFLAG_DRAWN; 18407 invalidate(sizeChanged); 18408 // parent display list may need to be recreated based on a change in the bounds 18409 // of any child 18410 invalidateParentCaches(); 18411 } 18412 18413 // Reset drawn bit to original value (invalidate turns it off) 18414 mPrivateFlags |= drawn; 18415 18416 mBackgroundSizeChanged = true; 18417 if (mForegroundInfo != null) { 18418 mForegroundInfo.mBoundsChanged = true; 18419 } 18420 18421 notifySubtreeAccessibilityStateChangedIfNeeded(); 18422 } 18423 return changed; 18424 } 18425 18426 /** 18427 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 18428 * @hide 18429 */ 18430 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 18431 setFrame(left, top, right, bottom); 18432 } 18433 18434 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 18435 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 18436 if (mOverlay != null) { 18437 mOverlay.getOverlayView().setRight(newWidth); 18438 mOverlay.getOverlayView().setBottom(newHeight); 18439 } 18440 rebuildOutline(); 18441 } 18442 18443 /** 18444 * Finalize inflating a view from XML. This is called as the last phase 18445 * of inflation, after all child views have been added. 18446 * 18447 * <p>Even if the subclass overrides onFinishInflate, they should always be 18448 * sure to call the super method, so that we get called. 18449 */ 18450 @CallSuper 18451 protected void onFinishInflate() { 18452 } 18453 18454 /** 18455 * Returns the resources associated with this view. 18456 * 18457 * @return Resources object. 18458 */ 18459 public Resources getResources() { 18460 return mResources; 18461 } 18462 18463 /** 18464 * Invalidates the specified Drawable. 18465 * 18466 * @param drawable the drawable to invalidate 18467 */ 18468 @Override 18469 public void invalidateDrawable(@NonNull Drawable drawable) { 18470 if (verifyDrawable(drawable)) { 18471 final Rect dirty = drawable.getDirtyBounds(); 18472 final int scrollX = mScrollX; 18473 final int scrollY = mScrollY; 18474 18475 invalidate(dirty.left + scrollX, dirty.top + scrollY, 18476 dirty.right + scrollX, dirty.bottom + scrollY); 18477 rebuildOutline(); 18478 } 18479 } 18480 18481 /** 18482 * Schedules an action on a drawable to occur at a specified time. 18483 * 18484 * @param who the recipient of the action 18485 * @param what the action to run on the drawable 18486 * @param when the time at which the action must occur. Uses the 18487 * {@link SystemClock#uptimeMillis} timebase. 18488 */ 18489 @Override 18490 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 18491 if (verifyDrawable(who) && what != null) { 18492 final long delay = when - SystemClock.uptimeMillis(); 18493 if (mAttachInfo != null) { 18494 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 18495 Choreographer.CALLBACK_ANIMATION, what, who, 18496 Choreographer.subtractFrameDelay(delay)); 18497 } else { 18498 // Postpone the runnable until we know 18499 // on which thread it needs to run. 18500 getRunQueue().postDelayed(what, delay); 18501 } 18502 } 18503 } 18504 18505 /** 18506 * Cancels a scheduled action on a drawable. 18507 * 18508 * @param who the recipient of the action 18509 * @param what the action to cancel 18510 */ 18511 @Override 18512 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 18513 if (verifyDrawable(who) && what != null) { 18514 if (mAttachInfo != null) { 18515 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18516 Choreographer.CALLBACK_ANIMATION, what, who); 18517 } 18518 getRunQueue().removeCallbacks(what); 18519 } 18520 } 18521 18522 /** 18523 * Unschedule any events associated with the given Drawable. This can be 18524 * used when selecting a new Drawable into a view, so that the previous 18525 * one is completely unscheduled. 18526 * 18527 * @param who The Drawable to unschedule. 18528 * 18529 * @see #drawableStateChanged 18530 */ 18531 public void unscheduleDrawable(Drawable who) { 18532 if (mAttachInfo != null && who != null) { 18533 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18534 Choreographer.CALLBACK_ANIMATION, null, who); 18535 } 18536 } 18537 18538 /** 18539 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 18540 * that the View directionality can and will be resolved before its Drawables. 18541 * 18542 * Will call {@link View#onResolveDrawables} when resolution is done. 18543 * 18544 * @hide 18545 */ 18546 protected void resolveDrawables() { 18547 // Drawables resolution may need to happen before resolving the layout direction (which is 18548 // done only during the measure() call). 18549 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 18550 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 18551 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 18552 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 18553 // direction to be resolved as its resolved value will be the same as its raw value. 18554 if (!isLayoutDirectionResolved() && 18555 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 18556 return; 18557 } 18558 18559 final int layoutDirection = isLayoutDirectionResolved() ? 18560 getLayoutDirection() : getRawLayoutDirection(); 18561 18562 if (mBackground != null) { 18563 mBackground.setLayoutDirection(layoutDirection); 18564 } 18565 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18566 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 18567 } 18568 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 18569 onResolveDrawables(layoutDirection); 18570 } 18571 18572 boolean areDrawablesResolved() { 18573 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 18574 } 18575 18576 /** 18577 * Called when layout direction has been resolved. 18578 * 18579 * The default implementation does nothing. 18580 * 18581 * @param layoutDirection The resolved layout direction. 18582 * 18583 * @see #LAYOUT_DIRECTION_LTR 18584 * @see #LAYOUT_DIRECTION_RTL 18585 * 18586 * @hide 18587 */ 18588 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 18589 } 18590 18591 /** 18592 * @hide 18593 */ 18594 protected void resetResolvedDrawables() { 18595 resetResolvedDrawablesInternal(); 18596 } 18597 18598 void resetResolvedDrawablesInternal() { 18599 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 18600 } 18601 18602 /** 18603 * If your view subclass is displaying its own Drawable objects, it should 18604 * override this function and return true for any Drawable it is 18605 * displaying. This allows animations for those drawables to be 18606 * scheduled. 18607 * 18608 * <p>Be sure to call through to the super class when overriding this 18609 * function. 18610 * 18611 * @param who The Drawable to verify. Return true if it is one you are 18612 * displaying, else return the result of calling through to the 18613 * super class. 18614 * 18615 * @return boolean If true than the Drawable is being displayed in the 18616 * view; else false and it is not allowed to animate. 18617 * 18618 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 18619 * @see #drawableStateChanged() 18620 */ 18621 @CallSuper 18622 protected boolean verifyDrawable(@NonNull Drawable who) { 18623 // Avoid verifying the scroll bar drawable so that we don't end up in 18624 // an invalidation loop. This effectively prevents the scroll bar 18625 // drawable from triggering invalidations and scheduling runnables. 18626 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); 18627 } 18628 18629 /** 18630 * This function is called whenever the state of the view changes in such 18631 * a way that it impacts the state of drawables being shown. 18632 * <p> 18633 * If the View has a StateListAnimator, it will also be called to run necessary state 18634 * change animations. 18635 * <p> 18636 * Be sure to call through to the superclass when overriding this function. 18637 * 18638 * @see Drawable#setState(int[]) 18639 */ 18640 @CallSuper 18641 protected void drawableStateChanged() { 18642 final int[] state = getDrawableState(); 18643 boolean changed = false; 18644 18645 final Drawable bg = mBackground; 18646 if (bg != null && bg.isStateful()) { 18647 changed |= bg.setState(state); 18648 } 18649 18650 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 18651 if (fg != null && fg.isStateful()) { 18652 changed |= fg.setState(state); 18653 } 18654 18655 if (mScrollCache != null) { 18656 final Drawable scrollBar = mScrollCache.scrollBar; 18657 if (scrollBar != null && scrollBar.isStateful()) { 18658 changed |= scrollBar.setState(state) 18659 && mScrollCache.state != ScrollabilityCache.OFF; 18660 } 18661 } 18662 18663 if (mStateListAnimator != null) { 18664 mStateListAnimator.setState(state); 18665 } 18666 18667 if (changed) { 18668 invalidate(); 18669 } 18670 } 18671 18672 /** 18673 * This function is called whenever the view hotspot changes and needs to 18674 * be propagated to drawables or child views managed by the view. 18675 * <p> 18676 * Dispatching to child views is handled by 18677 * {@link #dispatchDrawableHotspotChanged(float, float)}. 18678 * <p> 18679 * Be sure to call through to the superclass when overriding this function. 18680 * 18681 * @param x hotspot x coordinate 18682 * @param y hotspot y coordinate 18683 */ 18684 @CallSuper 18685 public void drawableHotspotChanged(float x, float y) { 18686 if (mBackground != null) { 18687 mBackground.setHotspot(x, y); 18688 } 18689 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18690 mForegroundInfo.mDrawable.setHotspot(x, y); 18691 } 18692 18693 dispatchDrawableHotspotChanged(x, y); 18694 } 18695 18696 /** 18697 * Dispatches drawableHotspotChanged to all of this View's children. 18698 * 18699 * @param x hotspot x coordinate 18700 * @param y hotspot y coordinate 18701 * @see #drawableHotspotChanged(float, float) 18702 */ 18703 public void dispatchDrawableHotspotChanged(float x, float y) { 18704 } 18705 18706 /** 18707 * Call this to force a view to update its drawable state. This will cause 18708 * drawableStateChanged to be called on this view. Views that are interested 18709 * in the new state should call getDrawableState. 18710 * 18711 * @see #drawableStateChanged 18712 * @see #getDrawableState 18713 */ 18714 public void refreshDrawableState() { 18715 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 18716 drawableStateChanged(); 18717 18718 ViewParent parent = mParent; 18719 if (parent != null) { 18720 parent.childDrawableStateChanged(this); 18721 } 18722 } 18723 18724 /** 18725 * Return an array of resource IDs of the drawable states representing the 18726 * current state of the view. 18727 * 18728 * @return The current drawable state 18729 * 18730 * @see Drawable#setState(int[]) 18731 * @see #drawableStateChanged() 18732 * @see #onCreateDrawableState(int) 18733 */ 18734 public final int[] getDrawableState() { 18735 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 18736 return mDrawableState; 18737 } else { 18738 mDrawableState = onCreateDrawableState(0); 18739 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 18740 return mDrawableState; 18741 } 18742 } 18743 18744 /** 18745 * Generate the new {@link android.graphics.drawable.Drawable} state for 18746 * this view. This is called by the view 18747 * system when the cached Drawable state is determined to be invalid. To 18748 * retrieve the current state, you should use {@link #getDrawableState}. 18749 * 18750 * @param extraSpace if non-zero, this is the number of extra entries you 18751 * would like in the returned array in which you can place your own 18752 * states. 18753 * 18754 * @return Returns an array holding the current {@link Drawable} state of 18755 * the view. 18756 * 18757 * @see #mergeDrawableStates(int[], int[]) 18758 */ 18759 protected int[] onCreateDrawableState(int extraSpace) { 18760 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 18761 mParent instanceof View) { 18762 return ((View) mParent).onCreateDrawableState(extraSpace); 18763 } 18764 18765 int[] drawableState; 18766 18767 int privateFlags = mPrivateFlags; 18768 18769 int viewStateIndex = 0; 18770 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 18771 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 18772 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 18773 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 18774 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 18775 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 18776 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 18777 ThreadedRenderer.isAvailable()) { 18778 // This is set if HW acceleration is requested, even if the current 18779 // process doesn't allow it. This is just to allow app preview 18780 // windows to better match their app. 18781 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 18782 } 18783 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 18784 18785 final int privateFlags2 = mPrivateFlags2; 18786 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 18787 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 18788 } 18789 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 18790 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 18791 } 18792 18793 drawableState = StateSet.get(viewStateIndex); 18794 18795 //noinspection ConstantIfStatement 18796 if (false) { 18797 Log.i("View", "drawableStateIndex=" + viewStateIndex); 18798 Log.i("View", toString() 18799 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 18800 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 18801 + " fo=" + hasFocus() 18802 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 18803 + " wf=" + hasWindowFocus() 18804 + ": " + Arrays.toString(drawableState)); 18805 } 18806 18807 if (extraSpace == 0) { 18808 return drawableState; 18809 } 18810 18811 final int[] fullState; 18812 if (drawableState != null) { 18813 fullState = new int[drawableState.length + extraSpace]; 18814 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 18815 } else { 18816 fullState = new int[extraSpace]; 18817 } 18818 18819 return fullState; 18820 } 18821 18822 /** 18823 * Merge your own state values in <var>additionalState</var> into the base 18824 * state values <var>baseState</var> that were returned by 18825 * {@link #onCreateDrawableState(int)}. 18826 * 18827 * @param baseState The base state values returned by 18828 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 18829 * own additional state values. 18830 * 18831 * @param additionalState The additional state values you would like 18832 * added to <var>baseState</var>; this array is not modified. 18833 * 18834 * @return As a convenience, the <var>baseState</var> array you originally 18835 * passed into the function is returned. 18836 * 18837 * @see #onCreateDrawableState(int) 18838 */ 18839 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 18840 final int N = baseState.length; 18841 int i = N - 1; 18842 while (i >= 0 && baseState[i] == 0) { 18843 i--; 18844 } 18845 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 18846 return baseState; 18847 } 18848 18849 /** 18850 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 18851 * on all Drawable objects associated with this view. 18852 * <p> 18853 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 18854 * attached to this view. 18855 */ 18856 @CallSuper 18857 public void jumpDrawablesToCurrentState() { 18858 if (mBackground != null) { 18859 mBackground.jumpToCurrentState(); 18860 } 18861 if (mStateListAnimator != null) { 18862 mStateListAnimator.jumpToCurrentState(); 18863 } 18864 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18865 mForegroundInfo.mDrawable.jumpToCurrentState(); 18866 } 18867 } 18868 18869 /** 18870 * Sets the background color for this view. 18871 * @param color the color of the background 18872 */ 18873 @RemotableViewMethod 18874 public void setBackgroundColor(@ColorInt int color) { 18875 if (mBackground instanceof ColorDrawable) { 18876 ((ColorDrawable) mBackground.mutate()).setColor(color); 18877 computeOpaqueFlags(); 18878 mBackgroundResource = 0; 18879 } else { 18880 setBackground(new ColorDrawable(color)); 18881 } 18882 } 18883 18884 /** 18885 * Set the background to a given resource. The resource should refer to 18886 * a Drawable object or 0 to remove the background. 18887 * @param resid The identifier of the resource. 18888 * 18889 * @attr ref android.R.styleable#View_background 18890 */ 18891 @RemotableViewMethod 18892 public void setBackgroundResource(@DrawableRes int resid) { 18893 if (resid != 0 && resid == mBackgroundResource) { 18894 return; 18895 } 18896 18897 Drawable d = null; 18898 if (resid != 0) { 18899 d = mContext.getDrawable(resid); 18900 } 18901 setBackground(d); 18902 18903 mBackgroundResource = resid; 18904 } 18905 18906 /** 18907 * Set the background to a given Drawable, or remove the background. If the 18908 * background has padding, this View's padding is set to the background's 18909 * padding. However, when a background is removed, this View's padding isn't 18910 * touched. If setting the padding is desired, please use 18911 * {@link #setPadding(int, int, int, int)}. 18912 * 18913 * @param background The Drawable to use as the background, or null to remove the 18914 * background 18915 */ 18916 public void setBackground(Drawable background) { 18917 //noinspection deprecation 18918 setBackgroundDrawable(background); 18919 } 18920 18921 /** 18922 * @deprecated use {@link #setBackground(Drawable)} instead 18923 */ 18924 @Deprecated 18925 public void setBackgroundDrawable(Drawable background) { 18926 computeOpaqueFlags(); 18927 18928 if (background == mBackground) { 18929 return; 18930 } 18931 18932 boolean requestLayout = false; 18933 18934 mBackgroundResource = 0; 18935 18936 /* 18937 * Regardless of whether we're setting a new background or not, we want 18938 * to clear the previous drawable. setVisible first while we still have the callback set. 18939 */ 18940 if (mBackground != null) { 18941 if (isAttachedToWindow()) { 18942 mBackground.setVisible(false, false); 18943 } 18944 mBackground.setCallback(null); 18945 unscheduleDrawable(mBackground); 18946 } 18947 18948 if (background != null) { 18949 Rect padding = sThreadLocal.get(); 18950 if (padding == null) { 18951 padding = new Rect(); 18952 sThreadLocal.set(padding); 18953 } 18954 resetResolvedDrawablesInternal(); 18955 background.setLayoutDirection(getLayoutDirection()); 18956 if (background.getPadding(padding)) { 18957 resetResolvedPaddingInternal(); 18958 switch (background.getLayoutDirection()) { 18959 case LAYOUT_DIRECTION_RTL: 18960 mUserPaddingLeftInitial = padding.right; 18961 mUserPaddingRightInitial = padding.left; 18962 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 18963 break; 18964 case LAYOUT_DIRECTION_LTR: 18965 default: 18966 mUserPaddingLeftInitial = padding.left; 18967 mUserPaddingRightInitial = padding.right; 18968 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 18969 } 18970 mLeftPaddingDefined = false; 18971 mRightPaddingDefined = false; 18972 } 18973 18974 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 18975 // if it has a different minimum size, we should layout again 18976 if (mBackground == null 18977 || mBackground.getMinimumHeight() != background.getMinimumHeight() 18978 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 18979 requestLayout = true; 18980 } 18981 18982 // Set mBackground before we set this as the callback and start making other 18983 // background drawable state change calls. In particular, the setVisible call below 18984 // can result in drawables attempting to start animations or otherwise invalidate, 18985 // which requires the view set as the callback (us) to recognize the drawable as 18986 // belonging to it as per verifyDrawable. 18987 mBackground = background; 18988 if (background.isStateful()) { 18989 background.setState(getDrawableState()); 18990 } 18991 if (isAttachedToWindow()) { 18992 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 18993 } 18994 18995 applyBackgroundTint(); 18996 18997 // Set callback last, since the view may still be initializing. 18998 background.setCallback(this); 18999 19000 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19001 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19002 requestLayout = true; 19003 } 19004 } else { 19005 /* Remove the background */ 19006 mBackground = null; 19007 if ((mViewFlags & WILL_NOT_DRAW) != 0 19008 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 19009 mPrivateFlags |= PFLAG_SKIP_DRAW; 19010 } 19011 19012 /* 19013 * When the background is set, we try to apply its padding to this 19014 * View. When the background is removed, we don't touch this View's 19015 * padding. This is noted in the Javadocs. Hence, we don't need to 19016 * requestLayout(), the invalidate() below is sufficient. 19017 */ 19018 19019 // The old background's minimum size could have affected this 19020 // View's layout, so let's requestLayout 19021 requestLayout = true; 19022 } 19023 19024 computeOpaqueFlags(); 19025 19026 if (requestLayout) { 19027 requestLayout(); 19028 } 19029 19030 mBackgroundSizeChanged = true; 19031 invalidate(true); 19032 invalidateOutline(); 19033 } 19034 19035 /** 19036 * Gets the background drawable 19037 * 19038 * @return The drawable used as the background for this view, if any. 19039 * 19040 * @see #setBackground(Drawable) 19041 * 19042 * @attr ref android.R.styleable#View_background 19043 */ 19044 public Drawable getBackground() { 19045 return mBackground; 19046 } 19047 19048 /** 19049 * Applies a tint to the background drawable. Does not modify the current tint 19050 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19051 * <p> 19052 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 19053 * mutate the drawable and apply the specified tint and tint mode using 19054 * {@link Drawable#setTintList(ColorStateList)}. 19055 * 19056 * @param tint the tint to apply, may be {@code null} to clear tint 19057 * 19058 * @attr ref android.R.styleable#View_backgroundTint 19059 * @see #getBackgroundTintList() 19060 * @see Drawable#setTintList(ColorStateList) 19061 */ 19062 public void setBackgroundTintList(@Nullable ColorStateList tint) { 19063 if (mBackgroundTint == null) { 19064 mBackgroundTint = new TintInfo(); 19065 } 19066 mBackgroundTint.mTintList = tint; 19067 mBackgroundTint.mHasTintList = true; 19068 19069 applyBackgroundTint(); 19070 } 19071 19072 /** 19073 * Return the tint applied to the background drawable, if specified. 19074 * 19075 * @return the tint applied to the background drawable 19076 * @attr ref android.R.styleable#View_backgroundTint 19077 * @see #setBackgroundTintList(ColorStateList) 19078 */ 19079 @Nullable 19080 public ColorStateList getBackgroundTintList() { 19081 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 19082 } 19083 19084 /** 19085 * Specifies the blending mode used to apply the tint specified by 19086 * {@link #setBackgroundTintList(ColorStateList)}} to the background 19087 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19088 * 19089 * @param tintMode the blending mode used to apply the tint, may be 19090 * {@code null} to clear tint 19091 * @attr ref android.R.styleable#View_backgroundTintMode 19092 * @see #getBackgroundTintMode() 19093 * @see Drawable#setTintMode(PorterDuff.Mode) 19094 */ 19095 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19096 if (mBackgroundTint == null) { 19097 mBackgroundTint = new TintInfo(); 19098 } 19099 mBackgroundTint.mTintMode = tintMode; 19100 mBackgroundTint.mHasTintMode = true; 19101 19102 applyBackgroundTint(); 19103 } 19104 19105 /** 19106 * Return the blending mode used to apply the tint to the background 19107 * drawable, if specified. 19108 * 19109 * @return the blending mode used to apply the tint to the background 19110 * drawable 19111 * @attr ref android.R.styleable#View_backgroundTintMode 19112 * @see #setBackgroundTintMode(PorterDuff.Mode) 19113 */ 19114 @Nullable 19115 public PorterDuff.Mode getBackgroundTintMode() { 19116 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 19117 } 19118 19119 private void applyBackgroundTint() { 19120 if (mBackground != null && mBackgroundTint != null) { 19121 final TintInfo tintInfo = mBackgroundTint; 19122 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19123 mBackground = mBackground.mutate(); 19124 19125 if (tintInfo.mHasTintList) { 19126 mBackground.setTintList(tintInfo.mTintList); 19127 } 19128 19129 if (tintInfo.mHasTintMode) { 19130 mBackground.setTintMode(tintInfo.mTintMode); 19131 } 19132 19133 // The drawable (or one of its children) may not have been 19134 // stateful before applying the tint, so let's try again. 19135 if (mBackground.isStateful()) { 19136 mBackground.setState(getDrawableState()); 19137 } 19138 } 19139 } 19140 } 19141 19142 /** 19143 * Returns the drawable used as the foreground of this View. The 19144 * foreground drawable, if non-null, is always drawn on top of the view's content. 19145 * 19146 * @return a Drawable or null if no foreground was set 19147 * 19148 * @see #onDrawForeground(Canvas) 19149 */ 19150 public Drawable getForeground() { 19151 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19152 } 19153 19154 /** 19155 * Supply a Drawable that is to be rendered on top of all of the content in the view. 19156 * 19157 * @param foreground the Drawable to be drawn on top of the children 19158 * 19159 * @attr ref android.R.styleable#View_foreground 19160 */ 19161 public void setForeground(Drawable foreground) { 19162 if (mForegroundInfo == null) { 19163 if (foreground == null) { 19164 // Nothing to do. 19165 return; 19166 } 19167 mForegroundInfo = new ForegroundInfo(); 19168 } 19169 19170 if (foreground == mForegroundInfo.mDrawable) { 19171 // Nothing to do 19172 return; 19173 } 19174 19175 if (mForegroundInfo.mDrawable != null) { 19176 if (isAttachedToWindow()) { 19177 mForegroundInfo.mDrawable.setVisible(false, false); 19178 } 19179 mForegroundInfo.mDrawable.setCallback(null); 19180 unscheduleDrawable(mForegroundInfo.mDrawable); 19181 } 19182 19183 mForegroundInfo.mDrawable = foreground; 19184 mForegroundInfo.mBoundsChanged = true; 19185 if (foreground != null) { 19186 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19187 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19188 } 19189 foreground.setLayoutDirection(getLayoutDirection()); 19190 if (foreground.isStateful()) { 19191 foreground.setState(getDrawableState()); 19192 } 19193 applyForegroundTint(); 19194 if (isAttachedToWindow()) { 19195 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 19196 } 19197 // Set callback last, since the view may still be initializing. 19198 foreground.setCallback(this); 19199 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) { 19200 mPrivateFlags |= PFLAG_SKIP_DRAW; 19201 } 19202 requestLayout(); 19203 invalidate(); 19204 } 19205 19206 /** 19207 * Magic bit used to support features of framework-internal window decor implementation details. 19208 * This used to live exclusively in FrameLayout. 19209 * 19210 * @return true if the foreground should draw inside the padding region or false 19211 * if it should draw inset by the view's padding 19212 * @hide internal use only; only used by FrameLayout and internal screen layouts. 19213 */ 19214 public boolean isForegroundInsidePadding() { 19215 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 19216 } 19217 19218 /** 19219 * Describes how the foreground is positioned. 19220 * 19221 * @return foreground gravity. 19222 * 19223 * @see #setForegroundGravity(int) 19224 * 19225 * @attr ref android.R.styleable#View_foregroundGravity 19226 */ 19227 public int getForegroundGravity() { 19228 return mForegroundInfo != null ? mForegroundInfo.mGravity 19229 : Gravity.START | Gravity.TOP; 19230 } 19231 19232 /** 19233 * Describes how the foreground is positioned. Defaults to START and TOP. 19234 * 19235 * @param gravity see {@link android.view.Gravity} 19236 * 19237 * @see #getForegroundGravity() 19238 * 19239 * @attr ref android.R.styleable#View_foregroundGravity 19240 */ 19241 public void setForegroundGravity(int gravity) { 19242 if (mForegroundInfo == null) { 19243 mForegroundInfo = new ForegroundInfo(); 19244 } 19245 19246 if (mForegroundInfo.mGravity != gravity) { 19247 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 19248 gravity |= Gravity.START; 19249 } 19250 19251 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 19252 gravity |= Gravity.TOP; 19253 } 19254 19255 mForegroundInfo.mGravity = gravity; 19256 requestLayout(); 19257 } 19258 } 19259 19260 /** 19261 * Applies a tint to the foreground drawable. Does not modify the current tint 19262 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19263 * <p> 19264 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 19265 * mutate the drawable and apply the specified tint and tint mode using 19266 * {@link Drawable#setTintList(ColorStateList)}. 19267 * 19268 * @param tint the tint to apply, may be {@code null} to clear tint 19269 * 19270 * @attr ref android.R.styleable#View_foregroundTint 19271 * @see #getForegroundTintList() 19272 * @see Drawable#setTintList(ColorStateList) 19273 */ 19274 public void setForegroundTintList(@Nullable ColorStateList tint) { 19275 if (mForegroundInfo == null) { 19276 mForegroundInfo = new ForegroundInfo(); 19277 } 19278 if (mForegroundInfo.mTintInfo == null) { 19279 mForegroundInfo.mTintInfo = new TintInfo(); 19280 } 19281 mForegroundInfo.mTintInfo.mTintList = tint; 19282 mForegroundInfo.mTintInfo.mHasTintList = true; 19283 19284 applyForegroundTint(); 19285 } 19286 19287 /** 19288 * Return the tint applied to the foreground drawable, if specified. 19289 * 19290 * @return the tint applied to the foreground drawable 19291 * @attr ref android.R.styleable#View_foregroundTint 19292 * @see #setForegroundTintList(ColorStateList) 19293 */ 19294 @Nullable 19295 public ColorStateList getForegroundTintList() { 19296 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19297 ? mForegroundInfo.mTintInfo.mTintList : null; 19298 } 19299 19300 /** 19301 * Specifies the blending mode used to apply the tint specified by 19302 * {@link #setForegroundTintList(ColorStateList)}} to the background 19303 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19304 * 19305 * @param tintMode the blending mode used to apply the tint, may be 19306 * {@code null} to clear tint 19307 * @attr ref android.R.styleable#View_foregroundTintMode 19308 * @see #getForegroundTintMode() 19309 * @see Drawable#setTintMode(PorterDuff.Mode) 19310 */ 19311 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19312 if (mForegroundInfo == null) { 19313 mForegroundInfo = new ForegroundInfo(); 19314 } 19315 if (mForegroundInfo.mTintInfo == null) { 19316 mForegroundInfo.mTintInfo = new TintInfo(); 19317 } 19318 mForegroundInfo.mTintInfo.mTintMode = tintMode; 19319 mForegroundInfo.mTintInfo.mHasTintMode = true; 19320 19321 applyForegroundTint(); 19322 } 19323 19324 /** 19325 * Return the blending mode used to apply the tint to the foreground 19326 * drawable, if specified. 19327 * 19328 * @return the blending mode used to apply the tint to the foreground 19329 * drawable 19330 * @attr ref android.R.styleable#View_foregroundTintMode 19331 * @see #setForegroundTintMode(PorterDuff.Mode) 19332 */ 19333 @Nullable 19334 public PorterDuff.Mode getForegroundTintMode() { 19335 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19336 ? mForegroundInfo.mTintInfo.mTintMode : null; 19337 } 19338 19339 private void applyForegroundTint() { 19340 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 19341 && mForegroundInfo.mTintInfo != null) { 19342 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 19343 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19344 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 19345 19346 if (tintInfo.mHasTintList) { 19347 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 19348 } 19349 19350 if (tintInfo.mHasTintMode) { 19351 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 19352 } 19353 19354 // The drawable (or one of its children) may not have been 19355 // stateful before applying the tint, so let's try again. 19356 if (mForegroundInfo.mDrawable.isStateful()) { 19357 mForegroundInfo.mDrawable.setState(getDrawableState()); 19358 } 19359 } 19360 } 19361 } 19362 19363 /** 19364 * Draw any foreground content for this view. 19365 * 19366 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 19367 * drawable or other view-specific decorations. The foreground is drawn on top of the 19368 * primary view content.</p> 19369 * 19370 * @param canvas canvas to draw into 19371 */ 19372 public void onDrawForeground(Canvas canvas) { 19373 onDrawScrollIndicators(canvas); 19374 onDrawScrollBars(canvas); 19375 19376 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19377 if (foreground != null) { 19378 if (mForegroundInfo.mBoundsChanged) { 19379 mForegroundInfo.mBoundsChanged = false; 19380 final Rect selfBounds = mForegroundInfo.mSelfBounds; 19381 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 19382 19383 if (mForegroundInfo.mInsidePadding) { 19384 selfBounds.set(0, 0, getWidth(), getHeight()); 19385 } else { 19386 selfBounds.set(getPaddingLeft(), getPaddingTop(), 19387 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 19388 } 19389 19390 final int ld = getLayoutDirection(); 19391 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 19392 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 19393 foreground.setBounds(overlayBounds); 19394 } 19395 19396 foreground.draw(canvas); 19397 } 19398 } 19399 19400 /** 19401 * Sets the padding. The view may add on the space required to display 19402 * the scrollbars, depending on the style and visibility of the scrollbars. 19403 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 19404 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 19405 * from the values set in this call. 19406 * 19407 * @attr ref android.R.styleable#View_padding 19408 * @attr ref android.R.styleable#View_paddingBottom 19409 * @attr ref android.R.styleable#View_paddingLeft 19410 * @attr ref android.R.styleable#View_paddingRight 19411 * @attr ref android.R.styleable#View_paddingTop 19412 * @param left the left padding in pixels 19413 * @param top the top padding in pixels 19414 * @param right the right padding in pixels 19415 * @param bottom the bottom padding in pixels 19416 */ 19417 public void setPadding(int left, int top, int right, int bottom) { 19418 resetResolvedPaddingInternal(); 19419 19420 mUserPaddingStart = UNDEFINED_PADDING; 19421 mUserPaddingEnd = UNDEFINED_PADDING; 19422 19423 mUserPaddingLeftInitial = left; 19424 mUserPaddingRightInitial = right; 19425 19426 mLeftPaddingDefined = true; 19427 mRightPaddingDefined = true; 19428 19429 internalSetPadding(left, top, right, bottom); 19430 } 19431 19432 /** 19433 * @hide 19434 */ 19435 protected void internalSetPadding(int left, int top, int right, int bottom) { 19436 mUserPaddingLeft = left; 19437 mUserPaddingRight = right; 19438 mUserPaddingBottom = bottom; 19439 19440 final int viewFlags = mViewFlags; 19441 boolean changed = false; 19442 19443 // Common case is there are no scroll bars. 19444 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 19445 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 19446 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 19447 ? 0 : getVerticalScrollbarWidth(); 19448 switch (mVerticalScrollbarPosition) { 19449 case SCROLLBAR_POSITION_DEFAULT: 19450 if (isLayoutRtl()) { 19451 left += offset; 19452 } else { 19453 right += offset; 19454 } 19455 break; 19456 case SCROLLBAR_POSITION_RIGHT: 19457 right += offset; 19458 break; 19459 case SCROLLBAR_POSITION_LEFT: 19460 left += offset; 19461 break; 19462 } 19463 } 19464 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 19465 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 19466 ? 0 : getHorizontalScrollbarHeight(); 19467 } 19468 } 19469 19470 if (mPaddingLeft != left) { 19471 changed = true; 19472 mPaddingLeft = left; 19473 } 19474 if (mPaddingTop != top) { 19475 changed = true; 19476 mPaddingTop = top; 19477 } 19478 if (mPaddingRight != right) { 19479 changed = true; 19480 mPaddingRight = right; 19481 } 19482 if (mPaddingBottom != bottom) { 19483 changed = true; 19484 mPaddingBottom = bottom; 19485 } 19486 19487 if (changed) { 19488 requestLayout(); 19489 invalidateOutline(); 19490 } 19491 } 19492 19493 /** 19494 * Sets the relative padding. The view may add on the space required to display 19495 * the scrollbars, depending on the style and visibility of the scrollbars. 19496 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 19497 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 19498 * from the values set in this call. 19499 * 19500 * @attr ref android.R.styleable#View_padding 19501 * @attr ref android.R.styleable#View_paddingBottom 19502 * @attr ref android.R.styleable#View_paddingStart 19503 * @attr ref android.R.styleable#View_paddingEnd 19504 * @attr ref android.R.styleable#View_paddingTop 19505 * @param start the start padding in pixels 19506 * @param top the top padding in pixels 19507 * @param end the end padding in pixels 19508 * @param bottom the bottom padding in pixels 19509 */ 19510 public void setPaddingRelative(int start, int top, int end, int bottom) { 19511 resetResolvedPaddingInternal(); 19512 19513 mUserPaddingStart = start; 19514 mUserPaddingEnd = end; 19515 mLeftPaddingDefined = true; 19516 mRightPaddingDefined = true; 19517 19518 switch(getLayoutDirection()) { 19519 case LAYOUT_DIRECTION_RTL: 19520 mUserPaddingLeftInitial = end; 19521 mUserPaddingRightInitial = start; 19522 internalSetPadding(end, top, start, bottom); 19523 break; 19524 case LAYOUT_DIRECTION_LTR: 19525 default: 19526 mUserPaddingLeftInitial = start; 19527 mUserPaddingRightInitial = end; 19528 internalSetPadding(start, top, end, bottom); 19529 } 19530 } 19531 19532 /** 19533 * Returns the top padding of this view. 19534 * 19535 * @return the top padding in pixels 19536 */ 19537 public int getPaddingTop() { 19538 return mPaddingTop; 19539 } 19540 19541 /** 19542 * Returns the bottom padding of this view. If there are inset and enabled 19543 * scrollbars, this value may include the space required to display the 19544 * scrollbars as well. 19545 * 19546 * @return the bottom padding in pixels 19547 */ 19548 public int getPaddingBottom() { 19549 return mPaddingBottom; 19550 } 19551 19552 /** 19553 * Returns the left padding of this view. If there are inset and enabled 19554 * scrollbars, this value may include the space required to display the 19555 * scrollbars as well. 19556 * 19557 * @return the left padding in pixels 19558 */ 19559 public int getPaddingLeft() { 19560 if (!isPaddingResolved()) { 19561 resolvePadding(); 19562 } 19563 return mPaddingLeft; 19564 } 19565 19566 /** 19567 * Returns the start padding of this view depending on its resolved layout direction. 19568 * If there are inset and enabled scrollbars, this value may include the space 19569 * required to display the scrollbars as well. 19570 * 19571 * @return the start padding in pixels 19572 */ 19573 public int getPaddingStart() { 19574 if (!isPaddingResolved()) { 19575 resolvePadding(); 19576 } 19577 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19578 mPaddingRight : mPaddingLeft; 19579 } 19580 19581 /** 19582 * Returns the right padding of this view. If there are inset and enabled 19583 * scrollbars, this value may include the space required to display the 19584 * scrollbars as well. 19585 * 19586 * @return the right padding in pixels 19587 */ 19588 public int getPaddingRight() { 19589 if (!isPaddingResolved()) { 19590 resolvePadding(); 19591 } 19592 return mPaddingRight; 19593 } 19594 19595 /** 19596 * Returns the end padding of this view depending on its resolved layout direction. 19597 * If there are inset and enabled scrollbars, this value may include the space 19598 * required to display the scrollbars as well. 19599 * 19600 * @return the end padding in pixels 19601 */ 19602 public int getPaddingEnd() { 19603 if (!isPaddingResolved()) { 19604 resolvePadding(); 19605 } 19606 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19607 mPaddingLeft : mPaddingRight; 19608 } 19609 19610 /** 19611 * Return if the padding has been set through relative values 19612 * {@link #setPaddingRelative(int, int, int, int)} or through 19613 * @attr ref android.R.styleable#View_paddingStart or 19614 * @attr ref android.R.styleable#View_paddingEnd 19615 * 19616 * @return true if the padding is relative or false if it is not. 19617 */ 19618 public boolean isPaddingRelative() { 19619 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 19620 } 19621 19622 Insets computeOpticalInsets() { 19623 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 19624 } 19625 19626 /** 19627 * @hide 19628 */ 19629 public void resetPaddingToInitialValues() { 19630 if (isRtlCompatibilityMode()) { 19631 mPaddingLeft = mUserPaddingLeftInitial; 19632 mPaddingRight = mUserPaddingRightInitial; 19633 return; 19634 } 19635 if (isLayoutRtl()) { 19636 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 19637 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 19638 } else { 19639 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 19640 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 19641 } 19642 } 19643 19644 /** 19645 * @hide 19646 */ 19647 public Insets getOpticalInsets() { 19648 if (mLayoutInsets == null) { 19649 mLayoutInsets = computeOpticalInsets(); 19650 } 19651 return mLayoutInsets; 19652 } 19653 19654 /** 19655 * Set this view's optical insets. 19656 * 19657 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 19658 * property. Views that compute their own optical insets should call it as part of measurement. 19659 * This method does not request layout. If you are setting optical insets outside of 19660 * measure/layout itself you will want to call requestLayout() yourself. 19661 * </p> 19662 * @hide 19663 */ 19664 public void setOpticalInsets(Insets insets) { 19665 mLayoutInsets = insets; 19666 } 19667 19668 /** 19669 * Changes the selection state of this view. A view can be selected or not. 19670 * Note that selection is not the same as focus. Views are typically 19671 * selected in the context of an AdapterView like ListView or GridView; 19672 * the selected view is the view that is highlighted. 19673 * 19674 * @param selected true if the view must be selected, false otherwise 19675 */ 19676 public void setSelected(boolean selected) { 19677 //noinspection DoubleNegation 19678 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 19679 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 19680 if (!selected) resetPressedState(); 19681 invalidate(true); 19682 refreshDrawableState(); 19683 dispatchSetSelected(selected); 19684 if (selected) { 19685 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 19686 } else { 19687 notifyViewAccessibilityStateChangedIfNeeded( 19688 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 19689 } 19690 } 19691 } 19692 19693 /** 19694 * Dispatch setSelected to all of this View's children. 19695 * 19696 * @see #setSelected(boolean) 19697 * 19698 * @param selected The new selected state 19699 */ 19700 protected void dispatchSetSelected(boolean selected) { 19701 } 19702 19703 /** 19704 * Indicates the selection state of this view. 19705 * 19706 * @return true if the view is selected, false otherwise 19707 */ 19708 @ViewDebug.ExportedProperty 19709 public boolean isSelected() { 19710 return (mPrivateFlags & PFLAG_SELECTED) != 0; 19711 } 19712 19713 /** 19714 * Changes the activated state of this view. A view can be activated or not. 19715 * Note that activation is not the same as selection. Selection is 19716 * a transient property, representing the view (hierarchy) the user is 19717 * currently interacting with. Activation is a longer-term state that the 19718 * user can move views in and out of. For example, in a list view with 19719 * single or multiple selection enabled, the views in the current selection 19720 * set are activated. (Um, yeah, we are deeply sorry about the terminology 19721 * here.) The activated state is propagated down to children of the view it 19722 * is set on. 19723 * 19724 * @param activated true if the view must be activated, false otherwise 19725 */ 19726 public void setActivated(boolean activated) { 19727 //noinspection DoubleNegation 19728 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 19729 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 19730 invalidate(true); 19731 refreshDrawableState(); 19732 dispatchSetActivated(activated); 19733 } 19734 } 19735 19736 /** 19737 * Dispatch setActivated to all of this View's children. 19738 * 19739 * @see #setActivated(boolean) 19740 * 19741 * @param activated The new activated state 19742 */ 19743 protected void dispatchSetActivated(boolean activated) { 19744 } 19745 19746 /** 19747 * Indicates the activation state of this view. 19748 * 19749 * @return true if the view is activated, false otherwise 19750 */ 19751 @ViewDebug.ExportedProperty 19752 public boolean isActivated() { 19753 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 19754 } 19755 19756 /** 19757 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 19758 * observer can be used to get notifications when global events, like 19759 * layout, happen. 19760 * 19761 * The returned ViewTreeObserver observer is not guaranteed to remain 19762 * valid for the lifetime of this View. If the caller of this method keeps 19763 * a long-lived reference to ViewTreeObserver, it should always check for 19764 * the return value of {@link ViewTreeObserver#isAlive()}. 19765 * 19766 * @return The ViewTreeObserver for this view's hierarchy. 19767 */ 19768 public ViewTreeObserver getViewTreeObserver() { 19769 if (mAttachInfo != null) { 19770 return mAttachInfo.mTreeObserver; 19771 } 19772 if (mFloatingTreeObserver == null) { 19773 mFloatingTreeObserver = new ViewTreeObserver(mContext); 19774 } 19775 return mFloatingTreeObserver; 19776 } 19777 19778 /** 19779 * <p>Finds the topmost view in the current view hierarchy.</p> 19780 * 19781 * @return the topmost view containing this view 19782 */ 19783 public View getRootView() { 19784 if (mAttachInfo != null) { 19785 final View v = mAttachInfo.mRootView; 19786 if (v != null) { 19787 return v; 19788 } 19789 } 19790 19791 View parent = this; 19792 19793 while (parent.mParent != null && parent.mParent instanceof View) { 19794 parent = (View) parent.mParent; 19795 } 19796 19797 return parent; 19798 } 19799 19800 /** 19801 * Transforms a motion event from view-local coordinates to on-screen 19802 * coordinates. 19803 * 19804 * @param ev the view-local motion event 19805 * @return false if the transformation could not be applied 19806 * @hide 19807 */ 19808 public boolean toGlobalMotionEvent(MotionEvent ev) { 19809 final AttachInfo info = mAttachInfo; 19810 if (info == null) { 19811 return false; 19812 } 19813 19814 final Matrix m = info.mTmpMatrix; 19815 m.set(Matrix.IDENTITY_MATRIX); 19816 transformMatrixToGlobal(m); 19817 ev.transform(m); 19818 return true; 19819 } 19820 19821 /** 19822 * Transforms a motion event from on-screen coordinates to view-local 19823 * coordinates. 19824 * 19825 * @param ev the on-screen motion event 19826 * @return false if the transformation could not be applied 19827 * @hide 19828 */ 19829 public boolean toLocalMotionEvent(MotionEvent ev) { 19830 final AttachInfo info = mAttachInfo; 19831 if (info == null) { 19832 return false; 19833 } 19834 19835 final Matrix m = info.mTmpMatrix; 19836 m.set(Matrix.IDENTITY_MATRIX); 19837 transformMatrixToLocal(m); 19838 ev.transform(m); 19839 return true; 19840 } 19841 19842 /** 19843 * Modifies the input matrix such that it maps view-local coordinates to 19844 * on-screen coordinates. 19845 * 19846 * @param m input matrix to modify 19847 * @hide 19848 */ 19849 public void transformMatrixToGlobal(Matrix m) { 19850 final ViewParent parent = mParent; 19851 if (parent instanceof View) { 19852 final View vp = (View) parent; 19853 vp.transformMatrixToGlobal(m); 19854 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 19855 } else if (parent instanceof ViewRootImpl) { 19856 final ViewRootImpl vr = (ViewRootImpl) parent; 19857 vr.transformMatrixToGlobal(m); 19858 m.preTranslate(0, -vr.mCurScrollY); 19859 } 19860 19861 m.preTranslate(mLeft, mTop); 19862 19863 if (!hasIdentityMatrix()) { 19864 m.preConcat(getMatrix()); 19865 } 19866 } 19867 19868 /** 19869 * Modifies the input matrix such that it maps on-screen coordinates to 19870 * view-local coordinates. 19871 * 19872 * @param m input matrix to modify 19873 * @hide 19874 */ 19875 public void transformMatrixToLocal(Matrix m) { 19876 final ViewParent parent = mParent; 19877 if (parent instanceof View) { 19878 final View vp = (View) parent; 19879 vp.transformMatrixToLocal(m); 19880 m.postTranslate(vp.mScrollX, vp.mScrollY); 19881 } else if (parent instanceof ViewRootImpl) { 19882 final ViewRootImpl vr = (ViewRootImpl) parent; 19883 vr.transformMatrixToLocal(m); 19884 m.postTranslate(0, vr.mCurScrollY); 19885 } 19886 19887 m.postTranslate(-mLeft, -mTop); 19888 19889 if (!hasIdentityMatrix()) { 19890 m.postConcat(getInverseMatrix()); 19891 } 19892 } 19893 19894 /** 19895 * @hide 19896 */ 19897 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 19898 @ViewDebug.IntToString(from = 0, to = "x"), 19899 @ViewDebug.IntToString(from = 1, to = "y") 19900 }) 19901 public int[] getLocationOnScreen() { 19902 int[] location = new int[2]; 19903 getLocationOnScreen(location); 19904 return location; 19905 } 19906 19907 /** 19908 * <p>Computes the coordinates of this view on the screen. The argument 19909 * must be an array of two integers. After the method returns, the array 19910 * contains the x and y location in that order.</p> 19911 * 19912 * @param outLocation an array of two integers in which to hold the coordinates 19913 */ 19914 public void getLocationOnScreen(@Size(2) int[] outLocation) { 19915 getLocationInWindow(outLocation); 19916 19917 final AttachInfo info = mAttachInfo; 19918 if (info != null) { 19919 outLocation[0] += info.mWindowLeft; 19920 outLocation[1] += info.mWindowTop; 19921 } 19922 } 19923 19924 /** 19925 * <p>Computes the coordinates of this view in its window. The argument 19926 * must be an array of two integers. After the method returns, the array 19927 * contains the x and y location in that order.</p> 19928 * 19929 * @param outLocation an array of two integers in which to hold the coordinates 19930 */ 19931 public void getLocationInWindow(@Size(2) int[] outLocation) { 19932 if (outLocation == null || outLocation.length < 2) { 19933 throw new IllegalArgumentException("outLocation must be an array of two integers"); 19934 } 19935 19936 outLocation[0] = 0; 19937 outLocation[1] = 0; 19938 19939 transformFromViewToWindowSpace(outLocation); 19940 } 19941 19942 /** @hide */ 19943 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 19944 if (inOutLocation == null || inOutLocation.length < 2) { 19945 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 19946 } 19947 19948 if (mAttachInfo == null) { 19949 // When the view is not attached to a window, this method does not make sense 19950 inOutLocation[0] = inOutLocation[1] = 0; 19951 return; 19952 } 19953 19954 float position[] = mAttachInfo.mTmpTransformLocation; 19955 position[0] = inOutLocation[0]; 19956 position[1] = inOutLocation[1]; 19957 19958 if (!hasIdentityMatrix()) { 19959 getMatrix().mapPoints(position); 19960 } 19961 19962 position[0] += mLeft; 19963 position[1] += mTop; 19964 19965 ViewParent viewParent = mParent; 19966 while (viewParent instanceof View) { 19967 final View view = (View) viewParent; 19968 19969 position[0] -= view.mScrollX; 19970 position[1] -= view.mScrollY; 19971 19972 if (!view.hasIdentityMatrix()) { 19973 view.getMatrix().mapPoints(position); 19974 } 19975 19976 position[0] += view.mLeft; 19977 position[1] += view.mTop; 19978 19979 viewParent = view.mParent; 19980 } 19981 19982 if (viewParent instanceof ViewRootImpl) { 19983 // *cough* 19984 final ViewRootImpl vr = (ViewRootImpl) viewParent; 19985 position[1] -= vr.mCurScrollY; 19986 } 19987 19988 inOutLocation[0] = Math.round(position[0]); 19989 inOutLocation[1] = Math.round(position[1]); 19990 } 19991 19992 /** 19993 * {@hide} 19994 * @param id the id of the view to be found 19995 * @return the view of the specified id, null if cannot be found 19996 */ 19997 protected View findViewTraversal(@IdRes int id) { 19998 if (id == mID) { 19999 return this; 20000 } 20001 return null; 20002 } 20003 20004 /** 20005 * {@hide} 20006 * @param tag the tag of the view to be found 20007 * @return the view of specified tag, null if cannot be found 20008 */ 20009 protected View findViewWithTagTraversal(Object tag) { 20010 if (tag != null && tag.equals(mTag)) { 20011 return this; 20012 } 20013 return null; 20014 } 20015 20016 /** 20017 * {@hide} 20018 * @param predicate The predicate to evaluate. 20019 * @param childToSkip If not null, ignores this child during the recursive traversal. 20020 * @return The first view that matches the predicate or null. 20021 */ 20022 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 20023 if (predicate.apply(this)) { 20024 return this; 20025 } 20026 return null; 20027 } 20028 20029 /** 20030 * Look for a child view with the given id. If this view has the given 20031 * id, return this view. 20032 * 20033 * @param id The id to search for. 20034 * @return The view that has the given id in the hierarchy or null 20035 */ 20036 @Nullable 20037 public final View findViewById(@IdRes int id) { 20038 if (id < 0) { 20039 return null; 20040 } 20041 return findViewTraversal(id); 20042 } 20043 20044 /** 20045 * Finds a view by its unuque and stable accessibility id. 20046 * 20047 * @param accessibilityId The searched accessibility id. 20048 * @return The found view. 20049 */ 20050 final View findViewByAccessibilityId(int accessibilityId) { 20051 if (accessibilityId < 0) { 20052 return null; 20053 } 20054 View view = findViewByAccessibilityIdTraversal(accessibilityId); 20055 if (view != null) { 20056 return view.includeForAccessibility() ? view : null; 20057 } 20058 return null; 20059 } 20060 20061 /** 20062 * Performs the traversal to find a view by its unuque and stable accessibility id. 20063 * 20064 * <strong>Note:</strong>This method does not stop at the root namespace 20065 * boundary since the user can touch the screen at an arbitrary location 20066 * potentially crossing the root namespace bounday which will send an 20067 * accessibility event to accessibility services and they should be able 20068 * to obtain the event source. Also accessibility ids are guaranteed to be 20069 * unique in the window. 20070 * 20071 * @param accessibilityId The accessibility id. 20072 * @return The found view. 20073 * 20074 * @hide 20075 */ 20076 public View findViewByAccessibilityIdTraversal(int accessibilityId) { 20077 if (getAccessibilityViewId() == accessibilityId) { 20078 return this; 20079 } 20080 return null; 20081 } 20082 20083 /** 20084 * Look for a child view with the given tag. If this view has the given 20085 * tag, return this view. 20086 * 20087 * @param tag The tag to search for, using "tag.equals(getTag())". 20088 * @return The View that has the given tag in the hierarchy or null 20089 */ 20090 public final View findViewWithTag(Object tag) { 20091 if (tag == null) { 20092 return null; 20093 } 20094 return findViewWithTagTraversal(tag); 20095 } 20096 20097 /** 20098 * {@hide} 20099 * Look for a child view that matches the specified predicate. 20100 * If this view matches the predicate, return this view. 20101 * 20102 * @param predicate The predicate to evaluate. 20103 * @return The first view that matches the predicate or null. 20104 */ 20105 public final View findViewByPredicate(Predicate<View> predicate) { 20106 return findViewByPredicateTraversal(predicate, null); 20107 } 20108 20109 /** 20110 * {@hide} 20111 * Look for a child view that matches the specified predicate, 20112 * starting with the specified view and its descendents and then 20113 * recusively searching the ancestors and siblings of that view 20114 * until this view is reached. 20115 * 20116 * This method is useful in cases where the predicate does not match 20117 * a single unique view (perhaps multiple views use the same id) 20118 * and we are trying to find the view that is "closest" in scope to the 20119 * starting view. 20120 * 20121 * @param start The view to start from. 20122 * @param predicate The predicate to evaluate. 20123 * @return The first view that matches the predicate or null. 20124 */ 20125 public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) { 20126 View childToSkip = null; 20127 for (;;) { 20128 View view = start.findViewByPredicateTraversal(predicate, childToSkip); 20129 if (view != null || start == this) { 20130 return view; 20131 } 20132 20133 ViewParent parent = start.getParent(); 20134 if (parent == null || !(parent instanceof View)) { 20135 return null; 20136 } 20137 20138 childToSkip = start; 20139 start = (View) parent; 20140 } 20141 } 20142 20143 /** 20144 * Sets the identifier for this view. The identifier does not have to be 20145 * unique in this view's hierarchy. The identifier should be a positive 20146 * number. 20147 * 20148 * @see #NO_ID 20149 * @see #getId() 20150 * @see #findViewById(int) 20151 * 20152 * @param id a number used to identify the view 20153 * 20154 * @attr ref android.R.styleable#View_id 20155 */ 20156 public void setId(@IdRes int id) { 20157 mID = id; 20158 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 20159 mID = generateViewId(); 20160 } 20161 } 20162 20163 /** 20164 * {@hide} 20165 * 20166 * @param isRoot true if the view belongs to the root namespace, false 20167 * otherwise 20168 */ 20169 public void setIsRootNamespace(boolean isRoot) { 20170 if (isRoot) { 20171 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 20172 } else { 20173 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 20174 } 20175 } 20176 20177 /** 20178 * {@hide} 20179 * 20180 * @return true if the view belongs to the root namespace, false otherwise 20181 */ 20182 public boolean isRootNamespace() { 20183 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 20184 } 20185 20186 /** 20187 * Returns this view's identifier. 20188 * 20189 * @return a positive integer used to identify the view or {@link #NO_ID} 20190 * if the view has no ID 20191 * 20192 * @see #setId(int) 20193 * @see #findViewById(int) 20194 * @attr ref android.R.styleable#View_id 20195 */ 20196 @IdRes 20197 @ViewDebug.CapturedViewProperty 20198 public int getId() { 20199 return mID; 20200 } 20201 20202 /** 20203 * Returns this view's tag. 20204 * 20205 * @return the Object stored in this view as a tag, or {@code null} if not 20206 * set 20207 * 20208 * @see #setTag(Object) 20209 * @see #getTag(int) 20210 */ 20211 @ViewDebug.ExportedProperty 20212 public Object getTag() { 20213 return mTag; 20214 } 20215 20216 /** 20217 * Sets the tag associated with this view. A tag can be used to mark 20218 * a view in its hierarchy and does not have to be unique within the 20219 * hierarchy. Tags can also be used to store data within a view without 20220 * resorting to another data structure. 20221 * 20222 * @param tag an Object to tag the view with 20223 * 20224 * @see #getTag() 20225 * @see #setTag(int, Object) 20226 */ 20227 public void setTag(final Object tag) { 20228 mTag = tag; 20229 } 20230 20231 /** 20232 * Returns the tag associated with this view and the specified key. 20233 * 20234 * @param key The key identifying the tag 20235 * 20236 * @return the Object stored in this view as a tag, or {@code null} if not 20237 * set 20238 * 20239 * @see #setTag(int, Object) 20240 * @see #getTag() 20241 */ 20242 public Object getTag(int key) { 20243 if (mKeyedTags != null) return mKeyedTags.get(key); 20244 return null; 20245 } 20246 20247 /** 20248 * Sets a tag associated with this view and a key. A tag can be used 20249 * to mark a view in its hierarchy and does not have to be unique within 20250 * the hierarchy. Tags can also be used to store data within a view 20251 * without resorting to another data structure. 20252 * 20253 * The specified key should be an id declared in the resources of the 20254 * application to ensure it is unique (see the <a 20255 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 20256 * Keys identified as belonging to 20257 * the Android framework or not associated with any package will cause 20258 * an {@link IllegalArgumentException} to be thrown. 20259 * 20260 * @param key The key identifying the tag 20261 * @param tag An Object to tag the view with 20262 * 20263 * @throws IllegalArgumentException If they specified key is not valid 20264 * 20265 * @see #setTag(Object) 20266 * @see #getTag(int) 20267 */ 20268 public void setTag(int key, final Object tag) { 20269 // If the package id is 0x00 or 0x01, it's either an undefined package 20270 // or a framework id 20271 if ((key >>> 24) < 2) { 20272 throw new IllegalArgumentException("The key must be an application-specific " 20273 + "resource id."); 20274 } 20275 20276 setKeyedTag(key, tag); 20277 } 20278 20279 /** 20280 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 20281 * framework id. 20282 * 20283 * @hide 20284 */ 20285 public void setTagInternal(int key, Object tag) { 20286 if ((key >>> 24) != 0x1) { 20287 throw new IllegalArgumentException("The key must be a framework-specific " 20288 + "resource id."); 20289 } 20290 20291 setKeyedTag(key, tag); 20292 } 20293 20294 private void setKeyedTag(int key, Object tag) { 20295 if (mKeyedTags == null) { 20296 mKeyedTags = new SparseArray<Object>(2); 20297 } 20298 20299 mKeyedTags.put(key, tag); 20300 } 20301 20302 /** 20303 * Prints information about this view in the log output, with the tag 20304 * {@link #VIEW_LOG_TAG}. 20305 * 20306 * @hide 20307 */ 20308 public void debug() { 20309 debug(0); 20310 } 20311 20312 /** 20313 * Prints information about this view in the log output, with the tag 20314 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 20315 * indentation defined by the <code>depth</code>. 20316 * 20317 * @param depth the indentation level 20318 * 20319 * @hide 20320 */ 20321 protected void debug(int depth) { 20322 String output = debugIndent(depth - 1); 20323 20324 output += "+ " + this; 20325 int id = getId(); 20326 if (id != -1) { 20327 output += " (id=" + id + ")"; 20328 } 20329 Object tag = getTag(); 20330 if (tag != null) { 20331 output += " (tag=" + tag + ")"; 20332 } 20333 Log.d(VIEW_LOG_TAG, output); 20334 20335 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 20336 output = debugIndent(depth) + " FOCUSED"; 20337 Log.d(VIEW_LOG_TAG, output); 20338 } 20339 20340 output = debugIndent(depth); 20341 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 20342 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 20343 + "} "; 20344 Log.d(VIEW_LOG_TAG, output); 20345 20346 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 20347 || mPaddingBottom != 0) { 20348 output = debugIndent(depth); 20349 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 20350 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 20351 Log.d(VIEW_LOG_TAG, output); 20352 } 20353 20354 output = debugIndent(depth); 20355 output += "mMeasureWidth=" + mMeasuredWidth + 20356 " mMeasureHeight=" + mMeasuredHeight; 20357 Log.d(VIEW_LOG_TAG, output); 20358 20359 output = debugIndent(depth); 20360 if (mLayoutParams == null) { 20361 output += "BAD! no layout params"; 20362 } else { 20363 output = mLayoutParams.debug(output); 20364 } 20365 Log.d(VIEW_LOG_TAG, output); 20366 20367 output = debugIndent(depth); 20368 output += "flags={"; 20369 output += View.printFlags(mViewFlags); 20370 output += "}"; 20371 Log.d(VIEW_LOG_TAG, output); 20372 20373 output = debugIndent(depth); 20374 output += "privateFlags={"; 20375 output += View.printPrivateFlags(mPrivateFlags); 20376 output += "}"; 20377 Log.d(VIEW_LOG_TAG, output); 20378 } 20379 20380 /** 20381 * Creates a string of whitespaces used for indentation. 20382 * 20383 * @param depth the indentation level 20384 * @return a String containing (depth * 2 + 3) * 2 white spaces 20385 * 20386 * @hide 20387 */ 20388 protected static String debugIndent(int depth) { 20389 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 20390 for (int i = 0; i < (depth * 2) + 3; i++) { 20391 spaces.append(' ').append(' '); 20392 } 20393 return spaces.toString(); 20394 } 20395 20396 /** 20397 * <p>Return the offset of the widget's text baseline from the widget's top 20398 * boundary. If this widget does not support baseline alignment, this 20399 * method returns -1. </p> 20400 * 20401 * @return the offset of the baseline within the widget's bounds or -1 20402 * if baseline alignment is not supported 20403 */ 20404 @ViewDebug.ExportedProperty(category = "layout") 20405 public int getBaseline() { 20406 return -1; 20407 } 20408 20409 /** 20410 * Returns whether the view hierarchy is currently undergoing a layout pass. This 20411 * information is useful to avoid situations such as calling {@link #requestLayout()} during 20412 * a layout pass. 20413 * 20414 * @return whether the view hierarchy is currently undergoing a layout pass 20415 */ 20416 public boolean isInLayout() { 20417 ViewRootImpl viewRoot = getViewRootImpl(); 20418 return (viewRoot != null && viewRoot.isInLayout()); 20419 } 20420 20421 /** 20422 * Call this when something has changed which has invalidated the 20423 * layout of this view. This will schedule a layout pass of the view 20424 * tree. This should not be called while the view hierarchy is currently in a layout 20425 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 20426 * end of the current layout pass (and then layout will run again) or after the current 20427 * frame is drawn and the next layout occurs. 20428 * 20429 * <p>Subclasses which override this method should call the superclass method to 20430 * handle possible request-during-layout errors correctly.</p> 20431 */ 20432 @CallSuper 20433 public void requestLayout() { 20434 if (mMeasureCache != null) mMeasureCache.clear(); 20435 20436 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 20437 // Only trigger request-during-layout logic if this is the view requesting it, 20438 // not the views in its parent hierarchy 20439 ViewRootImpl viewRoot = getViewRootImpl(); 20440 if (viewRoot != null && viewRoot.isInLayout()) { 20441 if (!viewRoot.requestLayoutDuringLayout(this)) { 20442 return; 20443 } 20444 } 20445 mAttachInfo.mViewRequestingLayout = this; 20446 } 20447 20448 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20449 mPrivateFlags |= PFLAG_INVALIDATED; 20450 20451 if (mParent != null && !mParent.isLayoutRequested()) { 20452 mParent.requestLayout(); 20453 } 20454 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 20455 mAttachInfo.mViewRequestingLayout = null; 20456 } 20457 } 20458 20459 /** 20460 * Forces this view to be laid out during the next layout pass. 20461 * This method does not call requestLayout() or forceLayout() 20462 * on the parent. 20463 */ 20464 public void forceLayout() { 20465 if (mMeasureCache != null) mMeasureCache.clear(); 20466 20467 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20468 mPrivateFlags |= PFLAG_INVALIDATED; 20469 } 20470 20471 /** 20472 * <p> 20473 * This is called to find out how big a view should be. The parent 20474 * supplies constraint information in the width and height parameters. 20475 * </p> 20476 * 20477 * <p> 20478 * The actual measurement work of a view is performed in 20479 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 20480 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 20481 * </p> 20482 * 20483 * 20484 * @param widthMeasureSpec Horizontal space requirements as imposed by the 20485 * parent 20486 * @param heightMeasureSpec Vertical space requirements as imposed by the 20487 * parent 20488 * 20489 * @see #onMeasure(int, int) 20490 */ 20491 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 20492 boolean optical = isLayoutModeOptical(this); 20493 if (optical != isLayoutModeOptical(mParent)) { 20494 Insets insets = getOpticalInsets(); 20495 int oWidth = insets.left + insets.right; 20496 int oHeight = insets.top + insets.bottom; 20497 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 20498 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 20499 } 20500 20501 // Suppress sign extension for the low bytes 20502 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 20503 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 20504 20505 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 20506 20507 // Optimize layout by avoiding an extra EXACTLY pass when the view is 20508 // already measured as the correct size. In API 23 and below, this 20509 // extra pass is required to make LinearLayout re-distribute weight. 20510 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 20511 || heightMeasureSpec != mOldHeightMeasureSpec; 20512 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 20513 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 20514 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 20515 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 20516 final boolean needsLayout = specChanged 20517 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 20518 20519 if (forceLayout || needsLayout) { 20520 // first clears the measured dimension flag 20521 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 20522 20523 resolveRtlPropertiesIfNeeded(); 20524 20525 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 20526 if (cacheIndex < 0 || sIgnoreMeasureCache) { 20527 // measure ourselves, this should set the measured dimension flag back 20528 onMeasure(widthMeasureSpec, heightMeasureSpec); 20529 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20530 } else { 20531 long value = mMeasureCache.valueAt(cacheIndex); 20532 // Casting a long to int drops the high 32 bits, no mask needed 20533 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 20534 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20535 } 20536 20537 // flag not set, setMeasuredDimension() was not invoked, we raise 20538 // an exception to warn the developer 20539 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 20540 throw new IllegalStateException("View with id " + getId() + ": " 20541 + getClass().getName() + "#onMeasure() did not set the" 20542 + " measured dimension by calling" 20543 + " setMeasuredDimension()"); 20544 } 20545 20546 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 20547 } 20548 20549 mOldWidthMeasureSpec = widthMeasureSpec; 20550 mOldHeightMeasureSpec = heightMeasureSpec; 20551 20552 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 20553 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 20554 } 20555 20556 /** 20557 * <p> 20558 * Measure the view and its content to determine the measured width and the 20559 * measured height. This method is invoked by {@link #measure(int, int)} and 20560 * should be overridden by subclasses to provide accurate and efficient 20561 * measurement of their contents. 20562 * </p> 20563 * 20564 * <p> 20565 * <strong>CONTRACT:</strong> When overriding this method, you 20566 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 20567 * measured width and height of this view. Failure to do so will trigger an 20568 * <code>IllegalStateException</code>, thrown by 20569 * {@link #measure(int, int)}. Calling the superclass' 20570 * {@link #onMeasure(int, int)} is a valid use. 20571 * </p> 20572 * 20573 * <p> 20574 * The base class implementation of measure defaults to the background size, 20575 * unless a larger size is allowed by the MeasureSpec. Subclasses should 20576 * override {@link #onMeasure(int, int)} to provide better measurements of 20577 * their content. 20578 * </p> 20579 * 20580 * <p> 20581 * If this method is overridden, it is the subclass's responsibility to make 20582 * sure the measured height and width are at least the view's minimum height 20583 * and width ({@link #getSuggestedMinimumHeight()} and 20584 * {@link #getSuggestedMinimumWidth()}). 20585 * </p> 20586 * 20587 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 20588 * The requirements are encoded with 20589 * {@link android.view.View.MeasureSpec}. 20590 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 20591 * The requirements are encoded with 20592 * {@link android.view.View.MeasureSpec}. 20593 * 20594 * @see #getMeasuredWidth() 20595 * @see #getMeasuredHeight() 20596 * @see #setMeasuredDimension(int, int) 20597 * @see #getSuggestedMinimumHeight() 20598 * @see #getSuggestedMinimumWidth() 20599 * @see android.view.View.MeasureSpec#getMode(int) 20600 * @see android.view.View.MeasureSpec#getSize(int) 20601 */ 20602 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 20603 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 20604 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 20605 } 20606 20607 /** 20608 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 20609 * measured width and measured height. Failing to do so will trigger an 20610 * exception at measurement time.</p> 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 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 20620 boolean optical = isLayoutModeOptical(this); 20621 if (optical != isLayoutModeOptical(mParent)) { 20622 Insets insets = getOpticalInsets(); 20623 int opticalWidth = insets.left + insets.right; 20624 int opticalHeight = insets.top + insets.bottom; 20625 20626 measuredWidth += optical ? opticalWidth : -opticalWidth; 20627 measuredHeight += optical ? opticalHeight : -opticalHeight; 20628 } 20629 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 20630 } 20631 20632 /** 20633 * Sets the measured dimension without extra processing for things like optical bounds. 20634 * Useful for reapplying consistent values that have already been cooked with adjustments 20635 * for optical bounds, etc. such as those from the measurement cache. 20636 * 20637 * @param measuredWidth The measured width of this view. May be a complex 20638 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20639 * {@link #MEASURED_STATE_TOO_SMALL}. 20640 * @param measuredHeight The measured height of this view. May be a complex 20641 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20642 * {@link #MEASURED_STATE_TOO_SMALL}. 20643 */ 20644 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 20645 mMeasuredWidth = measuredWidth; 20646 mMeasuredHeight = measuredHeight; 20647 20648 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 20649 } 20650 20651 /** 20652 * Merge two states as returned by {@link #getMeasuredState()}. 20653 * @param curState The current state as returned from a view or the result 20654 * of combining multiple views. 20655 * @param newState The new view state to combine. 20656 * @return Returns a new integer reflecting the combination of the two 20657 * states. 20658 */ 20659 public static int combineMeasuredStates(int curState, int newState) { 20660 return curState | newState; 20661 } 20662 20663 /** 20664 * Version of {@link #resolveSizeAndState(int, int, int)} 20665 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 20666 */ 20667 public static int resolveSize(int size, int measureSpec) { 20668 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 20669 } 20670 20671 /** 20672 * Utility to reconcile a desired size and state, with constraints imposed 20673 * by a MeasureSpec. Will take the desired size, unless a different size 20674 * is imposed by the constraints. The returned value is a compound integer, 20675 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 20676 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 20677 * resulting size is smaller than the size the view wants to be. 20678 * 20679 * @param size How big the view wants to be. 20680 * @param measureSpec Constraints imposed by the parent. 20681 * @param childMeasuredState Size information bit mask for the view's 20682 * children. 20683 * @return Size information bit mask as defined by 20684 * {@link #MEASURED_SIZE_MASK} and 20685 * {@link #MEASURED_STATE_TOO_SMALL}. 20686 */ 20687 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 20688 final int specMode = MeasureSpec.getMode(measureSpec); 20689 final int specSize = MeasureSpec.getSize(measureSpec); 20690 final int result; 20691 switch (specMode) { 20692 case MeasureSpec.AT_MOST: 20693 if (specSize < size) { 20694 result = specSize | MEASURED_STATE_TOO_SMALL; 20695 } else { 20696 result = size; 20697 } 20698 break; 20699 case MeasureSpec.EXACTLY: 20700 result = specSize; 20701 break; 20702 case MeasureSpec.UNSPECIFIED: 20703 default: 20704 result = size; 20705 } 20706 return result | (childMeasuredState & MEASURED_STATE_MASK); 20707 } 20708 20709 /** 20710 * Utility to return a default size. Uses the supplied size if the 20711 * MeasureSpec imposed no constraints. Will get larger if allowed 20712 * by the MeasureSpec. 20713 * 20714 * @param size Default size for this view 20715 * @param measureSpec Constraints imposed by the parent 20716 * @return The size this view should be. 20717 */ 20718 public static int getDefaultSize(int size, int measureSpec) { 20719 int result = size; 20720 int specMode = MeasureSpec.getMode(measureSpec); 20721 int specSize = MeasureSpec.getSize(measureSpec); 20722 20723 switch (specMode) { 20724 case MeasureSpec.UNSPECIFIED: 20725 result = size; 20726 break; 20727 case MeasureSpec.AT_MOST: 20728 case MeasureSpec.EXACTLY: 20729 result = specSize; 20730 break; 20731 } 20732 return result; 20733 } 20734 20735 /** 20736 * Returns the suggested minimum height that the view should use. This 20737 * returns the maximum of the view's minimum height 20738 * and the background's minimum height 20739 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 20740 * <p> 20741 * When being used in {@link #onMeasure(int, int)}, the caller should still 20742 * ensure the returned height is within the requirements of the parent. 20743 * 20744 * @return The suggested minimum height of the view. 20745 */ 20746 protected int getSuggestedMinimumHeight() { 20747 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 20748 20749 } 20750 20751 /** 20752 * Returns the suggested minimum width that the view should use. This 20753 * returns the maximum of the view's minimum width 20754 * and the background's minimum width 20755 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 20756 * <p> 20757 * When being used in {@link #onMeasure(int, int)}, the caller should still 20758 * ensure the returned width is within the requirements of the parent. 20759 * 20760 * @return The suggested minimum width of the view. 20761 */ 20762 protected int getSuggestedMinimumWidth() { 20763 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 20764 } 20765 20766 /** 20767 * Returns the minimum height of the view. 20768 * 20769 * @return the minimum height the view will try to be, in pixels 20770 * 20771 * @see #setMinimumHeight(int) 20772 * 20773 * @attr ref android.R.styleable#View_minHeight 20774 */ 20775 public int getMinimumHeight() { 20776 return mMinHeight; 20777 } 20778 20779 /** 20780 * Sets the minimum height of the view. It is not guaranteed the view will 20781 * be able to achieve this minimum height (for example, if its parent layout 20782 * constrains it with less available height). 20783 * 20784 * @param minHeight The minimum height the view will try to be, in pixels 20785 * 20786 * @see #getMinimumHeight() 20787 * 20788 * @attr ref android.R.styleable#View_minHeight 20789 */ 20790 @RemotableViewMethod 20791 public void setMinimumHeight(int minHeight) { 20792 mMinHeight = minHeight; 20793 requestLayout(); 20794 } 20795 20796 /** 20797 * Returns the minimum width of the view. 20798 * 20799 * @return the minimum width the view will try to be, in pixels 20800 * 20801 * @see #setMinimumWidth(int) 20802 * 20803 * @attr ref android.R.styleable#View_minWidth 20804 */ 20805 public int getMinimumWidth() { 20806 return mMinWidth; 20807 } 20808 20809 /** 20810 * Sets the minimum width of the view. It is not guaranteed the view will 20811 * be able to achieve this minimum width (for example, if its parent layout 20812 * constrains it with less available width). 20813 * 20814 * @param minWidth The minimum width the view will try to be, in pixels 20815 * 20816 * @see #getMinimumWidth() 20817 * 20818 * @attr ref android.R.styleable#View_minWidth 20819 */ 20820 public void setMinimumWidth(int minWidth) { 20821 mMinWidth = minWidth; 20822 requestLayout(); 20823 20824 } 20825 20826 /** 20827 * Get the animation currently associated with this view. 20828 * 20829 * @return The animation that is currently playing or 20830 * scheduled to play for this view. 20831 */ 20832 public Animation getAnimation() { 20833 return mCurrentAnimation; 20834 } 20835 20836 /** 20837 * Start the specified animation now. 20838 * 20839 * @param animation the animation to start now 20840 */ 20841 public void startAnimation(Animation animation) { 20842 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 20843 setAnimation(animation); 20844 invalidateParentCaches(); 20845 invalidate(true); 20846 } 20847 20848 /** 20849 * Cancels any animations for this view. 20850 */ 20851 public void clearAnimation() { 20852 if (mCurrentAnimation != null) { 20853 mCurrentAnimation.detach(); 20854 } 20855 mCurrentAnimation = null; 20856 invalidateParentIfNeeded(); 20857 } 20858 20859 /** 20860 * Sets the next animation to play for this view. 20861 * If you want the animation to play immediately, use 20862 * {@link #startAnimation(android.view.animation.Animation)} instead. 20863 * This method provides allows fine-grained 20864 * control over the start time and invalidation, but you 20865 * must make sure that 1) the animation has a start time set, and 20866 * 2) the view's parent (which controls animations on its children) 20867 * will be invalidated when the animation is supposed to 20868 * start. 20869 * 20870 * @param animation The next animation, or null. 20871 */ 20872 public void setAnimation(Animation animation) { 20873 mCurrentAnimation = animation; 20874 20875 if (animation != null) { 20876 // If the screen is off assume the animation start time is now instead of 20877 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 20878 // would cause the animation to start when the screen turns back on 20879 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 20880 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 20881 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 20882 } 20883 animation.reset(); 20884 } 20885 } 20886 20887 /** 20888 * Invoked by a parent ViewGroup to notify the start of the animation 20889 * currently associated with this view. If you override this method, 20890 * always call super.onAnimationStart(); 20891 * 20892 * @see #setAnimation(android.view.animation.Animation) 20893 * @see #getAnimation() 20894 */ 20895 @CallSuper 20896 protected void onAnimationStart() { 20897 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 20898 } 20899 20900 /** 20901 * Invoked by a parent ViewGroup to notify the end of the animation 20902 * currently associated with this view. If you override this method, 20903 * always call super.onAnimationEnd(); 20904 * 20905 * @see #setAnimation(android.view.animation.Animation) 20906 * @see #getAnimation() 20907 */ 20908 @CallSuper 20909 protected void onAnimationEnd() { 20910 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 20911 } 20912 20913 /** 20914 * Invoked if there is a Transform that involves alpha. Subclass that can 20915 * draw themselves with the specified alpha should return true, and then 20916 * respect that alpha when their onDraw() is called. If this returns false 20917 * then the view may be redirected to draw into an offscreen buffer to 20918 * fulfill the request, which will look fine, but may be slower than if the 20919 * subclass handles it internally. The default implementation returns false. 20920 * 20921 * @param alpha The alpha (0..255) to apply to the view's drawing 20922 * @return true if the view can draw with the specified alpha. 20923 */ 20924 protected boolean onSetAlpha(int alpha) { 20925 return false; 20926 } 20927 20928 /** 20929 * This is used by the RootView to perform an optimization when 20930 * the view hierarchy contains one or several SurfaceView. 20931 * SurfaceView is always considered transparent, but its children are not, 20932 * therefore all View objects remove themselves from the global transparent 20933 * region (passed as a parameter to this function). 20934 * 20935 * @param region The transparent region for this ViewAncestor (window). 20936 * 20937 * @return Returns true if the effective visibility of the view at this 20938 * point is opaque, regardless of the transparent region; returns false 20939 * if it is possible for underlying windows to be seen behind the view. 20940 * 20941 * {@hide} 20942 */ 20943 public boolean gatherTransparentRegion(Region region) { 20944 final AttachInfo attachInfo = mAttachInfo; 20945 if (region != null && attachInfo != null) { 20946 final int pflags = mPrivateFlags; 20947 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 20948 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 20949 // remove it from the transparent region. 20950 final int[] location = attachInfo.mTransparentLocation; 20951 getLocationInWindow(location); 20952 // When a view has Z value, then it will be better to leave some area below the view 20953 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 20954 // the bottom part needs more offset than the left, top and right parts due to the 20955 // spot light effects. 20956 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 20957 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 20958 location[0] + mRight - mLeft + shadowOffset, 20959 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 20960 } else { 20961 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 20962 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 20963 // the background drawable's non-transparent parts from this transparent region. 20964 applyDrawableToTransparentRegion(mBackground, region); 20965 } 20966 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20967 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 20968 // Similarly, we remove the foreground drawable's non-transparent parts. 20969 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 20970 } 20971 } 20972 } 20973 return true; 20974 } 20975 20976 /** 20977 * Play a sound effect for this view. 20978 * 20979 * <p>The framework will play sound effects for some built in actions, such as 20980 * clicking, but you may wish to play these effects in your widget, 20981 * for instance, for internal navigation. 20982 * 20983 * <p>The sound effect will only be played if sound effects are enabled by the user, and 20984 * {@link #isSoundEffectsEnabled()} is true. 20985 * 20986 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 20987 */ 20988 public void playSoundEffect(int soundConstant) { 20989 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 20990 return; 20991 } 20992 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 20993 } 20994 20995 /** 20996 * BZZZTT!!1! 20997 * 20998 * <p>Provide haptic feedback to the user for this view. 20999 * 21000 * <p>The framework will provide haptic feedback for some built in actions, 21001 * such as long presses, but you may wish to provide feedback for your 21002 * own widget. 21003 * 21004 * <p>The feedback will only be performed if 21005 * {@link #isHapticFeedbackEnabled()} is true. 21006 * 21007 * @param feedbackConstant One of the constants defined in 21008 * {@link HapticFeedbackConstants} 21009 */ 21010 public boolean performHapticFeedback(int feedbackConstant) { 21011 return performHapticFeedback(feedbackConstant, 0); 21012 } 21013 21014 /** 21015 * BZZZTT!!1! 21016 * 21017 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 21018 * 21019 * @param feedbackConstant One of the constants defined in 21020 * {@link HapticFeedbackConstants} 21021 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 21022 */ 21023 public boolean performHapticFeedback(int feedbackConstant, int flags) { 21024 if (mAttachInfo == null) { 21025 return false; 21026 } 21027 //noinspection SimplifiableIfStatement 21028 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 21029 && !isHapticFeedbackEnabled()) { 21030 return false; 21031 } 21032 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 21033 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 21034 } 21035 21036 /** 21037 * Request that the visibility of the status bar or other screen/window 21038 * decorations be changed. 21039 * 21040 * <p>This method is used to put the over device UI into temporary modes 21041 * where the user's attention is focused more on the application content, 21042 * by dimming or hiding surrounding system affordances. This is typically 21043 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 21044 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 21045 * to be placed behind the action bar (and with these flags other system 21046 * affordances) so that smooth transitions between hiding and showing them 21047 * can be done. 21048 * 21049 * <p>Two representative examples of the use of system UI visibility is 21050 * implementing a content browsing application (like a magazine reader) 21051 * and a video playing application. 21052 * 21053 * <p>The first code shows a typical implementation of a View in a content 21054 * browsing application. In this implementation, the application goes 21055 * into a content-oriented mode by hiding the status bar and action bar, 21056 * and putting the navigation elements into lights out mode. The user can 21057 * then interact with content while in this mode. Such an application should 21058 * provide an easy way for the user to toggle out of the mode (such as to 21059 * check information in the status bar or access notifications). In the 21060 * implementation here, this is done simply by tapping on the content. 21061 * 21062 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 21063 * content} 21064 * 21065 * <p>This second code sample shows a typical implementation of a View 21066 * in a video playing application. In this situation, while the video is 21067 * playing the application would like to go into a complete full-screen mode, 21068 * to use as much of the display as possible for the video. When in this state 21069 * the user can not interact with the application; the system intercepts 21070 * touching on the screen to pop the UI out of full screen mode. See 21071 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 21072 * 21073 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 21074 * content} 21075 * 21076 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 21077 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 21078 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 21079 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 21080 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 21081 */ 21082 public void setSystemUiVisibility(int visibility) { 21083 if (visibility != mSystemUiVisibility) { 21084 mSystemUiVisibility = visibility; 21085 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 21086 mParent.recomputeViewAttributes(this); 21087 } 21088 } 21089 } 21090 21091 /** 21092 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 21093 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 21094 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 21095 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 21096 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 21097 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 21098 */ 21099 public int getSystemUiVisibility() { 21100 return mSystemUiVisibility; 21101 } 21102 21103 /** 21104 * Returns the current system UI visibility that is currently set for 21105 * the entire window. This is the combination of the 21106 * {@link #setSystemUiVisibility(int)} values supplied by all of the 21107 * views in the window. 21108 */ 21109 public int getWindowSystemUiVisibility() { 21110 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 21111 } 21112 21113 /** 21114 * Override to find out when the window's requested system UI visibility 21115 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 21116 * This is different from the callbacks received through 21117 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 21118 * in that this is only telling you about the local request of the window, 21119 * not the actual values applied by the system. 21120 */ 21121 public void onWindowSystemUiVisibilityChanged(int visible) { 21122 } 21123 21124 /** 21125 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 21126 * the view hierarchy. 21127 */ 21128 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 21129 onWindowSystemUiVisibilityChanged(visible); 21130 } 21131 21132 /** 21133 * Set a listener to receive callbacks when the visibility of the system bar changes. 21134 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 21135 */ 21136 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 21137 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 21138 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 21139 mParent.recomputeViewAttributes(this); 21140 } 21141 } 21142 21143 /** 21144 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 21145 * the view hierarchy. 21146 */ 21147 public void dispatchSystemUiVisibilityChanged(int visibility) { 21148 ListenerInfo li = mListenerInfo; 21149 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 21150 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 21151 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 21152 } 21153 } 21154 21155 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 21156 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 21157 if (val != mSystemUiVisibility) { 21158 setSystemUiVisibility(val); 21159 return true; 21160 } 21161 return false; 21162 } 21163 21164 /** @hide */ 21165 public void setDisabledSystemUiVisibility(int flags) { 21166 if (mAttachInfo != null) { 21167 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 21168 mAttachInfo.mDisabledSystemUiVisibility = flags; 21169 if (mParent != null) { 21170 mParent.recomputeViewAttributes(this); 21171 } 21172 } 21173 } 21174 } 21175 21176 /** 21177 * Creates an image that the system displays during the drag and drop 21178 * operation. This is called a "drag shadow". The default implementation 21179 * for a DragShadowBuilder based on a View returns an image that has exactly the same 21180 * appearance as the given View. The default also positions the center of the drag shadow 21181 * directly under the touch point. If no View is provided (the constructor with no parameters 21182 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 21183 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 21184 * default is an invisible drag shadow. 21185 * <p> 21186 * You are not required to use the View you provide to the constructor as the basis of the 21187 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 21188 * anything you want as the drag shadow. 21189 * </p> 21190 * <p> 21191 * You pass a DragShadowBuilder object to the system when you start the drag. The system 21192 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 21193 * size and position of the drag shadow. It uses this data to construct a 21194 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 21195 * so that your application can draw the shadow image in the Canvas. 21196 * </p> 21197 * 21198 * <div class="special reference"> 21199 * <h3>Developer Guides</h3> 21200 * <p>For a guide to implementing drag and drop features, read the 21201 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 21202 * </div> 21203 */ 21204 public static class DragShadowBuilder { 21205 private final WeakReference<View> mView; 21206 21207 /** 21208 * Constructs a shadow image builder based on a View. By default, the resulting drag 21209 * shadow will have the same appearance and dimensions as the View, with the touch point 21210 * over the center of the View. 21211 * @param view A View. Any View in scope can be used. 21212 */ 21213 public DragShadowBuilder(View view) { 21214 mView = new WeakReference<View>(view); 21215 } 21216 21217 /** 21218 * Construct a shadow builder object with no associated View. This 21219 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 21220 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 21221 * to supply the drag shadow's dimensions and appearance without 21222 * reference to any View object. If they are not overridden, then the result is an 21223 * invisible drag shadow. 21224 */ 21225 public DragShadowBuilder() { 21226 mView = new WeakReference<View>(null); 21227 } 21228 21229 /** 21230 * Returns the View object that had been passed to the 21231 * {@link #View.DragShadowBuilder(View)} 21232 * constructor. If that View parameter was {@code null} or if the 21233 * {@link #View.DragShadowBuilder()} 21234 * constructor was used to instantiate the builder object, this method will return 21235 * null. 21236 * 21237 * @return The View object associate with this builder object. 21238 */ 21239 @SuppressWarnings({"JavadocReference"}) 21240 final public View getView() { 21241 return mView.get(); 21242 } 21243 21244 /** 21245 * Provides the metrics for the shadow image. These include the dimensions of 21246 * the shadow image, and the point within that shadow that should 21247 * be centered under the touch location while dragging. 21248 * <p> 21249 * The default implementation sets the dimensions of the shadow to be the 21250 * same as the dimensions of the View itself and centers the shadow under 21251 * the touch point. 21252 * </p> 21253 * 21254 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 21255 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 21256 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 21257 * image. 21258 * 21259 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 21260 * shadow image that should be underneath the touch point during the drag and drop 21261 * operation. Your application must set {@link android.graphics.Point#x} to the 21262 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 21263 */ 21264 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 21265 final View view = mView.get(); 21266 if (view != null) { 21267 outShadowSize.set(view.getWidth(), view.getHeight()); 21268 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 21269 } else { 21270 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 21271 } 21272 } 21273 21274 /** 21275 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 21276 * based on the dimensions it received from the 21277 * {@link #onProvideShadowMetrics(Point, Point)} callback. 21278 * 21279 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 21280 */ 21281 public void onDrawShadow(Canvas canvas) { 21282 final View view = mView.get(); 21283 if (view != null) { 21284 view.draw(canvas); 21285 } else { 21286 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 21287 } 21288 } 21289 } 21290 21291 /** 21292 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 21293 * startDragAndDrop()} for newer platform versions. 21294 */ 21295 @Deprecated 21296 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 21297 Object myLocalState, int flags) { 21298 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 21299 } 21300 21301 /** 21302 * Starts a drag and drop operation. When your application calls this method, it passes a 21303 * {@link android.view.View.DragShadowBuilder} object to the system. The 21304 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 21305 * to get metrics for the drag shadow, and then calls the object's 21306 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 21307 * <p> 21308 * Once the system has the drag shadow, it begins the drag and drop operation by sending 21309 * drag events to all the View objects in your application that are currently visible. It does 21310 * this either by calling the View object's drag listener (an implementation of 21311 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 21312 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 21313 * Both are passed a {@link android.view.DragEvent} object that has a 21314 * {@link android.view.DragEvent#getAction()} value of 21315 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 21316 * </p> 21317 * <p> 21318 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 21319 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 21320 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 21321 * to the View the user selected for dragging. 21322 * </p> 21323 * @param data A {@link android.content.ClipData} object pointing to the data to be 21324 * transferred by the drag and drop operation. 21325 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21326 * drag shadow. 21327 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 21328 * drop operation. When dispatching drag events to views in the same activity this object 21329 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 21330 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 21331 * will return null). 21332 * <p> 21333 * myLocalState is a lightweight mechanism for the sending information from the dragged View 21334 * to the target Views. For example, it can contain flags that differentiate between a 21335 * a copy operation and a move operation. 21336 * </p> 21337 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 21338 * flags, or any combination of the following: 21339 * <ul> 21340 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 21341 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 21342 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 21343 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 21344 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 21345 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 21346 * </ul> 21347 * @return {@code true} if the method completes successfully, or 21348 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 21349 * do a drag, and so no drag operation is in progress. 21350 */ 21351 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 21352 Object myLocalState, int flags) { 21353 if (ViewDebug.DEBUG_DRAG) { 21354 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 21355 } 21356 if (mAttachInfo == null) { 21357 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 21358 return false; 21359 } 21360 21361 if (data != null) { 21362 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 21363 } 21364 21365 boolean okay = false; 21366 21367 Point shadowSize = new Point(); 21368 Point shadowTouchPoint = new Point(); 21369 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 21370 21371 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 21372 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 21373 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 21374 } 21375 21376 if (ViewDebug.DEBUG_DRAG) { 21377 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 21378 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 21379 } 21380 if (mAttachInfo.mDragSurface != null) { 21381 mAttachInfo.mDragSurface.release(); 21382 } 21383 mAttachInfo.mDragSurface = new Surface(); 21384 try { 21385 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 21386 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 21387 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 21388 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 21389 if (mAttachInfo.mDragToken != null) { 21390 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21391 try { 21392 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21393 shadowBuilder.onDrawShadow(canvas); 21394 } finally { 21395 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21396 } 21397 21398 final ViewRootImpl root = getViewRootImpl(); 21399 21400 // Cache the local state object for delivery with DragEvents 21401 root.setLocalDragState(myLocalState); 21402 21403 // repurpose 'shadowSize' for the last touch point 21404 root.getLastTouchPoint(shadowSize); 21405 21406 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 21407 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 21408 shadowTouchPoint.x, shadowTouchPoint.y, data); 21409 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 21410 } 21411 } catch (Exception e) { 21412 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 21413 mAttachInfo.mDragSurface.destroy(); 21414 mAttachInfo.mDragSurface = null; 21415 } 21416 21417 return okay; 21418 } 21419 21420 /** 21421 * Cancels an ongoing drag and drop operation. 21422 * <p> 21423 * A {@link android.view.DragEvent} object with 21424 * {@link android.view.DragEvent#getAction()} value of 21425 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 21426 * {@link android.view.DragEvent#getResult()} value of {@code false} 21427 * will be sent to every 21428 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 21429 * even if they are not currently visible. 21430 * </p> 21431 * <p> 21432 * This method can be called on any View in the same window as the View on which 21433 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 21434 * was called. 21435 * </p> 21436 */ 21437 public final void cancelDragAndDrop() { 21438 if (ViewDebug.DEBUG_DRAG) { 21439 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 21440 } 21441 if (mAttachInfo == null) { 21442 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 21443 return; 21444 } 21445 if (mAttachInfo.mDragToken != null) { 21446 try { 21447 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 21448 } catch (Exception e) { 21449 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 21450 } 21451 mAttachInfo.mDragToken = null; 21452 } else { 21453 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 21454 } 21455 } 21456 21457 /** 21458 * Updates the drag shadow for the ongoing drag and drop operation. 21459 * 21460 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21461 * new drag shadow. 21462 */ 21463 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 21464 if (ViewDebug.DEBUG_DRAG) { 21465 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 21466 } 21467 if (mAttachInfo == null) { 21468 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 21469 return; 21470 } 21471 if (mAttachInfo.mDragToken != null) { 21472 try { 21473 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21474 try { 21475 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21476 shadowBuilder.onDrawShadow(canvas); 21477 } finally { 21478 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21479 } 21480 } catch (Exception e) { 21481 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 21482 } 21483 } else { 21484 Log.e(VIEW_LOG_TAG, "No active drag"); 21485 } 21486 } 21487 21488 /** 21489 * Starts a move from {startX, startY}, the amount of the movement will be the offset 21490 * between {startX, startY} and the new cursor positon. 21491 * @param startX horizontal coordinate where the move started. 21492 * @param startY vertical coordinate where the move started. 21493 * @return whether moving was started successfully. 21494 * @hide 21495 */ 21496 public final boolean startMovingTask(float startX, float startY) { 21497 if (ViewDebug.DEBUG_POSITIONING) { 21498 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 21499 } 21500 try { 21501 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 21502 } catch (RemoteException e) { 21503 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 21504 } 21505 return false; 21506 } 21507 21508 /** 21509 * Handles drag events sent by the system following a call to 21510 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 21511 * startDragAndDrop()}. 21512 *<p> 21513 * When the system calls this method, it passes a 21514 * {@link android.view.DragEvent} object. A call to 21515 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 21516 * in DragEvent. The method uses these to determine what is happening in the drag and drop 21517 * operation. 21518 * @param event The {@link android.view.DragEvent} sent by the system. 21519 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 21520 * in DragEvent, indicating the type of drag event represented by this object. 21521 * @return {@code true} if the method was successful, otherwise {@code false}. 21522 * <p> 21523 * The method should return {@code true} in response to an action type of 21524 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 21525 * operation. 21526 * </p> 21527 * <p> 21528 * The method should also return {@code true} in response to an action type of 21529 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 21530 * {@code false} if it didn't. 21531 * </p> 21532 * <p> 21533 * For all other events, the return value is ignored. 21534 * </p> 21535 */ 21536 public boolean onDragEvent(DragEvent event) { 21537 return false; 21538 } 21539 21540 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 21541 boolean dispatchDragEnterExitInPreN(DragEvent event) { 21542 return callDragEventHandler(event); 21543 } 21544 21545 /** 21546 * Detects if this View is enabled and has a drag event listener. 21547 * If both are true, then it calls the drag event listener with the 21548 * {@link android.view.DragEvent} it received. If the drag event listener returns 21549 * {@code true}, then dispatchDragEvent() returns {@code true}. 21550 * <p> 21551 * For all other cases, the method calls the 21552 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 21553 * method and returns its result. 21554 * </p> 21555 * <p> 21556 * This ensures that a drag event is always consumed, even if the View does not have a drag 21557 * event listener. However, if the View has a listener and the listener returns true, then 21558 * onDragEvent() is not called. 21559 * </p> 21560 */ 21561 public boolean dispatchDragEvent(DragEvent event) { 21562 event.mEventHandlerWasCalled = true; 21563 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 21564 event.mAction == DragEvent.ACTION_DROP) { 21565 // About to deliver an event with coordinates to this view. Notify that now this view 21566 // has drag focus. This will send exit/enter events as needed. 21567 getViewRootImpl().setDragFocus(this, event); 21568 } 21569 return callDragEventHandler(event); 21570 } 21571 21572 final boolean callDragEventHandler(DragEvent event) { 21573 final boolean result; 21574 21575 ListenerInfo li = mListenerInfo; 21576 //noinspection SimplifiableIfStatement 21577 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 21578 && li.mOnDragListener.onDrag(this, event)) { 21579 result = true; 21580 } else { 21581 result = onDragEvent(event); 21582 } 21583 21584 switch (event.mAction) { 21585 case DragEvent.ACTION_DRAG_ENTERED: { 21586 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 21587 refreshDrawableState(); 21588 } break; 21589 case DragEvent.ACTION_DRAG_EXITED: { 21590 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 21591 refreshDrawableState(); 21592 } break; 21593 case DragEvent.ACTION_DRAG_ENDED: { 21594 mPrivateFlags2 &= ~View.DRAG_MASK; 21595 refreshDrawableState(); 21596 } break; 21597 } 21598 21599 return result; 21600 } 21601 21602 boolean canAcceptDrag() { 21603 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 21604 } 21605 21606 /** 21607 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 21608 * it is ever exposed at all. 21609 * @hide 21610 */ 21611 public void onCloseSystemDialogs(String reason) { 21612 } 21613 21614 /** 21615 * Given a Drawable whose bounds have been set to draw into this view, 21616 * update a Region being computed for 21617 * {@link #gatherTransparentRegion(android.graphics.Region)} so 21618 * that any non-transparent parts of the Drawable are removed from the 21619 * given transparent region. 21620 * 21621 * @param dr The Drawable whose transparency is to be applied to the region. 21622 * @param region A Region holding the current transparency information, 21623 * where any parts of the region that are set are considered to be 21624 * transparent. On return, this region will be modified to have the 21625 * transparency information reduced by the corresponding parts of the 21626 * Drawable that are not transparent. 21627 * {@hide} 21628 */ 21629 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 21630 if (DBG) { 21631 Log.i("View", "Getting transparent region for: " + this); 21632 } 21633 final Region r = dr.getTransparentRegion(); 21634 final Rect db = dr.getBounds(); 21635 final AttachInfo attachInfo = mAttachInfo; 21636 if (r != null && attachInfo != null) { 21637 final int w = getRight()-getLeft(); 21638 final int h = getBottom()-getTop(); 21639 if (db.left > 0) { 21640 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 21641 r.op(0, 0, db.left, h, Region.Op.UNION); 21642 } 21643 if (db.right < w) { 21644 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 21645 r.op(db.right, 0, w, h, Region.Op.UNION); 21646 } 21647 if (db.top > 0) { 21648 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 21649 r.op(0, 0, w, db.top, Region.Op.UNION); 21650 } 21651 if (db.bottom < h) { 21652 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 21653 r.op(0, db.bottom, w, h, Region.Op.UNION); 21654 } 21655 final int[] location = attachInfo.mTransparentLocation; 21656 getLocationInWindow(location); 21657 r.translate(location[0], location[1]); 21658 region.op(r, Region.Op.INTERSECT); 21659 } else { 21660 region.op(db, Region.Op.DIFFERENCE); 21661 } 21662 } 21663 21664 private void checkForLongClick(int delayOffset, float x, float y) { 21665 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 21666 mHasPerformedLongPress = false; 21667 21668 if (mPendingCheckForLongPress == null) { 21669 mPendingCheckForLongPress = new CheckForLongPress(); 21670 } 21671 mPendingCheckForLongPress.setAnchor(x, y); 21672 mPendingCheckForLongPress.rememberWindowAttachCount(); 21673 mPendingCheckForLongPress.rememberPressedState(); 21674 postDelayed(mPendingCheckForLongPress, 21675 ViewConfiguration.getLongPressTimeout() - delayOffset); 21676 } 21677 } 21678 21679 /** 21680 * Inflate a view from an XML resource. This convenience method wraps the {@link 21681 * LayoutInflater} class, which provides a full range of options for view inflation. 21682 * 21683 * @param context The Context object for your activity or application. 21684 * @param resource The resource ID to inflate 21685 * @param root A view group that will be the parent. Used to properly inflate the 21686 * layout_* parameters. 21687 * @see LayoutInflater 21688 */ 21689 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 21690 LayoutInflater factory = LayoutInflater.from(context); 21691 return factory.inflate(resource, root); 21692 } 21693 21694 /** 21695 * Scroll the view with standard behavior for scrolling beyond the normal 21696 * content boundaries. Views that call this method should override 21697 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 21698 * results of an over-scroll operation. 21699 * 21700 * Views can use this method to handle any touch or fling-based scrolling. 21701 * 21702 * @param deltaX Change in X in pixels 21703 * @param deltaY Change in Y in pixels 21704 * @param scrollX Current X scroll value in pixels before applying deltaX 21705 * @param scrollY Current Y scroll value in pixels before applying deltaY 21706 * @param scrollRangeX Maximum content scroll range along the X axis 21707 * @param scrollRangeY Maximum content scroll range along the Y axis 21708 * @param maxOverScrollX Number of pixels to overscroll by in either direction 21709 * along the X axis. 21710 * @param maxOverScrollY Number of pixels to overscroll by in either direction 21711 * along the Y axis. 21712 * @param isTouchEvent true if this scroll operation is the result of a touch event. 21713 * @return true if scrolling was clamped to an over-scroll boundary along either 21714 * axis, false otherwise. 21715 */ 21716 @SuppressWarnings({"UnusedParameters"}) 21717 protected boolean overScrollBy(int deltaX, int deltaY, 21718 int scrollX, int scrollY, 21719 int scrollRangeX, int scrollRangeY, 21720 int maxOverScrollX, int maxOverScrollY, 21721 boolean isTouchEvent) { 21722 final int overScrollMode = mOverScrollMode; 21723 final boolean canScrollHorizontal = 21724 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 21725 final boolean canScrollVertical = 21726 computeVerticalScrollRange() > computeVerticalScrollExtent(); 21727 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 21728 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 21729 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 21730 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 21731 21732 int newScrollX = scrollX + deltaX; 21733 if (!overScrollHorizontal) { 21734 maxOverScrollX = 0; 21735 } 21736 21737 int newScrollY = scrollY + deltaY; 21738 if (!overScrollVertical) { 21739 maxOverScrollY = 0; 21740 } 21741 21742 // Clamp values if at the limits and record 21743 final int left = -maxOverScrollX; 21744 final int right = maxOverScrollX + scrollRangeX; 21745 final int top = -maxOverScrollY; 21746 final int bottom = maxOverScrollY + scrollRangeY; 21747 21748 boolean clampedX = false; 21749 if (newScrollX > right) { 21750 newScrollX = right; 21751 clampedX = true; 21752 } else if (newScrollX < left) { 21753 newScrollX = left; 21754 clampedX = true; 21755 } 21756 21757 boolean clampedY = false; 21758 if (newScrollY > bottom) { 21759 newScrollY = bottom; 21760 clampedY = true; 21761 } else if (newScrollY < top) { 21762 newScrollY = top; 21763 clampedY = true; 21764 } 21765 21766 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 21767 21768 return clampedX || clampedY; 21769 } 21770 21771 /** 21772 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 21773 * respond to the results of an over-scroll operation. 21774 * 21775 * @param scrollX New X scroll value in pixels 21776 * @param scrollY New Y scroll value in pixels 21777 * @param clampedX True if scrollX was clamped to an over-scroll boundary 21778 * @param clampedY True if scrollY was clamped to an over-scroll boundary 21779 */ 21780 protected void onOverScrolled(int scrollX, int scrollY, 21781 boolean clampedX, boolean clampedY) { 21782 // Intentionally empty. 21783 } 21784 21785 /** 21786 * Returns the over-scroll mode for this view. The result will be 21787 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21788 * (allow over-scrolling only if the view content is larger than the container), 21789 * or {@link #OVER_SCROLL_NEVER}. 21790 * 21791 * @return This view's over-scroll mode. 21792 */ 21793 public int getOverScrollMode() { 21794 return mOverScrollMode; 21795 } 21796 21797 /** 21798 * Set the over-scroll mode for this view. Valid over-scroll modes are 21799 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21800 * (allow over-scrolling only if the view content is larger than the container), 21801 * or {@link #OVER_SCROLL_NEVER}. 21802 * 21803 * Setting the over-scroll mode of a view will have an effect only if the 21804 * view is capable of scrolling. 21805 * 21806 * @param overScrollMode The new over-scroll mode for this view. 21807 */ 21808 public void setOverScrollMode(int overScrollMode) { 21809 if (overScrollMode != OVER_SCROLL_ALWAYS && 21810 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 21811 overScrollMode != OVER_SCROLL_NEVER) { 21812 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 21813 } 21814 mOverScrollMode = overScrollMode; 21815 } 21816 21817 /** 21818 * Enable or disable nested scrolling for this view. 21819 * 21820 * <p>If this property is set to true the view will be permitted to initiate nested 21821 * scrolling operations with a compatible parent view in the current hierarchy. If this 21822 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 21823 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 21824 * the nested scroll.</p> 21825 * 21826 * @param enabled true to enable nested scrolling, false to disable 21827 * 21828 * @see #isNestedScrollingEnabled() 21829 */ 21830 public void setNestedScrollingEnabled(boolean enabled) { 21831 if (enabled) { 21832 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 21833 } else { 21834 stopNestedScroll(); 21835 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 21836 } 21837 } 21838 21839 /** 21840 * Returns true if nested scrolling is enabled for this view. 21841 * 21842 * <p>If nested scrolling is enabled and this View class implementation supports it, 21843 * this view will act as a nested scrolling child view when applicable, forwarding data 21844 * about the scroll operation in progress to a compatible and cooperating nested scrolling 21845 * parent.</p> 21846 * 21847 * @return true if nested scrolling is enabled 21848 * 21849 * @see #setNestedScrollingEnabled(boolean) 21850 */ 21851 public boolean isNestedScrollingEnabled() { 21852 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 21853 PFLAG3_NESTED_SCROLLING_ENABLED; 21854 } 21855 21856 /** 21857 * Begin a nestable scroll operation along the given axes. 21858 * 21859 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 21860 * 21861 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 21862 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 21863 * In the case of touch scrolling the nested scroll will be terminated automatically in 21864 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 21865 * In the event of programmatic scrolling the caller must explicitly call 21866 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 21867 * 21868 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 21869 * If it returns false the caller may ignore the rest of this contract until the next scroll. 21870 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 21871 * 21872 * <p>At each incremental step of the scroll the caller should invoke 21873 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 21874 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 21875 * parent at least partially consumed the scroll and the caller should adjust the amount it 21876 * scrolls by.</p> 21877 * 21878 * <p>After applying the remainder of the scroll delta the caller should invoke 21879 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 21880 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 21881 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 21882 * </p> 21883 * 21884 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 21885 * {@link #SCROLL_AXIS_VERTICAL}. 21886 * @return true if a cooperative parent was found and nested scrolling has been enabled for 21887 * the current gesture. 21888 * 21889 * @see #stopNestedScroll() 21890 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21891 * @see #dispatchNestedScroll(int, int, int, int, int[]) 21892 */ 21893 public boolean startNestedScroll(int axes) { 21894 if (hasNestedScrollingParent()) { 21895 // Already in progress 21896 return true; 21897 } 21898 if (isNestedScrollingEnabled()) { 21899 ViewParent p = getParent(); 21900 View child = this; 21901 while (p != null) { 21902 try { 21903 if (p.onStartNestedScroll(child, this, axes)) { 21904 mNestedScrollingParent = p; 21905 p.onNestedScrollAccepted(child, this, axes); 21906 return true; 21907 } 21908 } catch (AbstractMethodError e) { 21909 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 21910 "method onStartNestedScroll", e); 21911 // Allow the search upward to continue 21912 } 21913 if (p instanceof View) { 21914 child = (View) p; 21915 } 21916 p = p.getParent(); 21917 } 21918 } 21919 return false; 21920 } 21921 21922 /** 21923 * Stop a nested scroll in progress. 21924 * 21925 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 21926 * 21927 * @see #startNestedScroll(int) 21928 */ 21929 public void stopNestedScroll() { 21930 if (mNestedScrollingParent != null) { 21931 mNestedScrollingParent.onStopNestedScroll(this); 21932 mNestedScrollingParent = null; 21933 } 21934 } 21935 21936 /** 21937 * Returns true if this view has a nested scrolling parent. 21938 * 21939 * <p>The presence of a nested scrolling parent indicates that this view has initiated 21940 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 21941 * 21942 * @return whether this view has a nested scrolling parent 21943 */ 21944 public boolean hasNestedScrollingParent() { 21945 return mNestedScrollingParent != null; 21946 } 21947 21948 /** 21949 * Dispatch one step of a nested scroll in progress. 21950 * 21951 * <p>Implementations of views that support nested scrolling should call this to report 21952 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 21953 * is not currently in progress or nested scrolling is not 21954 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 21955 * 21956 * <p>Compatible View implementations should also call 21957 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 21958 * consuming a component of the scroll event themselves.</p> 21959 * 21960 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 21961 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 21962 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 21963 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 21964 * @param offsetInWindow Optional. If not null, on return this will contain the offset 21965 * in local view coordinates of this view from before this operation 21966 * to after it completes. View implementations may use this to adjust 21967 * expected input coordinate tracking. 21968 * @return true if the event was dispatched, false if it could not be dispatched. 21969 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21970 */ 21971 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 21972 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 21973 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21974 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 21975 int startX = 0; 21976 int startY = 0; 21977 if (offsetInWindow != null) { 21978 getLocationInWindow(offsetInWindow); 21979 startX = offsetInWindow[0]; 21980 startY = offsetInWindow[1]; 21981 } 21982 21983 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 21984 dxUnconsumed, dyUnconsumed); 21985 21986 if (offsetInWindow != null) { 21987 getLocationInWindow(offsetInWindow); 21988 offsetInWindow[0] -= startX; 21989 offsetInWindow[1] -= startY; 21990 } 21991 return true; 21992 } else if (offsetInWindow != null) { 21993 // No motion, no dispatch. Keep offsetInWindow up to date. 21994 offsetInWindow[0] = 0; 21995 offsetInWindow[1] = 0; 21996 } 21997 } 21998 return false; 21999 } 22000 22001 /** 22002 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 22003 * 22004 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 22005 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 22006 * scrolling operation to consume some or all of the scroll operation before the child view 22007 * consumes it.</p> 22008 * 22009 * @param dx Horizontal scroll distance in pixels 22010 * @param dy Vertical scroll distance in pixels 22011 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 22012 * and consumed[1] the consumed dy. 22013 * @param offsetInWindow Optional. If not null, on return this will contain the offset 22014 * in local view coordinates of this view from before this operation 22015 * to after it completes. View implementations may use this to adjust 22016 * expected input coordinate tracking. 22017 * @return true if the parent consumed some or all of the scroll delta 22018 * @see #dispatchNestedScroll(int, int, int, int, int[]) 22019 */ 22020 public boolean dispatchNestedPreScroll(int dx, int dy, 22021 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 22022 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22023 if (dx != 0 || dy != 0) { 22024 int startX = 0; 22025 int startY = 0; 22026 if (offsetInWindow != null) { 22027 getLocationInWindow(offsetInWindow); 22028 startX = offsetInWindow[0]; 22029 startY = offsetInWindow[1]; 22030 } 22031 22032 if (consumed == null) { 22033 if (mTempNestedScrollConsumed == null) { 22034 mTempNestedScrollConsumed = new int[2]; 22035 } 22036 consumed = mTempNestedScrollConsumed; 22037 } 22038 consumed[0] = 0; 22039 consumed[1] = 0; 22040 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 22041 22042 if (offsetInWindow != null) { 22043 getLocationInWindow(offsetInWindow); 22044 offsetInWindow[0] -= startX; 22045 offsetInWindow[1] -= startY; 22046 } 22047 return consumed[0] != 0 || consumed[1] != 0; 22048 } else if (offsetInWindow != null) { 22049 offsetInWindow[0] = 0; 22050 offsetInWindow[1] = 0; 22051 } 22052 } 22053 return false; 22054 } 22055 22056 /** 22057 * Dispatch a fling to a nested scrolling parent. 22058 * 22059 * <p>This method should be used to indicate that a nested scrolling child has detected 22060 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 22061 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 22062 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 22063 * along a scrollable axis.</p> 22064 * 22065 * <p>If a nested scrolling child view would normally fling but it is at the edge of 22066 * its own content, it can use this method to delegate the fling to its nested scrolling 22067 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 22068 * 22069 * @param velocityX Horizontal fling velocity in pixels per second 22070 * @param velocityY Vertical fling velocity in pixels per second 22071 * @param consumed true if the child consumed the fling, false otherwise 22072 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 22073 */ 22074 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 22075 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22076 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 22077 } 22078 return false; 22079 } 22080 22081 /** 22082 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 22083 * 22084 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 22085 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 22086 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 22087 * before the child view consumes it. If this method returns <code>true</code>, a nested 22088 * parent view consumed the fling and this view should not scroll as a result.</p> 22089 * 22090 * <p>For a better user experience, only one view in a nested scrolling chain should consume 22091 * the fling at a time. If a parent view consumed the fling this method will return false. 22092 * Custom view implementations should account for this in two ways:</p> 22093 * 22094 * <ul> 22095 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 22096 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 22097 * position regardless.</li> 22098 * <li>If a nested parent does consume the fling, this view should not scroll at all, 22099 * even to settle back to a valid idle position.</li> 22100 * </ul> 22101 * 22102 * <p>Views should also not offer fling velocities to nested parent views along an axis 22103 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 22104 * should not offer a horizontal fling velocity to its parents since scrolling along that 22105 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 22106 * 22107 * @param velocityX Horizontal fling velocity in pixels per second 22108 * @param velocityY Vertical fling velocity in pixels per second 22109 * @return true if a nested scrolling parent consumed the fling 22110 */ 22111 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 22112 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22113 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 22114 } 22115 return false; 22116 } 22117 22118 /** 22119 * Gets a scale factor that determines the distance the view should scroll 22120 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 22121 * @return The vertical scroll scale factor. 22122 * @hide 22123 */ 22124 protected float getVerticalScrollFactor() { 22125 if (mVerticalScrollFactor == 0) { 22126 TypedValue outValue = new TypedValue(); 22127 if (!mContext.getTheme().resolveAttribute( 22128 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 22129 throw new IllegalStateException( 22130 "Expected theme to define listPreferredItemHeight."); 22131 } 22132 mVerticalScrollFactor = outValue.getDimension( 22133 mContext.getResources().getDisplayMetrics()); 22134 } 22135 return mVerticalScrollFactor; 22136 } 22137 22138 /** 22139 * Gets a scale factor that determines the distance the view should scroll 22140 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 22141 * @return The horizontal scroll scale factor. 22142 * @hide 22143 */ 22144 protected float getHorizontalScrollFactor() { 22145 // TODO: Should use something else. 22146 return getVerticalScrollFactor(); 22147 } 22148 22149 /** 22150 * Return the value specifying the text direction or policy that was set with 22151 * {@link #setTextDirection(int)}. 22152 * 22153 * @return the defined text direction. It can be one of: 22154 * 22155 * {@link #TEXT_DIRECTION_INHERIT}, 22156 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22157 * {@link #TEXT_DIRECTION_ANY_RTL}, 22158 * {@link #TEXT_DIRECTION_LTR}, 22159 * {@link #TEXT_DIRECTION_RTL}, 22160 * {@link #TEXT_DIRECTION_LOCALE}, 22161 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22162 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22163 * 22164 * @attr ref android.R.styleable#View_textDirection 22165 * 22166 * @hide 22167 */ 22168 @ViewDebug.ExportedProperty(category = "text", mapping = { 22169 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22170 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22171 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22172 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22173 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22174 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22175 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22176 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22177 }) 22178 public int getRawTextDirection() { 22179 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 22180 } 22181 22182 /** 22183 * Set the text direction. 22184 * 22185 * @param textDirection the direction to set. Should be one of: 22186 * 22187 * {@link #TEXT_DIRECTION_INHERIT}, 22188 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22189 * {@link #TEXT_DIRECTION_ANY_RTL}, 22190 * {@link #TEXT_DIRECTION_LTR}, 22191 * {@link #TEXT_DIRECTION_RTL}, 22192 * {@link #TEXT_DIRECTION_LOCALE} 22193 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22194 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 22195 * 22196 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 22197 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 22198 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 22199 * 22200 * @attr ref android.R.styleable#View_textDirection 22201 */ 22202 public void setTextDirection(int textDirection) { 22203 if (getRawTextDirection() != textDirection) { 22204 // Reset the current text direction and the resolved one 22205 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 22206 resetResolvedTextDirection(); 22207 // Set the new text direction 22208 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 22209 // Do resolution 22210 resolveTextDirection(); 22211 // Notify change 22212 onRtlPropertiesChanged(getLayoutDirection()); 22213 // Refresh 22214 requestLayout(); 22215 invalidate(true); 22216 } 22217 } 22218 22219 /** 22220 * Return the resolved text direction. 22221 * 22222 * @return the resolved text direction. Returns one of: 22223 * 22224 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22225 * {@link #TEXT_DIRECTION_ANY_RTL}, 22226 * {@link #TEXT_DIRECTION_LTR}, 22227 * {@link #TEXT_DIRECTION_RTL}, 22228 * {@link #TEXT_DIRECTION_LOCALE}, 22229 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22230 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22231 * 22232 * @attr ref android.R.styleable#View_textDirection 22233 */ 22234 @ViewDebug.ExportedProperty(category = "text", mapping = { 22235 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22236 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22237 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22238 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22239 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22240 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22241 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22242 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22243 }) 22244 public int getTextDirection() { 22245 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 22246 } 22247 22248 /** 22249 * Resolve the text direction. 22250 * 22251 * @return true if resolution has been done, false otherwise. 22252 * 22253 * @hide 22254 */ 22255 public boolean resolveTextDirection() { 22256 // Reset any previous text direction resolution 22257 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22258 22259 if (hasRtlSupport()) { 22260 // Set resolved text direction flag depending on text direction flag 22261 final int textDirection = getRawTextDirection(); 22262 switch(textDirection) { 22263 case TEXT_DIRECTION_INHERIT: 22264 if (!canResolveTextDirection()) { 22265 // We cannot do the resolution if there is no parent, so use the default one 22266 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22267 // Resolution will need to happen again later 22268 return false; 22269 } 22270 22271 // Parent has not yet resolved, so we still return the default 22272 try { 22273 if (!mParent.isTextDirectionResolved()) { 22274 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22275 // Resolution will need to happen again later 22276 return false; 22277 } 22278 } catch (AbstractMethodError e) { 22279 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22280 " does not fully implement ViewParent", e); 22281 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 22282 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22283 return true; 22284 } 22285 22286 // Set current resolved direction to the same value as the parent's one 22287 int parentResolvedDirection; 22288 try { 22289 parentResolvedDirection = mParent.getTextDirection(); 22290 } catch (AbstractMethodError e) { 22291 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22292 " does not fully implement ViewParent", e); 22293 parentResolvedDirection = TEXT_DIRECTION_LTR; 22294 } 22295 switch (parentResolvedDirection) { 22296 case TEXT_DIRECTION_FIRST_STRONG: 22297 case TEXT_DIRECTION_ANY_RTL: 22298 case TEXT_DIRECTION_LTR: 22299 case TEXT_DIRECTION_RTL: 22300 case TEXT_DIRECTION_LOCALE: 22301 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22302 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22303 mPrivateFlags2 |= 22304 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22305 break; 22306 default: 22307 // Default resolved direction is "first strong" heuristic 22308 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22309 } 22310 break; 22311 case TEXT_DIRECTION_FIRST_STRONG: 22312 case TEXT_DIRECTION_ANY_RTL: 22313 case TEXT_DIRECTION_LTR: 22314 case TEXT_DIRECTION_RTL: 22315 case TEXT_DIRECTION_LOCALE: 22316 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22317 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22318 // Resolved direction is the same as text direction 22319 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22320 break; 22321 default: 22322 // Default resolved direction is "first strong" heuristic 22323 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22324 } 22325 } else { 22326 // Default resolved direction is "first strong" heuristic 22327 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22328 } 22329 22330 // Set to resolved 22331 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 22332 return true; 22333 } 22334 22335 /** 22336 * Check if text direction resolution can be done. 22337 * 22338 * @return true if text direction resolution can be done otherwise return false. 22339 */ 22340 public boolean canResolveTextDirection() { 22341 switch (getRawTextDirection()) { 22342 case TEXT_DIRECTION_INHERIT: 22343 if (mParent != null) { 22344 try { 22345 return mParent.canResolveTextDirection(); 22346 } catch (AbstractMethodError e) { 22347 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22348 " does not fully implement ViewParent", e); 22349 } 22350 } 22351 return false; 22352 22353 default: 22354 return true; 22355 } 22356 } 22357 22358 /** 22359 * Reset resolved text direction. Text direction will be resolved during a call to 22360 * {@link #onMeasure(int, int)}. 22361 * 22362 * @hide 22363 */ 22364 public void resetResolvedTextDirection() { 22365 // Reset any previous text direction resolution 22366 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22367 // Set to default value 22368 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22369 } 22370 22371 /** 22372 * @return true if text direction is inherited. 22373 * 22374 * @hide 22375 */ 22376 public boolean isTextDirectionInherited() { 22377 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 22378 } 22379 22380 /** 22381 * @return true if text direction is resolved. 22382 */ 22383 public boolean isTextDirectionResolved() { 22384 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 22385 } 22386 22387 /** 22388 * Return the value specifying the text alignment or policy that was set with 22389 * {@link #setTextAlignment(int)}. 22390 * 22391 * @return the defined text alignment. It can be one of: 22392 * 22393 * {@link #TEXT_ALIGNMENT_INHERIT}, 22394 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22395 * {@link #TEXT_ALIGNMENT_CENTER}, 22396 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22397 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22398 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22399 * {@link #TEXT_ALIGNMENT_VIEW_END} 22400 * 22401 * @attr ref android.R.styleable#View_textAlignment 22402 * 22403 * @hide 22404 */ 22405 @ViewDebug.ExportedProperty(category = "text", mapping = { 22406 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22407 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22408 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22409 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22410 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22411 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22412 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22413 }) 22414 @TextAlignment 22415 public int getRawTextAlignment() { 22416 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 22417 } 22418 22419 /** 22420 * Set the text alignment. 22421 * 22422 * @param textAlignment The text alignment to set. Should be one of 22423 * 22424 * {@link #TEXT_ALIGNMENT_INHERIT}, 22425 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22426 * {@link #TEXT_ALIGNMENT_CENTER}, 22427 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22428 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22429 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22430 * {@link #TEXT_ALIGNMENT_VIEW_END} 22431 * 22432 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 22433 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 22434 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 22435 * 22436 * @attr ref android.R.styleable#View_textAlignment 22437 */ 22438 public void setTextAlignment(@TextAlignment int textAlignment) { 22439 if (textAlignment != getRawTextAlignment()) { 22440 // Reset the current and resolved text alignment 22441 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 22442 resetResolvedTextAlignment(); 22443 // Set the new text alignment 22444 mPrivateFlags2 |= 22445 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 22446 // Do resolution 22447 resolveTextAlignment(); 22448 // Notify change 22449 onRtlPropertiesChanged(getLayoutDirection()); 22450 // Refresh 22451 requestLayout(); 22452 invalidate(true); 22453 } 22454 } 22455 22456 /** 22457 * Return the resolved text alignment. 22458 * 22459 * @return the resolved text alignment. Returns one of: 22460 * 22461 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22462 * {@link #TEXT_ALIGNMENT_CENTER}, 22463 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22464 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22465 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22466 * {@link #TEXT_ALIGNMENT_VIEW_END} 22467 * 22468 * @attr ref android.R.styleable#View_textAlignment 22469 */ 22470 @ViewDebug.ExportedProperty(category = "text", mapping = { 22471 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22472 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22473 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22474 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22475 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22476 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22477 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22478 }) 22479 @TextAlignment 22480 public int getTextAlignment() { 22481 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 22482 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 22483 } 22484 22485 /** 22486 * Resolve the text alignment. 22487 * 22488 * @return true if resolution has been done, false otherwise. 22489 * 22490 * @hide 22491 */ 22492 public boolean resolveTextAlignment() { 22493 // Reset any previous text alignment resolution 22494 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22495 22496 if (hasRtlSupport()) { 22497 // Set resolved text alignment flag depending on text alignment flag 22498 final int textAlignment = getRawTextAlignment(); 22499 switch (textAlignment) { 22500 case TEXT_ALIGNMENT_INHERIT: 22501 // Check if we can resolve the text alignment 22502 if (!canResolveTextAlignment()) { 22503 // We cannot do the resolution if there is no parent so use the default 22504 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22505 // Resolution will need to happen again later 22506 return false; 22507 } 22508 22509 // Parent has not yet resolved, so we still return the default 22510 try { 22511 if (!mParent.isTextAlignmentResolved()) { 22512 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22513 // Resolution will need to happen again later 22514 return false; 22515 } 22516 } catch (AbstractMethodError e) { 22517 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22518 " does not fully implement ViewParent", e); 22519 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 22520 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22521 return true; 22522 } 22523 22524 int parentResolvedTextAlignment; 22525 try { 22526 parentResolvedTextAlignment = mParent.getTextAlignment(); 22527 } catch (AbstractMethodError e) { 22528 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22529 " does not fully implement ViewParent", e); 22530 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 22531 } 22532 switch (parentResolvedTextAlignment) { 22533 case TEXT_ALIGNMENT_GRAVITY: 22534 case TEXT_ALIGNMENT_TEXT_START: 22535 case TEXT_ALIGNMENT_TEXT_END: 22536 case TEXT_ALIGNMENT_CENTER: 22537 case TEXT_ALIGNMENT_VIEW_START: 22538 case TEXT_ALIGNMENT_VIEW_END: 22539 // Resolved text alignment is the same as the parent resolved 22540 // text alignment 22541 mPrivateFlags2 |= 22542 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22543 break; 22544 default: 22545 // Use default resolved text alignment 22546 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22547 } 22548 break; 22549 case TEXT_ALIGNMENT_GRAVITY: 22550 case TEXT_ALIGNMENT_TEXT_START: 22551 case TEXT_ALIGNMENT_TEXT_END: 22552 case TEXT_ALIGNMENT_CENTER: 22553 case TEXT_ALIGNMENT_VIEW_START: 22554 case TEXT_ALIGNMENT_VIEW_END: 22555 // Resolved text alignment is the same as text alignment 22556 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22557 break; 22558 default: 22559 // Use default resolved text alignment 22560 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22561 } 22562 } else { 22563 // Use default resolved text alignment 22564 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22565 } 22566 22567 // Set the resolved 22568 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22569 return true; 22570 } 22571 22572 /** 22573 * Check if text alignment resolution can be done. 22574 * 22575 * @return true if text alignment resolution can be done otherwise return false. 22576 */ 22577 public boolean canResolveTextAlignment() { 22578 switch (getRawTextAlignment()) { 22579 case TEXT_DIRECTION_INHERIT: 22580 if (mParent != null) { 22581 try { 22582 return mParent.canResolveTextAlignment(); 22583 } catch (AbstractMethodError e) { 22584 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22585 " does not fully implement ViewParent", e); 22586 } 22587 } 22588 return false; 22589 22590 default: 22591 return true; 22592 } 22593 } 22594 22595 /** 22596 * Reset resolved text alignment. Text alignment will be resolved during a call to 22597 * {@link #onMeasure(int, int)}. 22598 * 22599 * @hide 22600 */ 22601 public void resetResolvedTextAlignment() { 22602 // Reset any previous text alignment resolution 22603 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22604 // Set to default 22605 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22606 } 22607 22608 /** 22609 * @return true if text alignment is inherited. 22610 * 22611 * @hide 22612 */ 22613 public boolean isTextAlignmentInherited() { 22614 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 22615 } 22616 22617 /** 22618 * @return true if text alignment is resolved. 22619 */ 22620 public boolean isTextAlignmentResolved() { 22621 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22622 } 22623 22624 /** 22625 * Generate a value suitable for use in {@link #setId(int)}. 22626 * This value will not collide with ID values generated at build time by aapt for R.id. 22627 * 22628 * @return a generated ID value 22629 */ 22630 public static int generateViewId() { 22631 for (;;) { 22632 final int result = sNextGeneratedId.get(); 22633 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 22634 int newValue = result + 1; 22635 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 22636 if (sNextGeneratedId.compareAndSet(result, newValue)) { 22637 return result; 22638 } 22639 } 22640 } 22641 22642 private static boolean isViewIdGenerated(int id) { 22643 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 22644 } 22645 22646 /** 22647 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 22648 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 22649 * a normal View or a ViewGroup with 22650 * {@link android.view.ViewGroup#isTransitionGroup()} true. 22651 * @hide 22652 */ 22653 public void captureTransitioningViews(List<View> transitioningViews) { 22654 if (getVisibility() == View.VISIBLE) { 22655 transitioningViews.add(this); 22656 } 22657 } 22658 22659 /** 22660 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 22661 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 22662 * @hide 22663 */ 22664 public void findNamedViews(Map<String, View> namedElements) { 22665 if (getVisibility() == VISIBLE || mGhostView != null) { 22666 String transitionName = getTransitionName(); 22667 if (transitionName != null) { 22668 namedElements.put(transitionName, this); 22669 } 22670 } 22671 } 22672 22673 /** 22674 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 22675 * The default implementation does not care the location or event types, but some subclasses 22676 * may use it (such as WebViews). 22677 * @param event The MotionEvent from a mouse 22678 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 22679 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 22680 * @see PointerIcon 22681 */ 22682 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 22683 final float x = event.getX(pointerIndex); 22684 final float y = event.getY(pointerIndex); 22685 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 22686 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 22687 } 22688 return mPointerIcon; 22689 } 22690 22691 /** 22692 * Set the pointer icon for the current view. 22693 * Passing {@code null} will restore the pointer icon to its default value. 22694 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 22695 */ 22696 public void setPointerIcon(PointerIcon pointerIcon) { 22697 mPointerIcon = pointerIcon; 22698 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 22699 return; 22700 } 22701 try { 22702 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 22703 } catch (RemoteException e) { 22704 } 22705 } 22706 22707 /** 22708 * Gets the pointer icon for the current view. 22709 */ 22710 public PointerIcon getPointerIcon() { 22711 return mPointerIcon; 22712 } 22713 22714 // 22715 // Properties 22716 // 22717 /** 22718 * A Property wrapper around the <code>alpha</code> functionality handled by the 22719 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 22720 */ 22721 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 22722 @Override 22723 public void setValue(View object, float value) { 22724 object.setAlpha(value); 22725 } 22726 22727 @Override 22728 public Float get(View object) { 22729 return object.getAlpha(); 22730 } 22731 }; 22732 22733 /** 22734 * A Property wrapper around the <code>translationX</code> functionality handled by the 22735 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 22736 */ 22737 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 22738 @Override 22739 public void setValue(View object, float value) { 22740 object.setTranslationX(value); 22741 } 22742 22743 @Override 22744 public Float get(View object) { 22745 return object.getTranslationX(); 22746 } 22747 }; 22748 22749 /** 22750 * A Property wrapper around the <code>translationY</code> functionality handled by the 22751 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 22752 */ 22753 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 22754 @Override 22755 public void setValue(View object, float value) { 22756 object.setTranslationY(value); 22757 } 22758 22759 @Override 22760 public Float get(View object) { 22761 return object.getTranslationY(); 22762 } 22763 }; 22764 22765 /** 22766 * A Property wrapper around the <code>translationZ</code> functionality handled by the 22767 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 22768 */ 22769 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 22770 @Override 22771 public void setValue(View object, float value) { 22772 object.setTranslationZ(value); 22773 } 22774 22775 @Override 22776 public Float get(View object) { 22777 return object.getTranslationZ(); 22778 } 22779 }; 22780 22781 /** 22782 * A Property wrapper around the <code>x</code> functionality handled by the 22783 * {@link View#setX(float)} and {@link View#getX()} methods. 22784 */ 22785 public static final Property<View, Float> X = new FloatProperty<View>("x") { 22786 @Override 22787 public void setValue(View object, float value) { 22788 object.setX(value); 22789 } 22790 22791 @Override 22792 public Float get(View object) { 22793 return object.getX(); 22794 } 22795 }; 22796 22797 /** 22798 * A Property wrapper around the <code>y</code> functionality handled by the 22799 * {@link View#setY(float)} and {@link View#getY()} methods. 22800 */ 22801 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 22802 @Override 22803 public void setValue(View object, float value) { 22804 object.setY(value); 22805 } 22806 22807 @Override 22808 public Float get(View object) { 22809 return object.getY(); 22810 } 22811 }; 22812 22813 /** 22814 * A Property wrapper around the <code>z</code> functionality handled by the 22815 * {@link View#setZ(float)} and {@link View#getZ()} methods. 22816 */ 22817 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 22818 @Override 22819 public void setValue(View object, float value) { 22820 object.setZ(value); 22821 } 22822 22823 @Override 22824 public Float get(View object) { 22825 return object.getZ(); 22826 } 22827 }; 22828 22829 /** 22830 * A Property wrapper around the <code>rotation</code> functionality handled by the 22831 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 22832 */ 22833 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 22834 @Override 22835 public void setValue(View object, float value) { 22836 object.setRotation(value); 22837 } 22838 22839 @Override 22840 public Float get(View object) { 22841 return object.getRotation(); 22842 } 22843 }; 22844 22845 /** 22846 * A Property wrapper around the <code>rotationX</code> functionality handled by the 22847 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 22848 */ 22849 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 22850 @Override 22851 public void setValue(View object, float value) { 22852 object.setRotationX(value); 22853 } 22854 22855 @Override 22856 public Float get(View object) { 22857 return object.getRotationX(); 22858 } 22859 }; 22860 22861 /** 22862 * A Property wrapper around the <code>rotationY</code> functionality handled by the 22863 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 22864 */ 22865 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 22866 @Override 22867 public void setValue(View object, float value) { 22868 object.setRotationY(value); 22869 } 22870 22871 @Override 22872 public Float get(View object) { 22873 return object.getRotationY(); 22874 } 22875 }; 22876 22877 /** 22878 * A Property wrapper around the <code>scaleX</code> functionality handled by the 22879 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 22880 */ 22881 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 22882 @Override 22883 public void setValue(View object, float value) { 22884 object.setScaleX(value); 22885 } 22886 22887 @Override 22888 public Float get(View object) { 22889 return object.getScaleX(); 22890 } 22891 }; 22892 22893 /** 22894 * A Property wrapper around the <code>scaleY</code> functionality handled by the 22895 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 22896 */ 22897 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 22898 @Override 22899 public void setValue(View object, float value) { 22900 object.setScaleY(value); 22901 } 22902 22903 @Override 22904 public Float get(View object) { 22905 return object.getScaleY(); 22906 } 22907 }; 22908 22909 /** 22910 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 22911 * Each MeasureSpec represents a requirement for either the width or the height. 22912 * A MeasureSpec is comprised of a size and a mode. There are three possible 22913 * modes: 22914 * <dl> 22915 * <dt>UNSPECIFIED</dt> 22916 * <dd> 22917 * The parent has not imposed any constraint on the child. It can be whatever size 22918 * it wants. 22919 * </dd> 22920 * 22921 * <dt>EXACTLY</dt> 22922 * <dd> 22923 * The parent has determined an exact size for the child. The child is going to be 22924 * given those bounds regardless of how big it wants to be. 22925 * </dd> 22926 * 22927 * <dt>AT_MOST</dt> 22928 * <dd> 22929 * The child can be as large as it wants up to the specified size. 22930 * </dd> 22931 * </dl> 22932 * 22933 * MeasureSpecs are implemented as ints to reduce object allocation. This class 22934 * is provided to pack and unpack the <size, mode> tuple into the int. 22935 */ 22936 public static class MeasureSpec { 22937 private static final int MODE_SHIFT = 30; 22938 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 22939 22940 /** @hide */ 22941 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 22942 @Retention(RetentionPolicy.SOURCE) 22943 public @interface MeasureSpecMode {} 22944 22945 /** 22946 * Measure specification mode: The parent has not imposed any constraint 22947 * on the child. It can be whatever size it wants. 22948 */ 22949 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 22950 22951 /** 22952 * Measure specification mode: The parent has determined an exact size 22953 * for the child. The child is going to be given those bounds regardless 22954 * of how big it wants to be. 22955 */ 22956 public static final int EXACTLY = 1 << MODE_SHIFT; 22957 22958 /** 22959 * Measure specification mode: The child can be as large as it wants up 22960 * to the specified size. 22961 */ 22962 public static final int AT_MOST = 2 << MODE_SHIFT; 22963 22964 /** 22965 * Creates a measure specification based on the supplied size and mode. 22966 * 22967 * The mode must always be one of the following: 22968 * <ul> 22969 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 22970 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 22971 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 22972 * </ul> 22973 * 22974 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 22975 * implementation was such that the order of arguments did not matter 22976 * and overflow in either value could impact the resulting MeasureSpec. 22977 * {@link android.widget.RelativeLayout} was affected by this bug. 22978 * Apps targeting API levels greater than 17 will get the fixed, more strict 22979 * behavior.</p> 22980 * 22981 * @param size the size of the measure specification 22982 * @param mode the mode of the measure specification 22983 * @return the measure specification based on size and mode 22984 */ 22985 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 22986 @MeasureSpecMode int mode) { 22987 if (sUseBrokenMakeMeasureSpec) { 22988 return size + mode; 22989 } else { 22990 return (size & ~MODE_MASK) | (mode & MODE_MASK); 22991 } 22992 } 22993 22994 /** 22995 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 22996 * will automatically get a size of 0. Older apps expect this. 22997 * 22998 * @hide internal use only for compatibility with system widgets and older apps 22999 */ 23000 public static int makeSafeMeasureSpec(int size, int mode) { 23001 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 23002 return 0; 23003 } 23004 return makeMeasureSpec(size, mode); 23005 } 23006 23007 /** 23008 * Extracts the mode from the supplied measure specification. 23009 * 23010 * @param measureSpec the measure specification to extract the mode from 23011 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 23012 * {@link android.view.View.MeasureSpec#AT_MOST} or 23013 * {@link android.view.View.MeasureSpec#EXACTLY} 23014 */ 23015 @MeasureSpecMode 23016 public static int getMode(int measureSpec) { 23017 //noinspection ResourceType 23018 return (measureSpec & MODE_MASK); 23019 } 23020 23021 /** 23022 * Extracts the size from the supplied measure specification. 23023 * 23024 * @param measureSpec the measure specification to extract the size from 23025 * @return the size in pixels defined in the supplied measure specification 23026 */ 23027 public static int getSize(int measureSpec) { 23028 return (measureSpec & ~MODE_MASK); 23029 } 23030 23031 static int adjust(int measureSpec, int delta) { 23032 final int mode = getMode(measureSpec); 23033 int size = getSize(measureSpec); 23034 if (mode == UNSPECIFIED) { 23035 // No need to adjust size for UNSPECIFIED mode. 23036 return makeMeasureSpec(size, UNSPECIFIED); 23037 } 23038 size += delta; 23039 if (size < 0) { 23040 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 23041 ") spec: " + toString(measureSpec) + " delta: " + delta); 23042 size = 0; 23043 } 23044 return makeMeasureSpec(size, mode); 23045 } 23046 23047 /** 23048 * Returns a String representation of the specified measure 23049 * specification. 23050 * 23051 * @param measureSpec the measure specification to convert to a String 23052 * @return a String with the following format: "MeasureSpec: MODE SIZE" 23053 */ 23054 public static String toString(int measureSpec) { 23055 int mode = getMode(measureSpec); 23056 int size = getSize(measureSpec); 23057 23058 StringBuilder sb = new StringBuilder("MeasureSpec: "); 23059 23060 if (mode == UNSPECIFIED) 23061 sb.append("UNSPECIFIED "); 23062 else if (mode == EXACTLY) 23063 sb.append("EXACTLY "); 23064 else if (mode == AT_MOST) 23065 sb.append("AT_MOST "); 23066 else 23067 sb.append(mode).append(" "); 23068 23069 sb.append(size); 23070 return sb.toString(); 23071 } 23072 } 23073 23074 private final class CheckForLongPress implements Runnable { 23075 private int mOriginalWindowAttachCount; 23076 private float mX; 23077 private float mY; 23078 private boolean mOriginalPressedState; 23079 23080 @Override 23081 public void run() { 23082 if ((mOriginalPressedState == isPressed()) && (mParent != null) 23083 && mOriginalWindowAttachCount == mWindowAttachCount) { 23084 if (performLongClick(mX, mY)) { 23085 mHasPerformedLongPress = true; 23086 } 23087 } 23088 } 23089 23090 public void setAnchor(float x, float y) { 23091 mX = x; 23092 mY = y; 23093 } 23094 23095 public void rememberWindowAttachCount() { 23096 mOriginalWindowAttachCount = mWindowAttachCount; 23097 } 23098 23099 public void rememberPressedState() { 23100 mOriginalPressedState = isPressed(); 23101 } 23102 } 23103 23104 private final class CheckForTap implements Runnable { 23105 public float x; 23106 public float y; 23107 23108 @Override 23109 public void run() { 23110 mPrivateFlags &= ~PFLAG_PREPRESSED; 23111 setPressed(true, x, y); 23112 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 23113 } 23114 } 23115 23116 private final class PerformClick implements Runnable { 23117 @Override 23118 public void run() { 23119 performClick(); 23120 } 23121 } 23122 23123 /** 23124 * This method returns a ViewPropertyAnimator object, which can be used to animate 23125 * specific properties on this View. 23126 * 23127 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 23128 */ 23129 public ViewPropertyAnimator animate() { 23130 if (mAnimator == null) { 23131 mAnimator = new ViewPropertyAnimator(this); 23132 } 23133 return mAnimator; 23134 } 23135 23136 /** 23137 * Sets the name of the View to be used to identify Views in Transitions. 23138 * Names should be unique in the View hierarchy. 23139 * 23140 * @param transitionName The name of the View to uniquely identify it for Transitions. 23141 */ 23142 public final void setTransitionName(String transitionName) { 23143 mTransitionName = transitionName; 23144 } 23145 23146 /** 23147 * Returns the name of the View to be used to identify Views in Transitions. 23148 * Names should be unique in the View hierarchy. 23149 * 23150 * <p>This returns null if the View has not been given a name.</p> 23151 * 23152 * @return The name used of the View to be used to identify Views in Transitions or null 23153 * if no name has been given. 23154 */ 23155 @ViewDebug.ExportedProperty 23156 public String getTransitionName() { 23157 return mTransitionName; 23158 } 23159 23160 /** 23161 * @hide 23162 */ 23163 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 23164 // Do nothing. 23165 } 23166 23167 /** 23168 * Interface definition for a callback to be invoked when a hardware key event is 23169 * dispatched to this view. The callback will be invoked before the key event is 23170 * given to the view. This is only useful for hardware keyboards; a software input 23171 * method has no obligation to trigger this listener. 23172 */ 23173 public interface OnKeyListener { 23174 /** 23175 * Called when a hardware key is dispatched to a view. This allows listeners to 23176 * get a chance to respond before the target view. 23177 * <p>Key presses in software keyboards will generally NOT trigger this method, 23178 * although some may elect to do so in some situations. Do not assume a 23179 * software input method has to be key-based; even if it is, it may use key presses 23180 * in a different way than you expect, so there is no way to reliably catch soft 23181 * input key presses. 23182 * 23183 * @param v The view the key has been dispatched to. 23184 * @param keyCode The code for the physical key that was pressed 23185 * @param event The KeyEvent object containing full information about 23186 * the event. 23187 * @return True if the listener has consumed the event, false otherwise. 23188 */ 23189 boolean onKey(View v, int keyCode, KeyEvent event); 23190 } 23191 23192 /** 23193 * Interface definition for a callback to be invoked when a touch event is 23194 * dispatched to this view. The callback will be invoked before the touch 23195 * event is given to the view. 23196 */ 23197 public interface OnTouchListener { 23198 /** 23199 * Called when a touch event is dispatched to a view. This allows listeners to 23200 * get a chance to respond before the target view. 23201 * 23202 * @param v The view the touch event has been dispatched to. 23203 * @param event The MotionEvent object containing full information about 23204 * the event. 23205 * @return True if the listener has consumed the event, false otherwise. 23206 */ 23207 boolean onTouch(View v, MotionEvent event); 23208 } 23209 23210 /** 23211 * Interface definition for a callback to be invoked when a hover event is 23212 * dispatched to this view. The callback will be invoked before the hover 23213 * event is given to the view. 23214 */ 23215 public interface OnHoverListener { 23216 /** 23217 * Called when a hover event is dispatched to a view. This allows listeners to 23218 * get a chance to respond before the target view. 23219 * 23220 * @param v The view the hover event has been dispatched to. 23221 * @param event The MotionEvent object containing full information about 23222 * the event. 23223 * @return True if the listener has consumed the event, false otherwise. 23224 */ 23225 boolean onHover(View v, MotionEvent event); 23226 } 23227 23228 /** 23229 * Interface definition for a callback to be invoked when a generic motion event is 23230 * dispatched to this view. The callback will be invoked before the generic motion 23231 * event is given to the view. 23232 */ 23233 public interface OnGenericMotionListener { 23234 /** 23235 * Called when a generic motion event is dispatched to a view. This allows listeners to 23236 * get a chance to respond before the target view. 23237 * 23238 * @param v The view the generic motion event has been dispatched to. 23239 * @param event The MotionEvent object containing full information about 23240 * the event. 23241 * @return True if the listener has consumed the event, false otherwise. 23242 */ 23243 boolean onGenericMotion(View v, MotionEvent event); 23244 } 23245 23246 /** 23247 * Interface definition for a callback to be invoked when a view has been clicked and held. 23248 */ 23249 public interface OnLongClickListener { 23250 /** 23251 * Called when a view has been clicked and held. 23252 * 23253 * @param v The view that was clicked and held. 23254 * 23255 * @return true if the callback consumed the long click, false otherwise. 23256 */ 23257 boolean onLongClick(View v); 23258 } 23259 23260 /** 23261 * Interface definition for a callback to be invoked when a drag is being dispatched 23262 * to this view. The callback will be invoked before the hosting view's own 23263 * onDrag(event) method. If the listener wants to fall back to the hosting view's 23264 * onDrag(event) behavior, it should return 'false' from this callback. 23265 * 23266 * <div class="special reference"> 23267 * <h3>Developer Guides</h3> 23268 * <p>For a guide to implementing drag and drop features, read the 23269 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 23270 * </div> 23271 */ 23272 public interface OnDragListener { 23273 /** 23274 * Called when a drag event is dispatched to a view. This allows listeners 23275 * to get a chance to override base View behavior. 23276 * 23277 * @param v The View that received the drag event. 23278 * @param event The {@link android.view.DragEvent} object for the drag event. 23279 * @return {@code true} if the drag event was handled successfully, or {@code false} 23280 * if the drag event was not handled. Note that {@code false} will trigger the View 23281 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 23282 */ 23283 boolean onDrag(View v, DragEvent event); 23284 } 23285 23286 /** 23287 * Interface definition for a callback to be invoked when the focus state of 23288 * a view changed. 23289 */ 23290 public interface OnFocusChangeListener { 23291 /** 23292 * Called when the focus state of a view has changed. 23293 * 23294 * @param v The view whose state has changed. 23295 * @param hasFocus The new focus state of v. 23296 */ 23297 void onFocusChange(View v, boolean hasFocus); 23298 } 23299 23300 /** 23301 * Interface definition for a callback to be invoked when a view is clicked. 23302 */ 23303 public interface OnClickListener { 23304 /** 23305 * Called when a view has been clicked. 23306 * 23307 * @param v The view that was clicked. 23308 */ 23309 void onClick(View v); 23310 } 23311 23312 /** 23313 * Interface definition for a callback to be invoked when a view is context clicked. 23314 */ 23315 public interface OnContextClickListener { 23316 /** 23317 * Called when a view is context clicked. 23318 * 23319 * @param v The view that has been context clicked. 23320 * @return true if the callback consumed the context click, false otherwise. 23321 */ 23322 boolean onContextClick(View v); 23323 } 23324 23325 /** 23326 * Interface definition for a callback to be invoked when the context menu 23327 * for this view is being built. 23328 */ 23329 public interface OnCreateContextMenuListener { 23330 /** 23331 * Called when the context menu for this view is being built. It is not 23332 * safe to hold onto the menu after this method returns. 23333 * 23334 * @param menu The context menu that is being built 23335 * @param v The view for which the context menu is being built 23336 * @param menuInfo Extra information about the item for which the 23337 * context menu should be shown. This information will vary 23338 * depending on the class of v. 23339 */ 23340 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 23341 } 23342 23343 /** 23344 * Interface definition for a callback to be invoked when the status bar changes 23345 * visibility. This reports <strong>global</strong> changes to the system UI 23346 * state, not what the application is requesting. 23347 * 23348 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 23349 */ 23350 public interface OnSystemUiVisibilityChangeListener { 23351 /** 23352 * Called when the status bar changes visibility because of a call to 23353 * {@link View#setSystemUiVisibility(int)}. 23354 * 23355 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 23356 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 23357 * This tells you the <strong>global</strong> state of these UI visibility 23358 * flags, not what your app is currently applying. 23359 */ 23360 public void onSystemUiVisibilityChange(int visibility); 23361 } 23362 23363 /** 23364 * Interface definition for a callback to be invoked when this view is attached 23365 * or detached from its window. 23366 */ 23367 public interface OnAttachStateChangeListener { 23368 /** 23369 * Called when the view is attached to a window. 23370 * @param v The view that was attached 23371 */ 23372 public void onViewAttachedToWindow(View v); 23373 /** 23374 * Called when the view is detached from a window. 23375 * @param v The view that was detached 23376 */ 23377 public void onViewDetachedFromWindow(View v); 23378 } 23379 23380 /** 23381 * Listener for applying window insets on a view in a custom way. 23382 * 23383 * <p>Apps may choose to implement this interface if they want to apply custom policy 23384 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 23385 * is set, its 23386 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 23387 * method will be called instead of the View's own 23388 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 23389 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 23390 * the View's normal behavior as part of its own.</p> 23391 */ 23392 public interface OnApplyWindowInsetsListener { 23393 /** 23394 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 23395 * on a View, this listener method will be called instead of the view's own 23396 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 23397 * 23398 * @param v The view applying window insets 23399 * @param insets The insets to apply 23400 * @return The insets supplied, minus any insets that were consumed 23401 */ 23402 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 23403 } 23404 23405 private final class UnsetPressedState implements Runnable { 23406 @Override 23407 public void run() { 23408 setPressed(false); 23409 } 23410 } 23411 23412 /** 23413 * Base class for derived classes that want to save and restore their own 23414 * state in {@link android.view.View#onSaveInstanceState()}. 23415 */ 23416 public static class BaseSavedState extends AbsSavedState { 23417 String mStartActivityRequestWhoSaved; 23418 23419 /** 23420 * Constructor used when reading from a parcel. Reads the state of the superclass. 23421 * 23422 * @param source parcel to read from 23423 */ 23424 public BaseSavedState(Parcel source) { 23425 this(source, null); 23426 } 23427 23428 /** 23429 * Constructor used when reading from a parcel using a given class loader. 23430 * Reads the state of the superclass. 23431 * 23432 * @param source parcel to read from 23433 * @param loader ClassLoader to use for reading 23434 */ 23435 public BaseSavedState(Parcel source, ClassLoader loader) { 23436 super(source, loader); 23437 mStartActivityRequestWhoSaved = source.readString(); 23438 } 23439 23440 /** 23441 * Constructor called by derived classes when creating their SavedState objects 23442 * 23443 * @param superState The state of the superclass of this view 23444 */ 23445 public BaseSavedState(Parcelable superState) { 23446 super(superState); 23447 } 23448 23449 @Override 23450 public void writeToParcel(Parcel out, int flags) { 23451 super.writeToParcel(out, flags); 23452 out.writeString(mStartActivityRequestWhoSaved); 23453 } 23454 23455 public static final Parcelable.Creator<BaseSavedState> CREATOR 23456 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 23457 @Override 23458 public BaseSavedState createFromParcel(Parcel in) { 23459 return new BaseSavedState(in); 23460 } 23461 23462 @Override 23463 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 23464 return new BaseSavedState(in, loader); 23465 } 23466 23467 @Override 23468 public BaseSavedState[] newArray(int size) { 23469 return new BaseSavedState[size]; 23470 } 23471 }; 23472 } 23473 23474 /** 23475 * A set of information given to a view when it is attached to its parent 23476 * window. 23477 */ 23478 final static class AttachInfo { 23479 interface Callbacks { 23480 void playSoundEffect(int effectId); 23481 boolean performHapticFeedback(int effectId, boolean always); 23482 } 23483 23484 /** 23485 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 23486 * to a Handler. This class contains the target (View) to invalidate and 23487 * the coordinates of the dirty rectangle. 23488 * 23489 * For performance purposes, this class also implements a pool of up to 23490 * POOL_LIMIT objects that get reused. This reduces memory allocations 23491 * whenever possible. 23492 */ 23493 static class InvalidateInfo { 23494 private static final int POOL_LIMIT = 10; 23495 23496 private static final SynchronizedPool<InvalidateInfo> sPool = 23497 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 23498 23499 View target; 23500 23501 int left; 23502 int top; 23503 int right; 23504 int bottom; 23505 23506 public static InvalidateInfo obtain() { 23507 InvalidateInfo instance = sPool.acquire(); 23508 return (instance != null) ? instance : new InvalidateInfo(); 23509 } 23510 23511 public void recycle() { 23512 target = null; 23513 sPool.release(this); 23514 } 23515 } 23516 23517 final IWindowSession mSession; 23518 23519 final IWindow mWindow; 23520 23521 final IBinder mWindowToken; 23522 23523 final Display mDisplay; 23524 23525 final Callbacks mRootCallbacks; 23526 23527 IWindowId mIWindowId; 23528 WindowId mWindowId; 23529 23530 /** 23531 * The top view of the hierarchy. 23532 */ 23533 View mRootView; 23534 23535 IBinder mPanelParentWindowToken; 23536 23537 boolean mHardwareAccelerated; 23538 boolean mHardwareAccelerationRequested; 23539 ThreadedRenderer mThreadedRenderer; 23540 List<RenderNode> mPendingAnimatingRenderNodes; 23541 23542 /** 23543 * The state of the display to which the window is attached, as reported 23544 * by {@link Display#getState()}. Note that the display state constants 23545 * declared by {@link Display} do not exactly line up with the screen state 23546 * constants declared by {@link View} (there are more display states than 23547 * screen states). 23548 */ 23549 int mDisplayState = Display.STATE_UNKNOWN; 23550 23551 /** 23552 * Scale factor used by the compatibility mode 23553 */ 23554 float mApplicationScale; 23555 23556 /** 23557 * Indicates whether the application is in compatibility mode 23558 */ 23559 boolean mScalingRequired; 23560 23561 /** 23562 * Left position of this view's window 23563 */ 23564 int mWindowLeft; 23565 23566 /** 23567 * Top position of this view's window 23568 */ 23569 int mWindowTop; 23570 23571 /** 23572 * Indicates whether views need to use 32-bit drawing caches 23573 */ 23574 boolean mUse32BitDrawingCache; 23575 23576 /** 23577 * For windows that are full-screen but using insets to layout inside 23578 * of the screen areas, these are the current insets to appear inside 23579 * the overscan area of the display. 23580 */ 23581 final Rect mOverscanInsets = new Rect(); 23582 23583 /** 23584 * For windows that are full-screen but using insets to layout inside 23585 * of the screen decorations, these are the current insets for the 23586 * content of the window. 23587 */ 23588 final Rect mContentInsets = new Rect(); 23589 23590 /** 23591 * For windows that are full-screen but using insets to layout inside 23592 * of the screen decorations, these are the current insets for the 23593 * actual visible parts of the window. 23594 */ 23595 final Rect mVisibleInsets = new Rect(); 23596 23597 /** 23598 * For windows that are full-screen but using insets to layout inside 23599 * of the screen decorations, these are the current insets for the 23600 * stable system windows. 23601 */ 23602 final Rect mStableInsets = new Rect(); 23603 23604 /** 23605 * For windows that include areas that are not covered by real surface these are the outsets 23606 * for real surface. 23607 */ 23608 final Rect mOutsets = new Rect(); 23609 23610 /** 23611 * In multi-window we force show the navigation bar. Because we don't want that the surface 23612 * size changes in this mode, we instead have a flag whether the navigation bar size should 23613 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 23614 */ 23615 boolean mAlwaysConsumeNavBar; 23616 23617 /** 23618 * The internal insets given by this window. This value is 23619 * supplied by the client (through 23620 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 23621 * be given to the window manager when changed to be used in laying 23622 * out windows behind it. 23623 */ 23624 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 23625 = new ViewTreeObserver.InternalInsetsInfo(); 23626 23627 /** 23628 * Set to true when mGivenInternalInsets is non-empty. 23629 */ 23630 boolean mHasNonEmptyGivenInternalInsets; 23631 23632 /** 23633 * All views in the window's hierarchy that serve as scroll containers, 23634 * used to determine if the window can be resized or must be panned 23635 * to adjust for a soft input area. 23636 */ 23637 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 23638 23639 final KeyEvent.DispatcherState mKeyDispatchState 23640 = new KeyEvent.DispatcherState(); 23641 23642 /** 23643 * Indicates whether the view's window currently has the focus. 23644 */ 23645 boolean mHasWindowFocus; 23646 23647 /** 23648 * The current visibility of the window. 23649 */ 23650 int mWindowVisibility; 23651 23652 /** 23653 * Indicates the time at which drawing started to occur. 23654 */ 23655 long mDrawingTime; 23656 23657 /** 23658 * Indicates whether or not ignoring the DIRTY_MASK flags. 23659 */ 23660 boolean mIgnoreDirtyState; 23661 23662 /** 23663 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 23664 * to avoid clearing that flag prematurely. 23665 */ 23666 boolean mSetIgnoreDirtyState = false; 23667 23668 /** 23669 * Indicates whether the view's window is currently in touch mode. 23670 */ 23671 boolean mInTouchMode; 23672 23673 /** 23674 * Indicates whether the view has requested unbuffered input dispatching for the current 23675 * event stream. 23676 */ 23677 boolean mUnbufferedDispatchRequested; 23678 23679 /** 23680 * Indicates that ViewAncestor should trigger a global layout change 23681 * the next time it performs a traversal 23682 */ 23683 boolean mRecomputeGlobalAttributes; 23684 23685 /** 23686 * Always report new attributes at next traversal. 23687 */ 23688 boolean mForceReportNewAttributes; 23689 23690 /** 23691 * Set during a traveral if any views want to keep the screen on. 23692 */ 23693 boolean mKeepScreenOn; 23694 23695 /** 23696 * Set during a traveral if the light center needs to be updated. 23697 */ 23698 boolean mNeedsUpdateLightCenter; 23699 23700 /** 23701 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 23702 */ 23703 int mSystemUiVisibility; 23704 23705 /** 23706 * Hack to force certain system UI visibility flags to be cleared. 23707 */ 23708 int mDisabledSystemUiVisibility; 23709 23710 /** 23711 * Last global system UI visibility reported by the window manager. 23712 */ 23713 int mGlobalSystemUiVisibility = -1; 23714 23715 /** 23716 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 23717 * attached. 23718 */ 23719 boolean mHasSystemUiListeners; 23720 23721 /** 23722 * Set if the window has requested to extend into the overscan region 23723 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 23724 */ 23725 boolean mOverscanRequested; 23726 23727 /** 23728 * Set if the visibility of any views has changed. 23729 */ 23730 boolean mViewVisibilityChanged; 23731 23732 /** 23733 * Set to true if a view has been scrolled. 23734 */ 23735 boolean mViewScrollChanged; 23736 23737 /** 23738 * Set to true if high contrast mode enabled 23739 */ 23740 boolean mHighContrastText; 23741 23742 /** 23743 * Set to true if a pointer event is currently being handled. 23744 */ 23745 boolean mHandlingPointerEvent; 23746 23747 /** 23748 * Global to the view hierarchy used as a temporary for dealing with 23749 * x/y points in the transparent region computations. 23750 */ 23751 final int[] mTransparentLocation = new int[2]; 23752 23753 /** 23754 * Global to the view hierarchy used as a temporary for dealing with 23755 * x/y points in the ViewGroup.invalidateChild implementation. 23756 */ 23757 final int[] mInvalidateChildLocation = new int[2]; 23758 23759 /** 23760 * Global to the view hierarchy used as a temporary for dealing with 23761 * computing absolute on-screen location. 23762 */ 23763 final int[] mTmpLocation = new int[2]; 23764 23765 /** 23766 * Global to the view hierarchy used as a temporary for dealing with 23767 * x/y location when view is transformed. 23768 */ 23769 final float[] mTmpTransformLocation = new float[2]; 23770 23771 /** 23772 * The view tree observer used to dispatch global events like 23773 * layout, pre-draw, touch mode change, etc. 23774 */ 23775 final ViewTreeObserver mTreeObserver; 23776 23777 /** 23778 * A Canvas used by the view hierarchy to perform bitmap caching. 23779 */ 23780 Canvas mCanvas; 23781 23782 /** 23783 * The view root impl. 23784 */ 23785 final ViewRootImpl mViewRootImpl; 23786 23787 /** 23788 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 23789 * handler can be used to pump events in the UI events queue. 23790 */ 23791 final Handler mHandler; 23792 23793 /** 23794 * Temporary for use in computing invalidate rectangles while 23795 * calling up the hierarchy. 23796 */ 23797 final Rect mTmpInvalRect = new Rect(); 23798 23799 /** 23800 * Temporary for use in computing hit areas with transformed views 23801 */ 23802 final RectF mTmpTransformRect = new RectF(); 23803 23804 /** 23805 * Temporary for use in computing hit areas with transformed views 23806 */ 23807 final RectF mTmpTransformRect1 = new RectF(); 23808 23809 /** 23810 * Temporary list of rectanges. 23811 */ 23812 final List<RectF> mTmpRectList = new ArrayList<>(); 23813 23814 /** 23815 * Temporary for use in transforming invalidation rect 23816 */ 23817 final Matrix mTmpMatrix = new Matrix(); 23818 23819 /** 23820 * Temporary for use in transforming invalidation rect 23821 */ 23822 final Transformation mTmpTransformation = new Transformation(); 23823 23824 /** 23825 * Temporary for use in querying outlines from OutlineProviders 23826 */ 23827 final Outline mTmpOutline = new Outline(); 23828 23829 /** 23830 * Temporary list for use in collecting focusable descendents of a view. 23831 */ 23832 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 23833 23834 /** 23835 * The id of the window for accessibility purposes. 23836 */ 23837 int mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 23838 23839 /** 23840 * Flags related to accessibility processing. 23841 * 23842 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 23843 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 23844 */ 23845 int mAccessibilityFetchFlags; 23846 23847 /** 23848 * The drawable for highlighting accessibility focus. 23849 */ 23850 Drawable mAccessibilityFocusDrawable; 23851 23852 /** 23853 * Show where the margins, bounds and layout bounds are for each view. 23854 */ 23855 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 23856 23857 /** 23858 * Point used to compute visible regions. 23859 */ 23860 final Point mPoint = new Point(); 23861 23862 /** 23863 * Used to track which View originated a requestLayout() call, used when 23864 * requestLayout() is called during layout. 23865 */ 23866 View mViewRequestingLayout; 23867 23868 /** 23869 * Used to track views that need (at least) a partial relayout at their current size 23870 * during the next traversal. 23871 */ 23872 List<View> mPartialLayoutViews = new ArrayList<>(); 23873 23874 /** 23875 * Swapped with mPartialLayoutViews during layout to avoid concurrent 23876 * modification. Lazily assigned during ViewRootImpl layout. 23877 */ 23878 List<View> mEmptyPartialLayoutViews; 23879 23880 /** 23881 * Used to track the identity of the current drag operation. 23882 */ 23883 IBinder mDragToken; 23884 23885 /** 23886 * The drag shadow surface for the current drag operation. 23887 */ 23888 public Surface mDragSurface; 23889 23890 23891 /** 23892 * The view that currently has a tooltip displayed. 23893 */ 23894 View mTooltipHost; 23895 23896 /** 23897 * Creates a new set of attachment information with the specified 23898 * events handler and thread. 23899 * 23900 * @param handler the events handler the view must use 23901 */ 23902 AttachInfo(IWindowSession session, IWindow window, Display display, 23903 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 23904 Context context) { 23905 mSession = session; 23906 mWindow = window; 23907 mWindowToken = window.asBinder(); 23908 mDisplay = display; 23909 mViewRootImpl = viewRootImpl; 23910 mHandler = handler; 23911 mRootCallbacks = effectPlayer; 23912 mTreeObserver = new ViewTreeObserver(context); 23913 } 23914 } 23915 23916 /** 23917 * <p>ScrollabilityCache holds various fields used by a View when scrolling 23918 * is supported. This avoids keeping too many unused fields in most 23919 * instances of View.</p> 23920 */ 23921 private static class ScrollabilityCache implements Runnable { 23922 23923 /** 23924 * Scrollbars are not visible 23925 */ 23926 public static final int OFF = 0; 23927 23928 /** 23929 * Scrollbars are visible 23930 */ 23931 public static final int ON = 1; 23932 23933 /** 23934 * Scrollbars are fading away 23935 */ 23936 public static final int FADING = 2; 23937 23938 public boolean fadeScrollBars; 23939 23940 public int fadingEdgeLength; 23941 public int scrollBarDefaultDelayBeforeFade; 23942 public int scrollBarFadeDuration; 23943 23944 public int scrollBarSize; 23945 public ScrollBarDrawable scrollBar; 23946 public float[] interpolatorValues; 23947 public View host; 23948 23949 public final Paint paint; 23950 public final Matrix matrix; 23951 public Shader shader; 23952 23953 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 23954 23955 private static final float[] OPAQUE = { 255 }; 23956 private static final float[] TRANSPARENT = { 0.0f }; 23957 23958 /** 23959 * When fading should start. This time moves into the future every time 23960 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 23961 */ 23962 public long fadeStartTime; 23963 23964 23965 /** 23966 * The current state of the scrollbars: ON, OFF, or FADING 23967 */ 23968 public int state = OFF; 23969 23970 private int mLastColor; 23971 23972 public final Rect mScrollBarBounds = new Rect(); 23973 23974 public static final int NOT_DRAGGING = 0; 23975 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 23976 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 23977 public int mScrollBarDraggingState = NOT_DRAGGING; 23978 23979 public float mScrollBarDraggingPos = 0; 23980 23981 public ScrollabilityCache(ViewConfiguration configuration, View host) { 23982 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 23983 scrollBarSize = configuration.getScaledScrollBarSize(); 23984 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 23985 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 23986 23987 paint = new Paint(); 23988 matrix = new Matrix(); 23989 // use use a height of 1, and then wack the matrix each time we 23990 // actually use it. 23991 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 23992 paint.setShader(shader); 23993 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 23994 23995 this.host = host; 23996 } 23997 23998 public void setFadeColor(int color) { 23999 if (color != mLastColor) { 24000 mLastColor = color; 24001 24002 if (color != 0) { 24003 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 24004 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 24005 paint.setShader(shader); 24006 // Restore the default transfer mode (src_over) 24007 paint.setXfermode(null); 24008 } else { 24009 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 24010 paint.setShader(shader); 24011 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 24012 } 24013 } 24014 } 24015 24016 public void run() { 24017 long now = AnimationUtils.currentAnimationTimeMillis(); 24018 if (now >= fadeStartTime) { 24019 24020 // the animation fades the scrollbars out by changing 24021 // the opacity (alpha) from fully opaque to fully 24022 // transparent 24023 int nextFrame = (int) now; 24024 int framesCount = 0; 24025 24026 Interpolator interpolator = scrollBarInterpolator; 24027 24028 // Start opaque 24029 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 24030 24031 // End transparent 24032 nextFrame += scrollBarFadeDuration; 24033 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 24034 24035 state = FADING; 24036 24037 // Kick off the fade animation 24038 host.invalidate(true); 24039 } 24040 } 24041 } 24042 24043 /** 24044 * Resuable callback for sending 24045 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 24046 */ 24047 private class SendViewScrolledAccessibilityEvent implements Runnable { 24048 public volatile boolean mIsPending; 24049 24050 public void run() { 24051 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 24052 mIsPending = false; 24053 } 24054 } 24055 24056 /** 24057 * <p> 24058 * This class represents a delegate that can be registered in a {@link View} 24059 * to enhance accessibility support via composition rather via inheritance. 24060 * It is specifically targeted to widget developers that extend basic View 24061 * classes i.e. classes in package android.view, that would like their 24062 * applications to be backwards compatible. 24063 * </p> 24064 * <div class="special reference"> 24065 * <h3>Developer Guides</h3> 24066 * <p>For more information about making applications accessible, read the 24067 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 24068 * developer guide.</p> 24069 * </div> 24070 * <p> 24071 * A scenario in which a developer would like to use an accessibility delegate 24072 * is overriding a method introduced in a later API version than the minimal API 24073 * version supported by the application. For example, the method 24074 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 24075 * in API version 4 when the accessibility APIs were first introduced. If a 24076 * developer would like his application to run on API version 4 devices (assuming 24077 * all other APIs used by the application are version 4 or lower) and take advantage 24078 * of this method, instead of overriding the method which would break the application's 24079 * backwards compatibility, he can override the corresponding method in this 24080 * delegate and register the delegate in the target View if the API version of 24081 * the system is high enough, i.e. the API version is the same as or higher than the API 24082 * version that introduced 24083 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 24084 * </p> 24085 * <p> 24086 * Here is an example implementation: 24087 * </p> 24088 * <code><pre><p> 24089 * if (Build.VERSION.SDK_INT >= 14) { 24090 * // If the API version is equal of higher than the version in 24091 * // which onInitializeAccessibilityNodeInfo was introduced we 24092 * // register a delegate with a customized implementation. 24093 * View view = findViewById(R.id.view_id); 24094 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 24095 * public void onInitializeAccessibilityNodeInfo(View host, 24096 * AccessibilityNodeInfo info) { 24097 * // Let the default implementation populate the info. 24098 * super.onInitializeAccessibilityNodeInfo(host, info); 24099 * // Set some other information. 24100 * info.setEnabled(host.isEnabled()); 24101 * } 24102 * }); 24103 * } 24104 * </code></pre></p> 24105 * <p> 24106 * This delegate contains methods that correspond to the accessibility methods 24107 * in View. If a delegate has been specified the implementation in View hands 24108 * off handling to the corresponding method in this delegate. The default 24109 * implementation the delegate methods behaves exactly as the corresponding 24110 * method in View for the case of no accessibility delegate been set. Hence, 24111 * to customize the behavior of a View method, clients can override only the 24112 * corresponding delegate method without altering the behavior of the rest 24113 * accessibility related methods of the host view. 24114 * </p> 24115 * <p> 24116 * <strong>Note:</strong> On platform versions prior to 24117 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 24118 * views in the {@code android.widget.*} package are called <i>before</i> 24119 * host methods. This prevents certain properties such as class name from 24120 * being modified by overriding 24121 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 24122 * as any changes will be overwritten by the host class. 24123 * <p> 24124 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 24125 * methods are called <i>after</i> host methods, which all properties to be 24126 * modified without being overwritten by the host class. 24127 */ 24128 public static class AccessibilityDelegate { 24129 24130 /** 24131 * Sends an accessibility event of the given type. If accessibility is not 24132 * enabled this method has no effect. 24133 * <p> 24134 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 24135 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 24136 * been set. 24137 * </p> 24138 * 24139 * @param host The View hosting the delegate. 24140 * @param eventType The type of the event to send. 24141 * 24142 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 24143 */ 24144 public void sendAccessibilityEvent(View host, int eventType) { 24145 host.sendAccessibilityEventInternal(eventType); 24146 } 24147 24148 /** 24149 * Performs the specified accessibility action on the view. For 24150 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 24151 * <p> 24152 * The default implementation behaves as 24153 * {@link View#performAccessibilityAction(int, Bundle) 24154 * View#performAccessibilityAction(int, Bundle)} for the case of 24155 * no accessibility delegate been set. 24156 * </p> 24157 * 24158 * @param action The action to perform. 24159 * @return Whether the action was performed. 24160 * 24161 * @see View#performAccessibilityAction(int, Bundle) 24162 * View#performAccessibilityAction(int, Bundle) 24163 */ 24164 public boolean performAccessibilityAction(View host, int action, Bundle args) { 24165 return host.performAccessibilityActionInternal(action, args); 24166 } 24167 24168 /** 24169 * Sends an accessibility event. This method behaves exactly as 24170 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 24171 * empty {@link AccessibilityEvent} and does not perform a check whether 24172 * accessibility is enabled. 24173 * <p> 24174 * The default implementation behaves as 24175 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24176 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 24177 * the case of no accessibility delegate been set. 24178 * </p> 24179 * 24180 * @param host The View hosting the delegate. 24181 * @param event The event to send. 24182 * 24183 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24184 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24185 */ 24186 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 24187 host.sendAccessibilityEventUncheckedInternal(event); 24188 } 24189 24190 /** 24191 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 24192 * to its children for adding their text content to the event. 24193 * <p> 24194 * The default implementation behaves as 24195 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24196 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 24197 * the case of no accessibility delegate been set. 24198 * </p> 24199 * 24200 * @param host The View hosting the delegate. 24201 * @param event The event. 24202 * @return True if the event population was completed. 24203 * 24204 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24205 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24206 */ 24207 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 24208 return host.dispatchPopulateAccessibilityEventInternal(event); 24209 } 24210 24211 /** 24212 * Gives a chance to the host View to populate the accessibility event with its 24213 * text content. 24214 * <p> 24215 * The default implementation behaves as 24216 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 24217 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 24218 * the case of no accessibility delegate been set. 24219 * </p> 24220 * 24221 * @param host The View hosting the delegate. 24222 * @param event The accessibility event which to populate. 24223 * 24224 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 24225 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 24226 */ 24227 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 24228 host.onPopulateAccessibilityEventInternal(event); 24229 } 24230 24231 /** 24232 * Initializes an {@link AccessibilityEvent} with information about the 24233 * the host View which is the event source. 24234 * <p> 24235 * The default implementation behaves as 24236 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 24237 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 24238 * the case of no accessibility delegate been set. 24239 * </p> 24240 * 24241 * @param host The View hosting the delegate. 24242 * @param event The event to initialize. 24243 * 24244 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 24245 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 24246 */ 24247 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 24248 host.onInitializeAccessibilityEventInternal(event); 24249 } 24250 24251 /** 24252 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 24253 * <p> 24254 * The default implementation behaves as 24255 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24256 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 24257 * the case of no accessibility delegate been set. 24258 * </p> 24259 * 24260 * @param host The View hosting the delegate. 24261 * @param info The instance to initialize. 24262 * 24263 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24264 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24265 */ 24266 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 24267 host.onInitializeAccessibilityNodeInfoInternal(info); 24268 } 24269 24270 /** 24271 * Called when a child of the host View has requested sending an 24272 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 24273 * to augment the event. 24274 * <p> 24275 * The default implementation behaves as 24276 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24277 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 24278 * the case of no accessibility delegate been set. 24279 * </p> 24280 * 24281 * @param host The View hosting the delegate. 24282 * @param child The child which requests sending the event. 24283 * @param event The event to be sent. 24284 * @return True if the event should be sent 24285 * 24286 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24287 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24288 */ 24289 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 24290 AccessibilityEvent event) { 24291 return host.onRequestSendAccessibilityEventInternal(child, event); 24292 } 24293 24294 /** 24295 * Gets the provider for managing a virtual view hierarchy rooted at this View 24296 * and reported to {@link android.accessibilityservice.AccessibilityService}s 24297 * that explore the window content. 24298 * <p> 24299 * The default implementation behaves as 24300 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 24301 * the case of no accessibility delegate been set. 24302 * </p> 24303 * 24304 * @return The provider. 24305 * 24306 * @see AccessibilityNodeProvider 24307 */ 24308 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 24309 return null; 24310 } 24311 24312 /** 24313 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 24314 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 24315 * This method is responsible for obtaining an accessibility node info from a 24316 * pool of reusable instances and calling 24317 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 24318 * view to initialize the former. 24319 * <p> 24320 * <strong>Note:</strong> The client is responsible for recycling the obtained 24321 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 24322 * creation. 24323 * </p> 24324 * <p> 24325 * The default implementation behaves as 24326 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 24327 * the case of no accessibility delegate been set. 24328 * </p> 24329 * @return A populated {@link AccessibilityNodeInfo}. 24330 * 24331 * @see AccessibilityNodeInfo 24332 * 24333 * @hide 24334 */ 24335 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 24336 return host.createAccessibilityNodeInfoInternal(); 24337 } 24338 } 24339 24340 private class MatchIdPredicate implements Predicate<View> { 24341 public int mId; 24342 24343 @Override 24344 public boolean apply(View view) { 24345 return (view.mID == mId); 24346 } 24347 } 24348 24349 private class MatchLabelForPredicate implements Predicate<View> { 24350 private int mLabeledId; 24351 24352 @Override 24353 public boolean apply(View view) { 24354 return (view.mLabelForId == mLabeledId); 24355 } 24356 } 24357 24358 private class SendViewStateChangedAccessibilityEvent implements Runnable { 24359 private int mChangeTypes = 0; 24360 private boolean mPosted; 24361 private boolean mPostedWithDelay; 24362 private long mLastEventTimeMillis; 24363 24364 @Override 24365 public void run() { 24366 mPosted = false; 24367 mPostedWithDelay = false; 24368 mLastEventTimeMillis = SystemClock.uptimeMillis(); 24369 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 24370 final AccessibilityEvent event = AccessibilityEvent.obtain(); 24371 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 24372 event.setContentChangeTypes(mChangeTypes); 24373 sendAccessibilityEventUnchecked(event); 24374 } 24375 mChangeTypes = 0; 24376 } 24377 24378 public void runOrPost(int changeType) { 24379 mChangeTypes |= changeType; 24380 24381 // If this is a live region or the child of a live region, collect 24382 // all events from this frame and send them on the next frame. 24383 if (inLiveRegion()) { 24384 // If we're already posted with a delay, remove that. 24385 if (mPostedWithDelay) { 24386 removeCallbacks(this); 24387 mPostedWithDelay = false; 24388 } 24389 // Only post if we're not already posted. 24390 if (!mPosted) { 24391 post(this); 24392 mPosted = true; 24393 } 24394 return; 24395 } 24396 24397 if (mPosted) { 24398 return; 24399 } 24400 24401 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 24402 final long minEventIntevalMillis = 24403 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 24404 if (timeSinceLastMillis >= minEventIntevalMillis) { 24405 removeCallbacks(this); 24406 run(); 24407 } else { 24408 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 24409 mPostedWithDelay = true; 24410 } 24411 } 24412 } 24413 24414 private boolean inLiveRegion() { 24415 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24416 return true; 24417 } 24418 24419 ViewParent parent = getParent(); 24420 while (parent instanceof View) { 24421 if (((View) parent).getAccessibilityLiveRegion() 24422 != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24423 return true; 24424 } 24425 parent = parent.getParent(); 24426 } 24427 24428 return false; 24429 } 24430 24431 /** 24432 * Dump all private flags in readable format, useful for documentation and 24433 * sanity checking. 24434 */ 24435 private static void dumpFlags() { 24436 final HashMap<String, String> found = Maps.newHashMap(); 24437 try { 24438 for (Field field : View.class.getDeclaredFields()) { 24439 final int modifiers = field.getModifiers(); 24440 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 24441 if (field.getType().equals(int.class)) { 24442 final int value = field.getInt(null); 24443 dumpFlag(found, field.getName(), value); 24444 } else if (field.getType().equals(int[].class)) { 24445 final int[] values = (int[]) field.get(null); 24446 for (int i = 0; i < values.length; i++) { 24447 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 24448 } 24449 } 24450 } 24451 } 24452 } catch (IllegalAccessException e) { 24453 throw new RuntimeException(e); 24454 } 24455 24456 final ArrayList<String> keys = Lists.newArrayList(); 24457 keys.addAll(found.keySet()); 24458 Collections.sort(keys); 24459 for (String key : keys) { 24460 Log.d(VIEW_LOG_TAG, found.get(key)); 24461 } 24462 } 24463 24464 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 24465 // Sort flags by prefix, then by bits, always keeping unique keys 24466 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 24467 final int prefix = name.indexOf('_'); 24468 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 24469 final String output = bits + " " + name; 24470 found.put(key, output); 24471 } 24472 24473 /** {@hide} */ 24474 public void encode(@NonNull ViewHierarchyEncoder stream) { 24475 stream.beginObject(this); 24476 encodeProperties(stream); 24477 stream.endObject(); 24478 } 24479 24480 /** {@hide} */ 24481 @CallSuper 24482 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 24483 Object resolveId = ViewDebug.resolveId(getContext(), mID); 24484 if (resolveId instanceof String) { 24485 stream.addProperty("id", (String) resolveId); 24486 } else { 24487 stream.addProperty("id", mID); 24488 } 24489 24490 stream.addProperty("misc:transformation.alpha", 24491 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 24492 stream.addProperty("misc:transitionName", getTransitionName()); 24493 24494 // layout 24495 stream.addProperty("layout:left", mLeft); 24496 stream.addProperty("layout:right", mRight); 24497 stream.addProperty("layout:top", mTop); 24498 stream.addProperty("layout:bottom", mBottom); 24499 stream.addProperty("layout:width", getWidth()); 24500 stream.addProperty("layout:height", getHeight()); 24501 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 24502 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 24503 stream.addProperty("layout:hasTransientState", hasTransientState()); 24504 stream.addProperty("layout:baseline", getBaseline()); 24505 24506 // layout params 24507 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 24508 if (layoutParams != null) { 24509 stream.addPropertyKey("layoutParams"); 24510 layoutParams.encode(stream); 24511 } 24512 24513 // scrolling 24514 stream.addProperty("scrolling:scrollX", mScrollX); 24515 stream.addProperty("scrolling:scrollY", mScrollY); 24516 24517 // padding 24518 stream.addProperty("padding:paddingLeft", mPaddingLeft); 24519 stream.addProperty("padding:paddingRight", mPaddingRight); 24520 stream.addProperty("padding:paddingTop", mPaddingTop); 24521 stream.addProperty("padding:paddingBottom", mPaddingBottom); 24522 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 24523 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 24524 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 24525 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 24526 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 24527 24528 // measurement 24529 stream.addProperty("measurement:minHeight", mMinHeight); 24530 stream.addProperty("measurement:minWidth", mMinWidth); 24531 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 24532 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 24533 24534 // drawing 24535 stream.addProperty("drawing:elevation", getElevation()); 24536 stream.addProperty("drawing:translationX", getTranslationX()); 24537 stream.addProperty("drawing:translationY", getTranslationY()); 24538 stream.addProperty("drawing:translationZ", getTranslationZ()); 24539 stream.addProperty("drawing:rotation", getRotation()); 24540 stream.addProperty("drawing:rotationX", getRotationX()); 24541 stream.addProperty("drawing:rotationY", getRotationY()); 24542 stream.addProperty("drawing:scaleX", getScaleX()); 24543 stream.addProperty("drawing:scaleY", getScaleY()); 24544 stream.addProperty("drawing:pivotX", getPivotX()); 24545 stream.addProperty("drawing:pivotY", getPivotY()); 24546 stream.addProperty("drawing:opaque", isOpaque()); 24547 stream.addProperty("drawing:alpha", getAlpha()); 24548 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 24549 stream.addProperty("drawing:shadow", hasShadow()); 24550 stream.addProperty("drawing:solidColor", getSolidColor()); 24551 stream.addProperty("drawing:layerType", mLayerType); 24552 stream.addProperty("drawing:willNotDraw", willNotDraw()); 24553 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 24554 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 24555 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 24556 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 24557 24558 // focus 24559 stream.addProperty("focus:hasFocus", hasFocus()); 24560 stream.addProperty("focus:isFocused", isFocused()); 24561 stream.addProperty("focus:isFocusable", isFocusable()); 24562 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 24563 24564 stream.addProperty("misc:clickable", isClickable()); 24565 stream.addProperty("misc:pressed", isPressed()); 24566 stream.addProperty("misc:selected", isSelected()); 24567 stream.addProperty("misc:touchMode", isInTouchMode()); 24568 stream.addProperty("misc:hovered", isHovered()); 24569 stream.addProperty("misc:activated", isActivated()); 24570 24571 stream.addProperty("misc:visibility", getVisibility()); 24572 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 24573 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 24574 24575 stream.addProperty("misc:enabled", isEnabled()); 24576 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 24577 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 24578 24579 // theme attributes 24580 Resources.Theme theme = getContext().getTheme(); 24581 if (theme != null) { 24582 stream.addPropertyKey("theme"); 24583 theme.encode(stream); 24584 } 24585 24586 // view attribute information 24587 int n = mAttributes != null ? mAttributes.length : 0; 24588 stream.addProperty("meta:__attrCount__", n/2); 24589 for (int i = 0; i < n; i += 2) { 24590 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 24591 } 24592 24593 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 24594 24595 // text 24596 stream.addProperty("text:textDirection", getTextDirection()); 24597 stream.addProperty("text:textAlignment", getTextAlignment()); 24598 24599 // accessibility 24600 CharSequence contentDescription = getContentDescription(); 24601 stream.addProperty("accessibility:contentDescription", 24602 contentDescription == null ? "" : contentDescription.toString()); 24603 stream.addProperty("accessibility:labelFor", getLabelFor()); 24604 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 24605 } 24606 24607 /** 24608 * Determine if this view is rendered on a round wearable device and is the main view 24609 * on the screen. 24610 */ 24611 private boolean shouldDrawRoundScrollbar() { 24612 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 24613 return false; 24614 } 24615 24616 final View rootView = getRootView(); 24617 final WindowInsets insets = getRootWindowInsets(); 24618 24619 int height = getHeight(); 24620 int width = getWidth(); 24621 int displayHeight = rootView.getHeight(); 24622 int displayWidth = rootView.getWidth(); 24623 24624 if (height != displayHeight || width != displayWidth) { 24625 return false; 24626 } 24627 24628 getLocationOnScreen(mAttachInfo.mTmpLocation); 24629 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 24630 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 24631 } 24632 24633 /** 24634 * Sets the tooltip text which will be displayed in a small popup next to the view. 24635 * <p> 24636 * The tooltip will be displayed: 24637 * <li>On long click, unless is not handled otherwise (by OnLongClickListener or a context 24638 * menu). </li> 24639 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 24640 * 24641 * @param tooltipText the tooltip text, or null if no tooltip is required 24642 */ 24643 public final void setTooltipText(@Nullable CharSequence tooltipText) { 24644 if (TextUtils.isEmpty(tooltipText)) { 24645 setFlags(0, TOOLTIP); 24646 hideTooltip(); 24647 mTooltipInfo = null; 24648 } else { 24649 setFlags(TOOLTIP, TOOLTIP); 24650 if (mTooltipInfo == null) { 24651 mTooltipInfo = new TooltipInfo(); 24652 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 24653 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 24654 } 24655 mTooltipInfo.mTooltipText = tooltipText; 24656 if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) { 24657 mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText); 24658 } 24659 } 24660 } 24661 24662 /** 24663 * To be removed once the support library has stopped using it. 24664 * 24665 * @deprecated use {@link #setTooltipText} instead 24666 */ 24667 @Deprecated 24668 public final void setTooltip(@Nullable CharSequence tooltipText) { 24669 setTooltipText(tooltipText); 24670 } 24671 24672 /** 24673 * Returns the view's tooltip text. 24674 * 24675 * @return the tooltip text 24676 */ 24677 @Nullable 24678 public final CharSequence getTooltipText() { 24679 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 24680 } 24681 24682 /** 24683 * To be removed once the support library has stopped using it. 24684 * 24685 * @deprecated use {@link #getTooltipText} instead 24686 */ 24687 @Deprecated 24688 @Nullable 24689 public final CharSequence getTooltip() { 24690 return getTooltipText(); 24691 } 24692 24693 private boolean showTooltip(int x, int y, boolean fromLongClick) { 24694 if (mAttachInfo == null) { 24695 return false; 24696 } 24697 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 24698 return false; 24699 } 24700 final CharSequence tooltipText = getTooltipText(); 24701 if (TextUtils.isEmpty(tooltipText)) { 24702 return false; 24703 } 24704 hideTooltip(); 24705 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 24706 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 24707 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 24708 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, tooltipText); 24709 mAttachInfo.mTooltipHost = this; 24710 return true; 24711 } 24712 24713 void hideTooltip() { 24714 if (mTooltipInfo == null) { 24715 return; 24716 } 24717 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24718 if (mTooltipInfo.mTooltipPopup == null) { 24719 return; 24720 } 24721 mTooltipInfo.mTooltipPopup.hide(); 24722 mTooltipInfo.mTooltipPopup = null; 24723 mTooltipInfo.mTooltipFromLongClick = false; 24724 if (mAttachInfo != null) { 24725 mAttachInfo.mTooltipHost = null; 24726 } 24727 } 24728 24729 private boolean showLongClickTooltip(int x, int y) { 24730 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24731 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24732 return showTooltip(x, y, true); 24733 } 24734 24735 private void showHoverTooltip() { 24736 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 24737 } 24738 24739 boolean dispatchTooltipHoverEvent(MotionEvent event) { 24740 if (mTooltipInfo == null) { 24741 return false; 24742 } 24743 switch(event.getAction()) { 24744 case MotionEvent.ACTION_HOVER_MOVE: 24745 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 24746 break; 24747 } 24748 if (!mTooltipInfo.mTooltipFromLongClick) { 24749 if (mTooltipInfo.mTooltipPopup == null) { 24750 // Schedule showing the tooltip after a timeout. 24751 mTooltipInfo.mAnchorX = (int) event.getX(); 24752 mTooltipInfo.mAnchorY = (int) event.getY(); 24753 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24754 postDelayed(mTooltipInfo.mShowTooltipRunnable, 24755 ViewConfiguration.getHoverTooltipShowTimeout()); 24756 } 24757 24758 // Hide hover-triggered tooltip after a period of inactivity. 24759 // Match the timeout used by NativeInputManager to hide the mouse pointer 24760 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 24761 final int timeout; 24762 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 24763 == SYSTEM_UI_FLAG_LOW_PROFILE) { 24764 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 24765 } else { 24766 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 24767 } 24768 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24769 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 24770 } 24771 return true; 24772 24773 case MotionEvent.ACTION_HOVER_EXIT: 24774 if (!mTooltipInfo.mTooltipFromLongClick) { 24775 hideTooltip(); 24776 } 24777 break; 24778 } 24779 return false; 24780 } 24781 24782 void handleTooltipKey(KeyEvent event) { 24783 switch (event.getAction()) { 24784 case KeyEvent.ACTION_DOWN: 24785 if (event.getRepeatCount() == 0) { 24786 hideTooltip(); 24787 } 24788 break; 24789 24790 case KeyEvent.ACTION_UP: 24791 handleTooltipUp(); 24792 break; 24793 } 24794 } 24795 24796 private void handleTooltipUp() { 24797 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 24798 return; 24799 } 24800 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24801 postDelayed(mTooltipInfo.mHideTooltipRunnable, 24802 ViewConfiguration.getLongPressTooltipHideTimeout()); 24803 } 24804 24805 /** 24806 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 24807 * is not showing. 24808 * @hide 24809 */ 24810 @TestApi 24811 public View getTooltipView() { 24812 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 24813 return null; 24814 } 24815 return mTooltipInfo.mTooltipPopup.getContentView(); 24816 } 24817} 24818