View.java revision c56c7462ef349efc11079c479424c0c60b473a47
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 if (mOverlay != null) { 16645 mOverlay.getOverlayView().destroyHardwareResources(); 16646 } 16647 if (mGhostView != null) { 16648 mGhostView.destroyHardwareResources(); 16649 } 16650 } 16651 16652 /** 16653 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 16654 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 16655 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 16656 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 16657 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 16658 * null.</p> 16659 * 16660 * <p>Enabling the drawing cache is similar to 16661 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 16662 * acceleration is turned off. When hardware acceleration is turned on, enabling the 16663 * drawing cache has no effect on rendering because the system uses a different mechanism 16664 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 16665 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 16666 * for information on how to enable software and hardware layers.</p> 16667 * 16668 * <p>This API can be used to manually generate 16669 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 16670 * {@link #getDrawingCache()}.</p> 16671 * 16672 * @param enabled true to enable the drawing cache, false otherwise 16673 * 16674 * @see #isDrawingCacheEnabled() 16675 * @see #getDrawingCache() 16676 * @see #buildDrawingCache() 16677 * @see #setLayerType(int, android.graphics.Paint) 16678 */ 16679 public void setDrawingCacheEnabled(boolean enabled) { 16680 mCachingFailed = false; 16681 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 16682 } 16683 16684 /** 16685 * <p>Indicates whether the drawing cache is enabled for this view.</p> 16686 * 16687 * @return true if the drawing cache is enabled 16688 * 16689 * @see #setDrawingCacheEnabled(boolean) 16690 * @see #getDrawingCache() 16691 */ 16692 @ViewDebug.ExportedProperty(category = "drawing") 16693 public boolean isDrawingCacheEnabled() { 16694 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 16695 } 16696 16697 /** 16698 * Debugging utility which recursively outputs the dirty state of a view and its 16699 * descendants. 16700 * 16701 * @hide 16702 */ 16703 @SuppressWarnings({"UnusedDeclaration"}) 16704 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 16705 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 16706 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 16707 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 16708 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 16709 if (clear) { 16710 mPrivateFlags &= clearMask; 16711 } 16712 if (this instanceof ViewGroup) { 16713 ViewGroup parent = (ViewGroup) this; 16714 final int count = parent.getChildCount(); 16715 for (int i = 0; i < count; i++) { 16716 final View child = parent.getChildAt(i); 16717 child.outputDirtyFlags(indent + " ", clear, clearMask); 16718 } 16719 } 16720 } 16721 16722 /** 16723 * This method is used by ViewGroup to cause its children to restore or recreate their 16724 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 16725 * to recreate its own display list, which would happen if it went through the normal 16726 * draw/dispatchDraw mechanisms. 16727 * 16728 * @hide 16729 */ 16730 protected void dispatchGetDisplayList() {} 16731 16732 /** 16733 * A view that is not attached or hardware accelerated cannot create a display list. 16734 * This method checks these conditions and returns the appropriate result. 16735 * 16736 * @return true if view has the ability to create a display list, false otherwise. 16737 * 16738 * @hide 16739 */ 16740 public boolean canHaveDisplayList() { 16741 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 16742 } 16743 16744 /** 16745 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 16746 * @hide 16747 */ 16748 @NonNull 16749 public RenderNode updateDisplayListIfDirty() { 16750 final RenderNode renderNode = mRenderNode; 16751 if (!canHaveDisplayList()) { 16752 // can't populate RenderNode, don't try 16753 return renderNode; 16754 } 16755 16756 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 16757 || !renderNode.isValid() 16758 || (mRecreateDisplayList)) { 16759 // Don't need to recreate the display list, just need to tell our 16760 // children to restore/recreate theirs 16761 if (renderNode.isValid() 16762 && !mRecreateDisplayList) { 16763 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16764 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16765 dispatchGetDisplayList(); 16766 16767 return renderNode; // no work needed 16768 } 16769 16770 // If we got here, we're recreating it. Mark it as such to ensure that 16771 // we copy in child display lists into ours in drawChild() 16772 mRecreateDisplayList = true; 16773 16774 int width = mRight - mLeft; 16775 int height = mBottom - mTop; 16776 int layerType = getLayerType(); 16777 16778 final DisplayListCanvas canvas = renderNode.start(width, height); 16779 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 16780 16781 try { 16782 if (layerType == LAYER_TYPE_SOFTWARE) { 16783 buildDrawingCache(true); 16784 Bitmap cache = getDrawingCache(true); 16785 if (cache != null) { 16786 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 16787 } 16788 } else { 16789 computeScroll(); 16790 16791 canvas.translate(-mScrollX, -mScrollY); 16792 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16793 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16794 16795 // Fast path for layouts with no backgrounds 16796 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16797 dispatchDraw(canvas); 16798 if (mOverlay != null && !mOverlay.isEmpty()) { 16799 mOverlay.getOverlayView().draw(canvas); 16800 } 16801 if (debugDraw()) { 16802 debugDrawFocus(canvas); 16803 } 16804 } else { 16805 draw(canvas); 16806 } 16807 } 16808 } finally { 16809 renderNode.end(canvas); 16810 setDisplayListProperties(renderNode); 16811 } 16812 } else { 16813 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16814 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16815 } 16816 return renderNode; 16817 } 16818 16819 private void resetDisplayList() { 16820 mRenderNode.discardDisplayList(); 16821 16822 if (mBackgroundRenderNode != null) { 16823 mBackgroundRenderNode.discardDisplayList(); 16824 } 16825 } 16826 16827 /** 16828 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 16829 * 16830 * @return A non-scaled bitmap representing this view or null if cache is disabled. 16831 * 16832 * @see #getDrawingCache(boolean) 16833 */ 16834 public Bitmap getDrawingCache() { 16835 return getDrawingCache(false); 16836 } 16837 16838 /** 16839 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 16840 * is null when caching is disabled. If caching is enabled and the cache is not ready, 16841 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 16842 * draw from the cache when the cache is enabled. To benefit from the cache, you must 16843 * request the drawing cache by calling this method and draw it on screen if the 16844 * returned bitmap is not null.</p> 16845 * 16846 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16847 * this method will create a bitmap of the same size as this view. Because this bitmap 16848 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16849 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16850 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16851 * size than the view. This implies that your application must be able to handle this 16852 * size.</p> 16853 * 16854 * @param autoScale Indicates whether the generated bitmap should be scaled based on 16855 * the current density of the screen when the application is in compatibility 16856 * mode. 16857 * 16858 * @return A bitmap representing this view or null if cache is disabled. 16859 * 16860 * @see #setDrawingCacheEnabled(boolean) 16861 * @see #isDrawingCacheEnabled() 16862 * @see #buildDrawingCache(boolean) 16863 * @see #destroyDrawingCache() 16864 */ 16865 public Bitmap getDrawingCache(boolean autoScale) { 16866 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 16867 return null; 16868 } 16869 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 16870 buildDrawingCache(autoScale); 16871 } 16872 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 16873 } 16874 16875 /** 16876 * <p>Frees the resources used by the drawing cache. If you call 16877 * {@link #buildDrawingCache()} manually without calling 16878 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16879 * should cleanup the cache with this method afterwards.</p> 16880 * 16881 * @see #setDrawingCacheEnabled(boolean) 16882 * @see #buildDrawingCache() 16883 * @see #getDrawingCache() 16884 */ 16885 public void destroyDrawingCache() { 16886 if (mDrawingCache != null) { 16887 mDrawingCache.recycle(); 16888 mDrawingCache = null; 16889 } 16890 if (mUnscaledDrawingCache != null) { 16891 mUnscaledDrawingCache.recycle(); 16892 mUnscaledDrawingCache = null; 16893 } 16894 } 16895 16896 /** 16897 * Setting a solid background color for the drawing cache's bitmaps will improve 16898 * performance and memory usage. Note, though that this should only be used if this 16899 * view will always be drawn on top of a solid color. 16900 * 16901 * @param color The background color to use for the drawing cache's bitmap 16902 * 16903 * @see #setDrawingCacheEnabled(boolean) 16904 * @see #buildDrawingCache() 16905 * @see #getDrawingCache() 16906 */ 16907 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 16908 if (color != mDrawingCacheBackgroundColor) { 16909 mDrawingCacheBackgroundColor = color; 16910 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16911 } 16912 } 16913 16914 /** 16915 * @see #setDrawingCacheBackgroundColor(int) 16916 * 16917 * @return The background color to used for the drawing cache's bitmap 16918 */ 16919 @ColorInt 16920 public int getDrawingCacheBackgroundColor() { 16921 return mDrawingCacheBackgroundColor; 16922 } 16923 16924 /** 16925 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 16926 * 16927 * @see #buildDrawingCache(boolean) 16928 */ 16929 public void buildDrawingCache() { 16930 buildDrawingCache(false); 16931 } 16932 16933 /** 16934 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 16935 * 16936 * <p>If you call {@link #buildDrawingCache()} manually without calling 16937 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16938 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 16939 * 16940 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16941 * this method will create a bitmap of the same size as this view. Because this bitmap 16942 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16943 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16944 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16945 * size than the view. This implies that your application must be able to handle this 16946 * size.</p> 16947 * 16948 * <p>You should avoid calling this method when hardware acceleration is enabled. If 16949 * you do not need the drawing cache bitmap, calling this method will increase memory 16950 * usage and cause the view to be rendered in software once, thus negatively impacting 16951 * performance.</p> 16952 * 16953 * @see #getDrawingCache() 16954 * @see #destroyDrawingCache() 16955 */ 16956 public void buildDrawingCache(boolean autoScale) { 16957 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 16958 mDrawingCache == null : mUnscaledDrawingCache == null)) { 16959 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 16960 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 16961 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 16962 } 16963 try { 16964 buildDrawingCacheImpl(autoScale); 16965 } finally { 16966 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 16967 } 16968 } 16969 } 16970 16971 /** 16972 * private, internal implementation of buildDrawingCache, used to enable tracing 16973 */ 16974 private void buildDrawingCacheImpl(boolean autoScale) { 16975 mCachingFailed = false; 16976 16977 int width = mRight - mLeft; 16978 int height = mBottom - mTop; 16979 16980 final AttachInfo attachInfo = mAttachInfo; 16981 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 16982 16983 if (autoScale && scalingRequired) { 16984 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 16985 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 16986 } 16987 16988 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 16989 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 16990 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 16991 16992 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 16993 final long drawingCacheSize = 16994 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 16995 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 16996 if (width > 0 && height > 0) { 16997 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 16998 + " too large to fit into a software layer (or drawing cache), needs " 16999 + projectedBitmapSize + " bytes, only " 17000 + drawingCacheSize + " available"); 17001 } 17002 destroyDrawingCache(); 17003 mCachingFailed = true; 17004 return; 17005 } 17006 17007 boolean clear = true; 17008 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 17009 17010 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 17011 Bitmap.Config quality; 17012 if (!opaque) { 17013 // Never pick ARGB_4444 because it looks awful 17014 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 17015 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 17016 case DRAWING_CACHE_QUALITY_AUTO: 17017 case DRAWING_CACHE_QUALITY_LOW: 17018 case DRAWING_CACHE_QUALITY_HIGH: 17019 default: 17020 quality = Bitmap.Config.ARGB_8888; 17021 break; 17022 } 17023 } else { 17024 // Optimization for translucent windows 17025 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 17026 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 17027 } 17028 17029 // Try to cleanup memory 17030 if (bitmap != null) bitmap.recycle(); 17031 17032 try { 17033 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17034 width, height, quality); 17035 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 17036 if (autoScale) { 17037 mDrawingCache = bitmap; 17038 } else { 17039 mUnscaledDrawingCache = bitmap; 17040 } 17041 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 17042 } catch (OutOfMemoryError e) { 17043 // If there is not enough memory to create the bitmap cache, just 17044 // ignore the issue as bitmap caches are not required to draw the 17045 // view hierarchy 17046 if (autoScale) { 17047 mDrawingCache = null; 17048 } else { 17049 mUnscaledDrawingCache = null; 17050 } 17051 mCachingFailed = true; 17052 return; 17053 } 17054 17055 clear = drawingCacheBackgroundColor != 0; 17056 } 17057 17058 Canvas canvas; 17059 if (attachInfo != null) { 17060 canvas = attachInfo.mCanvas; 17061 if (canvas == null) { 17062 canvas = new Canvas(); 17063 } 17064 canvas.setBitmap(bitmap); 17065 // Temporarily clobber the cached Canvas in case one of our children 17066 // is also using a drawing cache. Without this, the children would 17067 // steal the canvas by attaching their own bitmap to it and bad, bad 17068 // thing would happen (invisible views, corrupted drawings, etc.) 17069 attachInfo.mCanvas = null; 17070 } else { 17071 // This case should hopefully never or seldom happen 17072 canvas = new Canvas(bitmap); 17073 } 17074 17075 if (clear) { 17076 bitmap.eraseColor(drawingCacheBackgroundColor); 17077 } 17078 17079 computeScroll(); 17080 final int restoreCount = canvas.save(); 17081 17082 if (autoScale && scalingRequired) { 17083 final float scale = attachInfo.mApplicationScale; 17084 canvas.scale(scale, scale); 17085 } 17086 17087 canvas.translate(-mScrollX, -mScrollY); 17088 17089 mPrivateFlags |= PFLAG_DRAWN; 17090 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 17091 mLayerType != LAYER_TYPE_NONE) { 17092 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 17093 } 17094 17095 // Fast path for layouts with no backgrounds 17096 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17097 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17098 dispatchDraw(canvas); 17099 if (mOverlay != null && !mOverlay.isEmpty()) { 17100 mOverlay.getOverlayView().draw(canvas); 17101 } 17102 } else { 17103 draw(canvas); 17104 } 17105 17106 canvas.restoreToCount(restoreCount); 17107 canvas.setBitmap(null); 17108 17109 if (attachInfo != null) { 17110 // Restore the cached Canvas for our siblings 17111 attachInfo.mCanvas = canvas; 17112 } 17113 } 17114 17115 /** 17116 * Create a snapshot of the view into a bitmap. We should probably make 17117 * some form of this public, but should think about the API. 17118 * 17119 * @hide 17120 */ 17121 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 17122 int width = mRight - mLeft; 17123 int height = mBottom - mTop; 17124 17125 final AttachInfo attachInfo = mAttachInfo; 17126 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 17127 width = (int) ((width * scale) + 0.5f); 17128 height = (int) ((height * scale) + 0.5f); 17129 17130 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17131 width > 0 ? width : 1, height > 0 ? height : 1, quality); 17132 if (bitmap == null) { 17133 throw new OutOfMemoryError(); 17134 } 17135 17136 Resources resources = getResources(); 17137 if (resources != null) { 17138 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 17139 } 17140 17141 Canvas canvas; 17142 if (attachInfo != null) { 17143 canvas = attachInfo.mCanvas; 17144 if (canvas == null) { 17145 canvas = new Canvas(); 17146 } 17147 canvas.setBitmap(bitmap); 17148 // Temporarily clobber the cached Canvas in case one of our children 17149 // is also using a drawing cache. Without this, the children would 17150 // steal the canvas by attaching their own bitmap to it and bad, bad 17151 // things would happen (invisible views, corrupted drawings, etc.) 17152 attachInfo.mCanvas = null; 17153 } else { 17154 // This case should hopefully never or seldom happen 17155 canvas = new Canvas(bitmap); 17156 } 17157 17158 if ((backgroundColor & 0xff000000) != 0) { 17159 bitmap.eraseColor(backgroundColor); 17160 } 17161 17162 computeScroll(); 17163 final int restoreCount = canvas.save(); 17164 canvas.scale(scale, scale); 17165 canvas.translate(-mScrollX, -mScrollY); 17166 17167 // Temporarily remove the dirty mask 17168 int flags = mPrivateFlags; 17169 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17170 17171 // Fast path for layouts with no backgrounds 17172 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17173 dispatchDraw(canvas); 17174 if (mOverlay != null && !mOverlay.isEmpty()) { 17175 mOverlay.getOverlayView().draw(canvas); 17176 } 17177 } else { 17178 draw(canvas); 17179 } 17180 17181 mPrivateFlags = flags; 17182 17183 canvas.restoreToCount(restoreCount); 17184 canvas.setBitmap(null); 17185 17186 if (attachInfo != null) { 17187 // Restore the cached Canvas for our siblings 17188 attachInfo.mCanvas = canvas; 17189 } 17190 17191 return bitmap; 17192 } 17193 17194 /** 17195 * Indicates whether this View is currently in edit mode. A View is usually 17196 * in edit mode when displayed within a developer tool. For instance, if 17197 * this View is being drawn by a visual user interface builder, this method 17198 * should return true. 17199 * 17200 * Subclasses should check the return value of this method to provide 17201 * different behaviors if their normal behavior might interfere with the 17202 * host environment. For instance: the class spawns a thread in its 17203 * constructor, the drawing code relies on device-specific features, etc. 17204 * 17205 * This method is usually checked in the drawing code of custom widgets. 17206 * 17207 * @return True if this View is in edit mode, false otherwise. 17208 */ 17209 public boolean isInEditMode() { 17210 return false; 17211 } 17212 17213 /** 17214 * If the View draws content inside its padding and enables fading edges, 17215 * it needs to support padding offsets. Padding offsets are added to the 17216 * fading edges to extend the length of the fade so that it covers pixels 17217 * drawn inside the padding. 17218 * 17219 * Subclasses of this class should override this method if they need 17220 * to draw content inside the padding. 17221 * 17222 * @return True if padding offset must be applied, false otherwise. 17223 * 17224 * @see #getLeftPaddingOffset() 17225 * @see #getRightPaddingOffset() 17226 * @see #getTopPaddingOffset() 17227 * @see #getBottomPaddingOffset() 17228 * 17229 * @since CURRENT 17230 */ 17231 protected boolean isPaddingOffsetRequired() { 17232 return false; 17233 } 17234 17235 /** 17236 * Amount by which to extend the left fading region. Called only when 17237 * {@link #isPaddingOffsetRequired()} returns true. 17238 * 17239 * @return The left padding offset in pixels. 17240 * 17241 * @see #isPaddingOffsetRequired() 17242 * 17243 * @since CURRENT 17244 */ 17245 protected int getLeftPaddingOffset() { 17246 return 0; 17247 } 17248 17249 /** 17250 * Amount by which to extend the right fading region. Called only when 17251 * {@link #isPaddingOffsetRequired()} returns true. 17252 * 17253 * @return The right padding offset in pixels. 17254 * 17255 * @see #isPaddingOffsetRequired() 17256 * 17257 * @since CURRENT 17258 */ 17259 protected int getRightPaddingOffset() { 17260 return 0; 17261 } 17262 17263 /** 17264 * Amount by which to extend the top fading region. Called only when 17265 * {@link #isPaddingOffsetRequired()} returns true. 17266 * 17267 * @return The top padding offset in pixels. 17268 * 17269 * @see #isPaddingOffsetRequired() 17270 * 17271 * @since CURRENT 17272 */ 17273 protected int getTopPaddingOffset() { 17274 return 0; 17275 } 17276 17277 /** 17278 * Amount by which to extend the bottom fading region. Called only when 17279 * {@link #isPaddingOffsetRequired()} returns true. 17280 * 17281 * @return The bottom padding offset in pixels. 17282 * 17283 * @see #isPaddingOffsetRequired() 17284 * 17285 * @since CURRENT 17286 */ 17287 protected int getBottomPaddingOffset() { 17288 return 0; 17289 } 17290 17291 /** 17292 * @hide 17293 * @param offsetRequired 17294 */ 17295 protected int getFadeTop(boolean offsetRequired) { 17296 int top = mPaddingTop; 17297 if (offsetRequired) top += getTopPaddingOffset(); 17298 return top; 17299 } 17300 17301 /** 17302 * @hide 17303 * @param offsetRequired 17304 */ 17305 protected int getFadeHeight(boolean offsetRequired) { 17306 int padding = mPaddingTop; 17307 if (offsetRequired) padding += getTopPaddingOffset(); 17308 return mBottom - mTop - mPaddingBottom - padding; 17309 } 17310 17311 /** 17312 * <p>Indicates whether this view is attached to a hardware accelerated 17313 * window or not.</p> 17314 * 17315 * <p>Even if this method returns true, it does not mean that every call 17316 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 17317 * accelerated {@link android.graphics.Canvas}. For instance, if this view 17318 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 17319 * window is hardware accelerated, 17320 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 17321 * return false, and this method will return true.</p> 17322 * 17323 * @return True if the view is attached to a window and the window is 17324 * hardware accelerated; false in any other case. 17325 */ 17326 @ViewDebug.ExportedProperty(category = "drawing") 17327 public boolean isHardwareAccelerated() { 17328 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 17329 } 17330 17331 /** 17332 * Sets a rectangular area on this view to which the view will be clipped 17333 * when it is drawn. Setting the value to null will remove the clip bounds 17334 * and the view will draw normally, using its full bounds. 17335 * 17336 * @param clipBounds The rectangular area, in the local coordinates of 17337 * this view, to which future drawing operations will be clipped. 17338 */ 17339 public void setClipBounds(Rect clipBounds) { 17340 if (clipBounds == mClipBounds 17341 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 17342 return; 17343 } 17344 if (clipBounds != null) { 17345 if (mClipBounds == null) { 17346 mClipBounds = new Rect(clipBounds); 17347 } else { 17348 mClipBounds.set(clipBounds); 17349 } 17350 } else { 17351 mClipBounds = null; 17352 } 17353 mRenderNode.setClipBounds(mClipBounds); 17354 invalidateViewProperty(false, false); 17355 } 17356 17357 /** 17358 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 17359 * 17360 * @return A copy of the current clip bounds if clip bounds are set, 17361 * otherwise null. 17362 */ 17363 public Rect getClipBounds() { 17364 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 17365 } 17366 17367 17368 /** 17369 * Populates an output rectangle with the clip bounds of the view, 17370 * returning {@code true} if successful or {@code false} if the view's 17371 * clip bounds are {@code null}. 17372 * 17373 * @param outRect rectangle in which to place the clip bounds of the view 17374 * @return {@code true} if successful or {@code false} if the view's 17375 * clip bounds are {@code null} 17376 */ 17377 public boolean getClipBounds(Rect outRect) { 17378 if (mClipBounds != null) { 17379 outRect.set(mClipBounds); 17380 return true; 17381 } 17382 return false; 17383 } 17384 17385 /** 17386 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 17387 * case of an active Animation being run on the view. 17388 */ 17389 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 17390 Animation a, boolean scalingRequired) { 17391 Transformation invalidationTransform; 17392 final int flags = parent.mGroupFlags; 17393 final boolean initialized = a.isInitialized(); 17394 if (!initialized) { 17395 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 17396 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 17397 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 17398 onAnimationStart(); 17399 } 17400 17401 final Transformation t = parent.getChildTransformation(); 17402 boolean more = a.getTransformation(drawingTime, t, 1f); 17403 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 17404 if (parent.mInvalidationTransformation == null) { 17405 parent.mInvalidationTransformation = new Transformation(); 17406 } 17407 invalidationTransform = parent.mInvalidationTransformation; 17408 a.getTransformation(drawingTime, invalidationTransform, 1f); 17409 } else { 17410 invalidationTransform = t; 17411 } 17412 17413 if (more) { 17414 if (!a.willChangeBounds()) { 17415 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 17416 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 17417 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 17418 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 17419 // The child need to draw an animation, potentially offscreen, so 17420 // make sure we do not cancel invalidate requests 17421 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17422 parent.invalidate(mLeft, mTop, mRight, mBottom); 17423 } 17424 } else { 17425 if (parent.mInvalidateRegion == null) { 17426 parent.mInvalidateRegion = new RectF(); 17427 } 17428 final RectF region = parent.mInvalidateRegion; 17429 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 17430 invalidationTransform); 17431 17432 // The child need to draw an animation, potentially offscreen, so 17433 // make sure we do not cancel invalidate requests 17434 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17435 17436 final int left = mLeft + (int) region.left; 17437 final int top = mTop + (int) region.top; 17438 parent.invalidate(left, top, left + (int) (region.width() + .5f), 17439 top + (int) (region.height() + .5f)); 17440 } 17441 } 17442 return more; 17443 } 17444 17445 /** 17446 * This method is called by getDisplayList() when a display list is recorded for a View. 17447 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 17448 */ 17449 void setDisplayListProperties(RenderNode renderNode) { 17450 if (renderNode != null) { 17451 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 17452 renderNode.setClipToBounds(mParent instanceof ViewGroup 17453 && ((ViewGroup) mParent).getClipChildren()); 17454 17455 float alpha = 1; 17456 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 17457 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17458 ViewGroup parentVG = (ViewGroup) mParent; 17459 final Transformation t = parentVG.getChildTransformation(); 17460 if (parentVG.getChildStaticTransformation(this, t)) { 17461 final int transformType = t.getTransformationType(); 17462 if (transformType != Transformation.TYPE_IDENTITY) { 17463 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 17464 alpha = t.getAlpha(); 17465 } 17466 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 17467 renderNode.setStaticMatrix(t.getMatrix()); 17468 } 17469 } 17470 } 17471 } 17472 if (mTransformationInfo != null) { 17473 alpha *= getFinalAlpha(); 17474 if (alpha < 1) { 17475 final int multipliedAlpha = (int) (255 * alpha); 17476 if (onSetAlpha(multipliedAlpha)) { 17477 alpha = 1; 17478 } 17479 } 17480 renderNode.setAlpha(alpha); 17481 } else if (alpha < 1) { 17482 renderNode.setAlpha(alpha); 17483 } 17484 } 17485 } 17486 17487 /** 17488 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 17489 * 17490 * This is where the View specializes rendering behavior based on layer type, 17491 * and hardware acceleration. 17492 */ 17493 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 17494 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 17495 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 17496 * 17497 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 17498 * HW accelerated, it can't handle drawing RenderNodes. 17499 */ 17500 boolean drawingWithRenderNode = mAttachInfo != null 17501 && mAttachInfo.mHardwareAccelerated 17502 && hardwareAcceleratedCanvas; 17503 17504 boolean more = false; 17505 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 17506 final int parentFlags = parent.mGroupFlags; 17507 17508 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 17509 parent.getChildTransformation().clear(); 17510 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17511 } 17512 17513 Transformation transformToApply = null; 17514 boolean concatMatrix = false; 17515 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 17516 final Animation a = getAnimation(); 17517 if (a != null) { 17518 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 17519 concatMatrix = a.willChangeTransformationMatrix(); 17520 if (concatMatrix) { 17521 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17522 } 17523 transformToApply = parent.getChildTransformation(); 17524 } else { 17525 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 17526 // No longer animating: clear out old animation matrix 17527 mRenderNode.setAnimationMatrix(null); 17528 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17529 } 17530 if (!drawingWithRenderNode 17531 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17532 final Transformation t = parent.getChildTransformation(); 17533 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 17534 if (hasTransform) { 17535 final int transformType = t.getTransformationType(); 17536 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 17537 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 17538 } 17539 } 17540 } 17541 17542 concatMatrix |= !childHasIdentityMatrix; 17543 17544 // Sets the flag as early as possible to allow draw() implementations 17545 // to call invalidate() successfully when doing animations 17546 mPrivateFlags |= PFLAG_DRAWN; 17547 17548 if (!concatMatrix && 17549 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 17550 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 17551 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 17552 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 17553 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 17554 return more; 17555 } 17556 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 17557 17558 if (hardwareAcceleratedCanvas) { 17559 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 17560 // retain the flag's value temporarily in the mRecreateDisplayList flag 17561 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 17562 mPrivateFlags &= ~PFLAG_INVALIDATED; 17563 } 17564 17565 RenderNode renderNode = null; 17566 Bitmap cache = null; 17567 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 17568 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 17569 if (layerType != LAYER_TYPE_NONE) { 17570 // If not drawing with RenderNode, treat HW layers as SW 17571 layerType = LAYER_TYPE_SOFTWARE; 17572 buildDrawingCache(true); 17573 } 17574 cache = getDrawingCache(true); 17575 } 17576 17577 if (drawingWithRenderNode) { 17578 // Delay getting the display list until animation-driven alpha values are 17579 // set up and possibly passed on to the view 17580 renderNode = updateDisplayListIfDirty(); 17581 if (!renderNode.isValid()) { 17582 // Uncommon, but possible. If a view is removed from the hierarchy during the call 17583 // to getDisplayList(), the display list will be marked invalid and we should not 17584 // try to use it again. 17585 renderNode = null; 17586 drawingWithRenderNode = false; 17587 } 17588 } 17589 17590 int sx = 0; 17591 int sy = 0; 17592 if (!drawingWithRenderNode) { 17593 computeScroll(); 17594 sx = mScrollX; 17595 sy = mScrollY; 17596 } 17597 17598 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 17599 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 17600 17601 int restoreTo = -1; 17602 if (!drawingWithRenderNode || transformToApply != null) { 17603 restoreTo = canvas.save(); 17604 } 17605 if (offsetForScroll) { 17606 canvas.translate(mLeft - sx, mTop - sy); 17607 } else { 17608 if (!drawingWithRenderNode) { 17609 canvas.translate(mLeft, mTop); 17610 } 17611 if (scalingRequired) { 17612 if (drawingWithRenderNode) { 17613 // TODO: Might not need this if we put everything inside the DL 17614 restoreTo = canvas.save(); 17615 } 17616 // mAttachInfo cannot be null, otherwise scalingRequired == false 17617 final float scale = 1.0f / mAttachInfo.mApplicationScale; 17618 canvas.scale(scale, scale); 17619 } 17620 } 17621 17622 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 17623 if (transformToApply != null 17624 || alpha < 1 17625 || !hasIdentityMatrix() 17626 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17627 if (transformToApply != null || !childHasIdentityMatrix) { 17628 int transX = 0; 17629 int transY = 0; 17630 17631 if (offsetForScroll) { 17632 transX = -sx; 17633 transY = -sy; 17634 } 17635 17636 if (transformToApply != null) { 17637 if (concatMatrix) { 17638 if (drawingWithRenderNode) { 17639 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 17640 } else { 17641 // Undo the scroll translation, apply the transformation matrix, 17642 // then redo the scroll translate to get the correct result. 17643 canvas.translate(-transX, -transY); 17644 canvas.concat(transformToApply.getMatrix()); 17645 canvas.translate(transX, transY); 17646 } 17647 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17648 } 17649 17650 float transformAlpha = transformToApply.getAlpha(); 17651 if (transformAlpha < 1) { 17652 alpha *= transformAlpha; 17653 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17654 } 17655 } 17656 17657 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 17658 canvas.translate(-transX, -transY); 17659 canvas.concat(getMatrix()); 17660 canvas.translate(transX, transY); 17661 } 17662 } 17663 17664 // Deal with alpha if it is or used to be <1 17665 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17666 if (alpha < 1) { 17667 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17668 } else { 17669 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17670 } 17671 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17672 if (!drawingWithDrawingCache) { 17673 final int multipliedAlpha = (int) (255 * alpha); 17674 if (!onSetAlpha(multipliedAlpha)) { 17675 if (drawingWithRenderNode) { 17676 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 17677 } else if (layerType == LAYER_TYPE_NONE) { 17678 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 17679 multipliedAlpha); 17680 } 17681 } else { 17682 // Alpha is handled by the child directly, clobber the layer's alpha 17683 mPrivateFlags |= PFLAG_ALPHA_SET; 17684 } 17685 } 17686 } 17687 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17688 onSetAlpha(255); 17689 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17690 } 17691 17692 if (!drawingWithRenderNode) { 17693 // apply clips directly, since RenderNode won't do it for this draw 17694 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 17695 if (offsetForScroll) { 17696 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 17697 } else { 17698 if (!scalingRequired || cache == null) { 17699 canvas.clipRect(0, 0, getWidth(), getHeight()); 17700 } else { 17701 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 17702 } 17703 } 17704 } 17705 17706 if (mClipBounds != null) { 17707 // clip bounds ignore scroll 17708 canvas.clipRect(mClipBounds); 17709 } 17710 } 17711 17712 if (!drawingWithDrawingCache) { 17713 if (drawingWithRenderNode) { 17714 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17715 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 17716 } else { 17717 // Fast path for layouts with no backgrounds 17718 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17719 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17720 dispatchDraw(canvas); 17721 } else { 17722 draw(canvas); 17723 } 17724 } 17725 } else if (cache != null) { 17726 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17727 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 17728 // no layer paint, use temporary paint to draw bitmap 17729 Paint cachePaint = parent.mCachePaint; 17730 if (cachePaint == null) { 17731 cachePaint = new Paint(); 17732 cachePaint.setDither(false); 17733 parent.mCachePaint = cachePaint; 17734 } 17735 cachePaint.setAlpha((int) (alpha * 255)); 17736 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 17737 } else { 17738 // use layer paint to draw the bitmap, merging the two alphas, but also restore 17739 int layerPaintAlpha = mLayerPaint.getAlpha(); 17740 if (alpha < 1) { 17741 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 17742 } 17743 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 17744 if (alpha < 1) { 17745 mLayerPaint.setAlpha(layerPaintAlpha); 17746 } 17747 } 17748 } 17749 17750 if (restoreTo >= 0) { 17751 canvas.restoreToCount(restoreTo); 17752 } 17753 17754 if (a != null && !more) { 17755 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 17756 onSetAlpha(255); 17757 } 17758 parent.finishAnimatingView(this, a); 17759 } 17760 17761 if (more && hardwareAcceleratedCanvas) { 17762 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17763 // alpha animations should cause the child to recreate its display list 17764 invalidate(true); 17765 } 17766 } 17767 17768 mRecreateDisplayList = false; 17769 17770 return more; 17771 } 17772 17773 static Paint getDebugPaint() { 17774 if (sDebugPaint == null) { 17775 sDebugPaint = new Paint(); 17776 sDebugPaint.setAntiAlias(false); 17777 } 17778 return sDebugPaint; 17779 } 17780 17781 final int dipsToPixels(int dips) { 17782 float scale = getContext().getResources().getDisplayMetrics().density; 17783 return (int) (dips * scale + 0.5f); 17784 } 17785 17786 final private void debugDrawFocus(Canvas canvas) { 17787 if (isFocused()) { 17788 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 17789 final int l = mScrollX; 17790 final int r = l + mRight - mLeft; 17791 final int t = mScrollY; 17792 final int b = t + mBottom - mTop; 17793 17794 final Paint paint = getDebugPaint(); 17795 paint.setColor(DEBUG_CORNERS_COLOR); 17796 17797 // Draw squares in corners. 17798 paint.setStyle(Paint.Style.FILL); 17799 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 17800 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 17801 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 17802 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 17803 17804 // Draw big X across the view. 17805 paint.setStyle(Paint.Style.STROKE); 17806 canvas.drawLine(l, t, r, b, paint); 17807 canvas.drawLine(l, b, r, t, paint); 17808 } 17809 } 17810 17811 /** 17812 * Manually render this view (and all of its children) to the given Canvas. 17813 * The view must have already done a full layout before this function is 17814 * called. When implementing a view, implement 17815 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 17816 * If you do need to override this method, call the superclass version. 17817 * 17818 * @param canvas The Canvas to which the View is rendered. 17819 */ 17820 @CallSuper 17821 public void draw(Canvas canvas) { 17822 final int privateFlags = mPrivateFlags; 17823 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 17824 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 17825 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 17826 17827 /* 17828 * Draw traversal performs several drawing steps which must be executed 17829 * in the appropriate order: 17830 * 17831 * 1. Draw the background 17832 * 2. If necessary, save the canvas' layers to prepare for fading 17833 * 3. Draw view's content 17834 * 4. Draw children 17835 * 5. If necessary, draw the fading edges and restore layers 17836 * 6. Draw decorations (scrollbars for instance) 17837 */ 17838 17839 // Step 1, draw the background, if needed 17840 int saveCount; 17841 17842 if (!dirtyOpaque) { 17843 drawBackground(canvas); 17844 } 17845 17846 // skip step 2 & 5 if possible (common case) 17847 final int viewFlags = mViewFlags; 17848 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 17849 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 17850 if (!verticalEdges && !horizontalEdges) { 17851 // Step 3, draw the content 17852 if (!dirtyOpaque) onDraw(canvas); 17853 17854 // Step 4, draw the children 17855 dispatchDraw(canvas); 17856 17857 // Overlay is part of the content and draws beneath Foreground 17858 if (mOverlay != null && !mOverlay.isEmpty()) { 17859 mOverlay.getOverlayView().dispatchDraw(canvas); 17860 } 17861 17862 // Step 6, draw decorations (foreground, scrollbars) 17863 onDrawForeground(canvas); 17864 17865 if (debugDraw()) { 17866 debugDrawFocus(canvas); 17867 } 17868 17869 // we're done... 17870 return; 17871 } 17872 17873 /* 17874 * Here we do the full fledged routine... 17875 * (this is an uncommon case where speed matters less, 17876 * this is why we repeat some of the tests that have been 17877 * done above) 17878 */ 17879 17880 boolean drawTop = false; 17881 boolean drawBottom = false; 17882 boolean drawLeft = false; 17883 boolean drawRight = false; 17884 17885 float topFadeStrength = 0.0f; 17886 float bottomFadeStrength = 0.0f; 17887 float leftFadeStrength = 0.0f; 17888 float rightFadeStrength = 0.0f; 17889 17890 // Step 2, save the canvas' layers 17891 int paddingLeft = mPaddingLeft; 17892 17893 final boolean offsetRequired = isPaddingOffsetRequired(); 17894 if (offsetRequired) { 17895 paddingLeft += getLeftPaddingOffset(); 17896 } 17897 17898 int left = mScrollX + paddingLeft; 17899 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 17900 int top = mScrollY + getFadeTop(offsetRequired); 17901 int bottom = top + getFadeHeight(offsetRequired); 17902 17903 if (offsetRequired) { 17904 right += getRightPaddingOffset(); 17905 bottom += getBottomPaddingOffset(); 17906 } 17907 17908 final ScrollabilityCache scrollabilityCache = mScrollCache; 17909 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 17910 int length = (int) fadeHeight; 17911 17912 // clip the fade length if top and bottom fades overlap 17913 // overlapping fades produce odd-looking artifacts 17914 if (verticalEdges && (top + length > bottom - length)) { 17915 length = (bottom - top) / 2; 17916 } 17917 17918 // also clip horizontal fades if necessary 17919 if (horizontalEdges && (left + length > right - length)) { 17920 length = (right - left) / 2; 17921 } 17922 17923 if (verticalEdges) { 17924 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 17925 drawTop = topFadeStrength * fadeHeight > 1.0f; 17926 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 17927 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 17928 } 17929 17930 if (horizontalEdges) { 17931 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 17932 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 17933 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 17934 drawRight = rightFadeStrength * fadeHeight > 1.0f; 17935 } 17936 17937 saveCount = canvas.getSaveCount(); 17938 17939 int solidColor = getSolidColor(); 17940 if (solidColor == 0) { 17941 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 17942 17943 if (drawTop) { 17944 canvas.saveLayer(left, top, right, top + length, null, flags); 17945 } 17946 17947 if (drawBottom) { 17948 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 17949 } 17950 17951 if (drawLeft) { 17952 canvas.saveLayer(left, top, left + length, bottom, null, flags); 17953 } 17954 17955 if (drawRight) { 17956 canvas.saveLayer(right - length, top, right, bottom, null, flags); 17957 } 17958 } else { 17959 scrollabilityCache.setFadeColor(solidColor); 17960 } 17961 17962 // Step 3, draw the content 17963 if (!dirtyOpaque) onDraw(canvas); 17964 17965 // Step 4, draw the children 17966 dispatchDraw(canvas); 17967 17968 // Step 5, draw the fade effect and restore layers 17969 final Paint p = scrollabilityCache.paint; 17970 final Matrix matrix = scrollabilityCache.matrix; 17971 final Shader fade = scrollabilityCache.shader; 17972 17973 if (drawTop) { 17974 matrix.setScale(1, fadeHeight * topFadeStrength); 17975 matrix.postTranslate(left, top); 17976 fade.setLocalMatrix(matrix); 17977 p.setShader(fade); 17978 canvas.drawRect(left, top, right, top + length, p); 17979 } 17980 17981 if (drawBottom) { 17982 matrix.setScale(1, fadeHeight * bottomFadeStrength); 17983 matrix.postRotate(180); 17984 matrix.postTranslate(left, bottom); 17985 fade.setLocalMatrix(matrix); 17986 p.setShader(fade); 17987 canvas.drawRect(left, bottom - length, right, bottom, p); 17988 } 17989 17990 if (drawLeft) { 17991 matrix.setScale(1, fadeHeight * leftFadeStrength); 17992 matrix.postRotate(-90); 17993 matrix.postTranslate(left, top); 17994 fade.setLocalMatrix(matrix); 17995 p.setShader(fade); 17996 canvas.drawRect(left, top, left + length, bottom, p); 17997 } 17998 17999 if (drawRight) { 18000 matrix.setScale(1, fadeHeight * rightFadeStrength); 18001 matrix.postRotate(90); 18002 matrix.postTranslate(right, top); 18003 fade.setLocalMatrix(matrix); 18004 p.setShader(fade); 18005 canvas.drawRect(right - length, top, right, bottom, p); 18006 } 18007 18008 canvas.restoreToCount(saveCount); 18009 18010 // Overlay is part of the content and draws beneath Foreground 18011 if (mOverlay != null && !mOverlay.isEmpty()) { 18012 mOverlay.getOverlayView().dispatchDraw(canvas); 18013 } 18014 18015 // Step 6, draw decorations (foreground, scrollbars) 18016 onDrawForeground(canvas); 18017 18018 if (debugDraw()) { 18019 debugDrawFocus(canvas); 18020 } 18021 } 18022 18023 /** 18024 * Draws the background onto the specified canvas. 18025 * 18026 * @param canvas Canvas on which to draw the background 18027 */ 18028 private void drawBackground(Canvas canvas) { 18029 final Drawable background = mBackground; 18030 if (background == null) { 18031 return; 18032 } 18033 18034 setBackgroundBounds(); 18035 18036 // Attempt to use a display list if requested. 18037 if (canvas.isHardwareAccelerated() && mAttachInfo != null 18038 && mAttachInfo.mThreadedRenderer != null) { 18039 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 18040 18041 final RenderNode renderNode = mBackgroundRenderNode; 18042 if (renderNode != null && renderNode.isValid()) { 18043 setBackgroundRenderNodeProperties(renderNode); 18044 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18045 return; 18046 } 18047 } 18048 18049 final int scrollX = mScrollX; 18050 final int scrollY = mScrollY; 18051 if ((scrollX | scrollY) == 0) { 18052 background.draw(canvas); 18053 } else { 18054 canvas.translate(scrollX, scrollY); 18055 background.draw(canvas); 18056 canvas.translate(-scrollX, -scrollY); 18057 } 18058 } 18059 18060 /** 18061 * Sets the correct background bounds and rebuilds the outline, if needed. 18062 * <p/> 18063 * This is called by LayoutLib. 18064 */ 18065 void setBackgroundBounds() { 18066 if (mBackgroundSizeChanged && mBackground != null) { 18067 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 18068 mBackgroundSizeChanged = false; 18069 rebuildOutline(); 18070 } 18071 } 18072 18073 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 18074 renderNode.setTranslationX(mScrollX); 18075 renderNode.setTranslationY(mScrollY); 18076 } 18077 18078 /** 18079 * Creates a new display list or updates the existing display list for the 18080 * specified Drawable. 18081 * 18082 * @param drawable Drawable for which to create a display list 18083 * @param renderNode Existing RenderNode, or {@code null} 18084 * @return A valid display list for the specified drawable 18085 */ 18086 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 18087 if (renderNode == null) { 18088 renderNode = RenderNode.create(drawable.getClass().getName(), this); 18089 } 18090 18091 final Rect bounds = drawable.getBounds(); 18092 final int width = bounds.width(); 18093 final int height = bounds.height(); 18094 final DisplayListCanvas canvas = renderNode.start(width, height); 18095 18096 // Reverse left/top translation done by drawable canvas, which will 18097 // instead be applied by rendernode's LTRB bounds below. This way, the 18098 // drawable's bounds match with its rendernode bounds and its content 18099 // will lie within those bounds in the rendernode tree. 18100 canvas.translate(-bounds.left, -bounds.top); 18101 18102 try { 18103 drawable.draw(canvas); 18104 } finally { 18105 renderNode.end(canvas); 18106 } 18107 18108 // Set up drawable properties that are view-independent. 18109 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 18110 renderNode.setProjectBackwards(drawable.isProjected()); 18111 renderNode.setProjectionReceiver(true); 18112 renderNode.setClipToBounds(false); 18113 return renderNode; 18114 } 18115 18116 /** 18117 * Returns the overlay for this view, creating it if it does not yet exist. 18118 * Adding drawables to the overlay will cause them to be displayed whenever 18119 * the view itself is redrawn. Objects in the overlay should be actively 18120 * managed: remove them when they should not be displayed anymore. The 18121 * overlay will always have the same size as its host view. 18122 * 18123 * <p>Note: Overlays do not currently work correctly with {@link 18124 * SurfaceView} or {@link TextureView}; contents in overlays for these 18125 * types of views may not display correctly.</p> 18126 * 18127 * @return The ViewOverlay object for this view. 18128 * @see ViewOverlay 18129 */ 18130 public ViewOverlay getOverlay() { 18131 if (mOverlay == null) { 18132 mOverlay = new ViewOverlay(mContext, this); 18133 } 18134 return mOverlay; 18135 } 18136 18137 /** 18138 * Override this if your view is known to always be drawn on top of a solid color background, 18139 * and needs to draw fading edges. Returning a non-zero color enables the view system to 18140 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 18141 * should be set to 0xFF. 18142 * 18143 * @see #setVerticalFadingEdgeEnabled(boolean) 18144 * @see #setHorizontalFadingEdgeEnabled(boolean) 18145 * 18146 * @return The known solid color background for this view, or 0 if the color may vary 18147 */ 18148 @ViewDebug.ExportedProperty(category = "drawing") 18149 @ColorInt 18150 public int getSolidColor() { 18151 return 0; 18152 } 18153 18154 /** 18155 * Build a human readable string representation of the specified view flags. 18156 * 18157 * @param flags the view flags to convert to a string 18158 * @return a String representing the supplied flags 18159 */ 18160 private static String printFlags(int flags) { 18161 String output = ""; 18162 int numFlags = 0; 18163 if ((flags & FOCUSABLE_MASK) == FOCUSABLE) { 18164 output += "TAKES_FOCUS"; 18165 numFlags++; 18166 } 18167 18168 switch (flags & VISIBILITY_MASK) { 18169 case INVISIBLE: 18170 if (numFlags > 0) { 18171 output += " "; 18172 } 18173 output += "INVISIBLE"; 18174 // USELESS HERE numFlags++; 18175 break; 18176 case GONE: 18177 if (numFlags > 0) { 18178 output += " "; 18179 } 18180 output += "GONE"; 18181 // USELESS HERE numFlags++; 18182 break; 18183 default: 18184 break; 18185 } 18186 return output; 18187 } 18188 18189 /** 18190 * Build a human readable string representation of the specified private 18191 * view flags. 18192 * 18193 * @param privateFlags the private view flags to convert to a string 18194 * @return a String representing the supplied flags 18195 */ 18196 private static String printPrivateFlags(int privateFlags) { 18197 String output = ""; 18198 int numFlags = 0; 18199 18200 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 18201 output += "WANTS_FOCUS"; 18202 numFlags++; 18203 } 18204 18205 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 18206 if (numFlags > 0) { 18207 output += " "; 18208 } 18209 output += "FOCUSED"; 18210 numFlags++; 18211 } 18212 18213 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 18214 if (numFlags > 0) { 18215 output += " "; 18216 } 18217 output += "SELECTED"; 18218 numFlags++; 18219 } 18220 18221 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 18222 if (numFlags > 0) { 18223 output += " "; 18224 } 18225 output += "IS_ROOT_NAMESPACE"; 18226 numFlags++; 18227 } 18228 18229 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 18230 if (numFlags > 0) { 18231 output += " "; 18232 } 18233 output += "HAS_BOUNDS"; 18234 numFlags++; 18235 } 18236 18237 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 18238 if (numFlags > 0) { 18239 output += " "; 18240 } 18241 output += "DRAWN"; 18242 // USELESS HERE numFlags++; 18243 } 18244 return output; 18245 } 18246 18247 /** 18248 * <p>Indicates whether or not this view's layout will be requested during 18249 * the next hierarchy layout pass.</p> 18250 * 18251 * @return true if the layout will be forced during next layout pass 18252 */ 18253 public boolean isLayoutRequested() { 18254 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 18255 } 18256 18257 /** 18258 * Return true if o is a ViewGroup that is laying out using optical bounds. 18259 * @hide 18260 */ 18261 public static boolean isLayoutModeOptical(Object o) { 18262 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 18263 } 18264 18265 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 18266 Insets parentInsets = mParent instanceof View ? 18267 ((View) mParent).getOpticalInsets() : Insets.NONE; 18268 Insets childInsets = getOpticalInsets(); 18269 return setFrame( 18270 left + parentInsets.left - childInsets.left, 18271 top + parentInsets.top - childInsets.top, 18272 right + parentInsets.left + childInsets.right, 18273 bottom + parentInsets.top + childInsets.bottom); 18274 } 18275 18276 /** 18277 * Assign a size and position to a view and all of its 18278 * descendants 18279 * 18280 * <p>This is the second phase of the layout mechanism. 18281 * (The first is measuring). In this phase, each parent calls 18282 * layout on all of its children to position them. 18283 * This is typically done using the child measurements 18284 * that were stored in the measure pass().</p> 18285 * 18286 * <p>Derived classes should not override this method. 18287 * Derived classes with children should override 18288 * onLayout. In that method, they should 18289 * call layout on each of their children.</p> 18290 * 18291 * @param l Left position, relative to parent 18292 * @param t Top position, relative to parent 18293 * @param r Right position, relative to parent 18294 * @param b Bottom position, relative to parent 18295 */ 18296 @SuppressWarnings({"unchecked"}) 18297 public void layout(int l, int t, int r, int b) { 18298 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 18299 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 18300 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 18301 } 18302 18303 int oldL = mLeft; 18304 int oldT = mTop; 18305 int oldB = mBottom; 18306 int oldR = mRight; 18307 18308 boolean changed = isLayoutModeOptical(mParent) ? 18309 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 18310 18311 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 18312 onLayout(changed, l, t, r, b); 18313 18314 if (shouldDrawRoundScrollbar()) { 18315 if(mRoundScrollbarRenderer == null) { 18316 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 18317 } 18318 } else { 18319 mRoundScrollbarRenderer = null; 18320 } 18321 18322 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 18323 18324 ListenerInfo li = mListenerInfo; 18325 if (li != null && li.mOnLayoutChangeListeners != null) { 18326 ArrayList<OnLayoutChangeListener> listenersCopy = 18327 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 18328 int numListeners = listenersCopy.size(); 18329 for (int i = 0; i < numListeners; ++i) { 18330 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 18331 } 18332 } 18333 } 18334 18335 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 18336 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 18337 } 18338 18339 /** 18340 * Called from layout when this view should 18341 * assign a size and position to each of its children. 18342 * 18343 * Derived classes with children should override 18344 * this method and call layout on each of 18345 * their children. 18346 * @param changed This is a new size or position for this view 18347 * @param left Left position, relative to parent 18348 * @param top Top position, relative to parent 18349 * @param right Right position, relative to parent 18350 * @param bottom Bottom position, relative to parent 18351 */ 18352 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 18353 } 18354 18355 /** 18356 * Assign a size and position to this view. 18357 * 18358 * This is called from layout. 18359 * 18360 * @param left Left position, relative to parent 18361 * @param top Top position, relative to parent 18362 * @param right Right position, relative to parent 18363 * @param bottom Bottom position, relative to parent 18364 * @return true if the new size and position are different than the 18365 * previous ones 18366 * {@hide} 18367 */ 18368 protected boolean setFrame(int left, int top, int right, int bottom) { 18369 boolean changed = false; 18370 18371 if (DBG) { 18372 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 18373 + right + "," + bottom + ")"); 18374 } 18375 18376 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 18377 changed = true; 18378 18379 // Remember our drawn bit 18380 int drawn = mPrivateFlags & PFLAG_DRAWN; 18381 18382 int oldWidth = mRight - mLeft; 18383 int oldHeight = mBottom - mTop; 18384 int newWidth = right - left; 18385 int newHeight = bottom - top; 18386 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 18387 18388 // Invalidate our old position 18389 invalidate(sizeChanged); 18390 18391 mLeft = left; 18392 mTop = top; 18393 mRight = right; 18394 mBottom = bottom; 18395 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 18396 18397 mPrivateFlags |= PFLAG_HAS_BOUNDS; 18398 18399 18400 if (sizeChanged) { 18401 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 18402 } 18403 18404 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 18405 // If we are visible, force the DRAWN bit to on so that 18406 // this invalidate will go through (at least to our parent). 18407 // This is because someone may have invalidated this view 18408 // before this call to setFrame came in, thereby clearing 18409 // the DRAWN bit. 18410 mPrivateFlags |= PFLAG_DRAWN; 18411 invalidate(sizeChanged); 18412 // parent display list may need to be recreated based on a change in the bounds 18413 // of any child 18414 invalidateParentCaches(); 18415 } 18416 18417 // Reset drawn bit to original value (invalidate turns it off) 18418 mPrivateFlags |= drawn; 18419 18420 mBackgroundSizeChanged = true; 18421 if (mForegroundInfo != null) { 18422 mForegroundInfo.mBoundsChanged = true; 18423 } 18424 18425 notifySubtreeAccessibilityStateChangedIfNeeded(); 18426 } 18427 return changed; 18428 } 18429 18430 /** 18431 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 18432 * @hide 18433 */ 18434 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 18435 setFrame(left, top, right, bottom); 18436 } 18437 18438 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 18439 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 18440 if (mOverlay != null) { 18441 mOverlay.getOverlayView().setRight(newWidth); 18442 mOverlay.getOverlayView().setBottom(newHeight); 18443 } 18444 rebuildOutline(); 18445 } 18446 18447 /** 18448 * Finalize inflating a view from XML. This is called as the last phase 18449 * of inflation, after all child views have been added. 18450 * 18451 * <p>Even if the subclass overrides onFinishInflate, they should always be 18452 * sure to call the super method, so that we get called. 18453 */ 18454 @CallSuper 18455 protected void onFinishInflate() { 18456 } 18457 18458 /** 18459 * Returns the resources associated with this view. 18460 * 18461 * @return Resources object. 18462 */ 18463 public Resources getResources() { 18464 return mResources; 18465 } 18466 18467 /** 18468 * Invalidates the specified Drawable. 18469 * 18470 * @param drawable the drawable to invalidate 18471 */ 18472 @Override 18473 public void invalidateDrawable(@NonNull Drawable drawable) { 18474 if (verifyDrawable(drawable)) { 18475 final Rect dirty = drawable.getDirtyBounds(); 18476 final int scrollX = mScrollX; 18477 final int scrollY = mScrollY; 18478 18479 invalidate(dirty.left + scrollX, dirty.top + scrollY, 18480 dirty.right + scrollX, dirty.bottom + scrollY); 18481 rebuildOutline(); 18482 } 18483 } 18484 18485 /** 18486 * Schedules an action on a drawable to occur at a specified time. 18487 * 18488 * @param who the recipient of the action 18489 * @param what the action to run on the drawable 18490 * @param when the time at which the action must occur. Uses the 18491 * {@link SystemClock#uptimeMillis} timebase. 18492 */ 18493 @Override 18494 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 18495 if (verifyDrawable(who) && what != null) { 18496 final long delay = when - SystemClock.uptimeMillis(); 18497 if (mAttachInfo != null) { 18498 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 18499 Choreographer.CALLBACK_ANIMATION, what, who, 18500 Choreographer.subtractFrameDelay(delay)); 18501 } else { 18502 // Postpone the runnable until we know 18503 // on which thread it needs to run. 18504 getRunQueue().postDelayed(what, delay); 18505 } 18506 } 18507 } 18508 18509 /** 18510 * Cancels a scheduled action on a drawable. 18511 * 18512 * @param who the recipient of the action 18513 * @param what the action to cancel 18514 */ 18515 @Override 18516 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 18517 if (verifyDrawable(who) && what != null) { 18518 if (mAttachInfo != null) { 18519 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18520 Choreographer.CALLBACK_ANIMATION, what, who); 18521 } 18522 getRunQueue().removeCallbacks(what); 18523 } 18524 } 18525 18526 /** 18527 * Unschedule any events associated with the given Drawable. This can be 18528 * used when selecting a new Drawable into a view, so that the previous 18529 * one is completely unscheduled. 18530 * 18531 * @param who The Drawable to unschedule. 18532 * 18533 * @see #drawableStateChanged 18534 */ 18535 public void unscheduleDrawable(Drawable who) { 18536 if (mAttachInfo != null && who != null) { 18537 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18538 Choreographer.CALLBACK_ANIMATION, null, who); 18539 } 18540 } 18541 18542 /** 18543 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 18544 * that the View directionality can and will be resolved before its Drawables. 18545 * 18546 * Will call {@link View#onResolveDrawables} when resolution is done. 18547 * 18548 * @hide 18549 */ 18550 protected void resolveDrawables() { 18551 // Drawables resolution may need to happen before resolving the layout direction (which is 18552 // done only during the measure() call). 18553 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 18554 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 18555 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 18556 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 18557 // direction to be resolved as its resolved value will be the same as its raw value. 18558 if (!isLayoutDirectionResolved() && 18559 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 18560 return; 18561 } 18562 18563 final int layoutDirection = isLayoutDirectionResolved() ? 18564 getLayoutDirection() : getRawLayoutDirection(); 18565 18566 if (mBackground != null) { 18567 mBackground.setLayoutDirection(layoutDirection); 18568 } 18569 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18570 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 18571 } 18572 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 18573 onResolveDrawables(layoutDirection); 18574 } 18575 18576 boolean areDrawablesResolved() { 18577 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 18578 } 18579 18580 /** 18581 * Called when layout direction has been resolved. 18582 * 18583 * The default implementation does nothing. 18584 * 18585 * @param layoutDirection The resolved layout direction. 18586 * 18587 * @see #LAYOUT_DIRECTION_LTR 18588 * @see #LAYOUT_DIRECTION_RTL 18589 * 18590 * @hide 18591 */ 18592 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 18593 } 18594 18595 /** 18596 * @hide 18597 */ 18598 protected void resetResolvedDrawables() { 18599 resetResolvedDrawablesInternal(); 18600 } 18601 18602 void resetResolvedDrawablesInternal() { 18603 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 18604 } 18605 18606 /** 18607 * If your view subclass is displaying its own Drawable objects, it should 18608 * override this function and return true for any Drawable it is 18609 * displaying. This allows animations for those drawables to be 18610 * scheduled. 18611 * 18612 * <p>Be sure to call through to the super class when overriding this 18613 * function. 18614 * 18615 * @param who The Drawable to verify. Return true if it is one you are 18616 * displaying, else return the result of calling through to the 18617 * super class. 18618 * 18619 * @return boolean If true than the Drawable is being displayed in the 18620 * view; else false and it is not allowed to animate. 18621 * 18622 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 18623 * @see #drawableStateChanged() 18624 */ 18625 @CallSuper 18626 protected boolean verifyDrawable(@NonNull Drawable who) { 18627 // Avoid verifying the scroll bar drawable so that we don't end up in 18628 // an invalidation loop. This effectively prevents the scroll bar 18629 // drawable from triggering invalidations and scheduling runnables. 18630 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); 18631 } 18632 18633 /** 18634 * This function is called whenever the state of the view changes in such 18635 * a way that it impacts the state of drawables being shown. 18636 * <p> 18637 * If the View has a StateListAnimator, it will also be called to run necessary state 18638 * change animations. 18639 * <p> 18640 * Be sure to call through to the superclass when overriding this function. 18641 * 18642 * @see Drawable#setState(int[]) 18643 */ 18644 @CallSuper 18645 protected void drawableStateChanged() { 18646 final int[] state = getDrawableState(); 18647 boolean changed = false; 18648 18649 final Drawable bg = mBackground; 18650 if (bg != null && bg.isStateful()) { 18651 changed |= bg.setState(state); 18652 } 18653 18654 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 18655 if (fg != null && fg.isStateful()) { 18656 changed |= fg.setState(state); 18657 } 18658 18659 if (mScrollCache != null) { 18660 final Drawable scrollBar = mScrollCache.scrollBar; 18661 if (scrollBar != null && scrollBar.isStateful()) { 18662 changed |= scrollBar.setState(state) 18663 && mScrollCache.state != ScrollabilityCache.OFF; 18664 } 18665 } 18666 18667 if (mStateListAnimator != null) { 18668 mStateListAnimator.setState(state); 18669 } 18670 18671 if (changed) { 18672 invalidate(); 18673 } 18674 } 18675 18676 /** 18677 * This function is called whenever the view hotspot changes and needs to 18678 * be propagated to drawables or child views managed by the view. 18679 * <p> 18680 * Dispatching to child views is handled by 18681 * {@link #dispatchDrawableHotspotChanged(float, float)}. 18682 * <p> 18683 * Be sure to call through to the superclass when overriding this function. 18684 * 18685 * @param x hotspot x coordinate 18686 * @param y hotspot y coordinate 18687 */ 18688 @CallSuper 18689 public void drawableHotspotChanged(float x, float y) { 18690 if (mBackground != null) { 18691 mBackground.setHotspot(x, y); 18692 } 18693 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18694 mForegroundInfo.mDrawable.setHotspot(x, y); 18695 } 18696 18697 dispatchDrawableHotspotChanged(x, y); 18698 } 18699 18700 /** 18701 * Dispatches drawableHotspotChanged to all of this View's children. 18702 * 18703 * @param x hotspot x coordinate 18704 * @param y hotspot y coordinate 18705 * @see #drawableHotspotChanged(float, float) 18706 */ 18707 public void dispatchDrawableHotspotChanged(float x, float y) { 18708 } 18709 18710 /** 18711 * Call this to force a view to update its drawable state. This will cause 18712 * drawableStateChanged to be called on this view. Views that are interested 18713 * in the new state should call getDrawableState. 18714 * 18715 * @see #drawableStateChanged 18716 * @see #getDrawableState 18717 */ 18718 public void refreshDrawableState() { 18719 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 18720 drawableStateChanged(); 18721 18722 ViewParent parent = mParent; 18723 if (parent != null) { 18724 parent.childDrawableStateChanged(this); 18725 } 18726 } 18727 18728 /** 18729 * Return an array of resource IDs of the drawable states representing the 18730 * current state of the view. 18731 * 18732 * @return The current drawable state 18733 * 18734 * @see Drawable#setState(int[]) 18735 * @see #drawableStateChanged() 18736 * @see #onCreateDrawableState(int) 18737 */ 18738 public final int[] getDrawableState() { 18739 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 18740 return mDrawableState; 18741 } else { 18742 mDrawableState = onCreateDrawableState(0); 18743 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 18744 return mDrawableState; 18745 } 18746 } 18747 18748 /** 18749 * Generate the new {@link android.graphics.drawable.Drawable} state for 18750 * this view. This is called by the view 18751 * system when the cached Drawable state is determined to be invalid. To 18752 * retrieve the current state, you should use {@link #getDrawableState}. 18753 * 18754 * @param extraSpace if non-zero, this is the number of extra entries you 18755 * would like in the returned array in which you can place your own 18756 * states. 18757 * 18758 * @return Returns an array holding the current {@link Drawable} state of 18759 * the view. 18760 * 18761 * @see #mergeDrawableStates(int[], int[]) 18762 */ 18763 protected int[] onCreateDrawableState(int extraSpace) { 18764 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 18765 mParent instanceof View) { 18766 return ((View) mParent).onCreateDrawableState(extraSpace); 18767 } 18768 18769 int[] drawableState; 18770 18771 int privateFlags = mPrivateFlags; 18772 18773 int viewStateIndex = 0; 18774 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 18775 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 18776 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 18777 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 18778 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 18779 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 18780 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 18781 ThreadedRenderer.isAvailable()) { 18782 // This is set if HW acceleration is requested, even if the current 18783 // process doesn't allow it. This is just to allow app preview 18784 // windows to better match their app. 18785 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 18786 } 18787 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 18788 18789 final int privateFlags2 = mPrivateFlags2; 18790 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 18791 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 18792 } 18793 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 18794 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 18795 } 18796 18797 drawableState = StateSet.get(viewStateIndex); 18798 18799 //noinspection ConstantIfStatement 18800 if (false) { 18801 Log.i("View", "drawableStateIndex=" + viewStateIndex); 18802 Log.i("View", toString() 18803 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 18804 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 18805 + " fo=" + hasFocus() 18806 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 18807 + " wf=" + hasWindowFocus() 18808 + ": " + Arrays.toString(drawableState)); 18809 } 18810 18811 if (extraSpace == 0) { 18812 return drawableState; 18813 } 18814 18815 final int[] fullState; 18816 if (drawableState != null) { 18817 fullState = new int[drawableState.length + extraSpace]; 18818 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 18819 } else { 18820 fullState = new int[extraSpace]; 18821 } 18822 18823 return fullState; 18824 } 18825 18826 /** 18827 * Merge your own state values in <var>additionalState</var> into the base 18828 * state values <var>baseState</var> that were returned by 18829 * {@link #onCreateDrawableState(int)}. 18830 * 18831 * @param baseState The base state values returned by 18832 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 18833 * own additional state values. 18834 * 18835 * @param additionalState The additional state values you would like 18836 * added to <var>baseState</var>; this array is not modified. 18837 * 18838 * @return As a convenience, the <var>baseState</var> array you originally 18839 * passed into the function is returned. 18840 * 18841 * @see #onCreateDrawableState(int) 18842 */ 18843 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 18844 final int N = baseState.length; 18845 int i = N - 1; 18846 while (i >= 0 && baseState[i] == 0) { 18847 i--; 18848 } 18849 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 18850 return baseState; 18851 } 18852 18853 /** 18854 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 18855 * on all Drawable objects associated with this view. 18856 * <p> 18857 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 18858 * attached to this view. 18859 */ 18860 @CallSuper 18861 public void jumpDrawablesToCurrentState() { 18862 if (mBackground != null) { 18863 mBackground.jumpToCurrentState(); 18864 } 18865 if (mStateListAnimator != null) { 18866 mStateListAnimator.jumpToCurrentState(); 18867 } 18868 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18869 mForegroundInfo.mDrawable.jumpToCurrentState(); 18870 } 18871 } 18872 18873 /** 18874 * Sets the background color for this view. 18875 * @param color the color of the background 18876 */ 18877 @RemotableViewMethod 18878 public void setBackgroundColor(@ColorInt int color) { 18879 if (mBackground instanceof ColorDrawable) { 18880 ((ColorDrawable) mBackground.mutate()).setColor(color); 18881 computeOpaqueFlags(); 18882 mBackgroundResource = 0; 18883 } else { 18884 setBackground(new ColorDrawable(color)); 18885 } 18886 } 18887 18888 /** 18889 * Set the background to a given resource. The resource should refer to 18890 * a Drawable object or 0 to remove the background. 18891 * @param resid The identifier of the resource. 18892 * 18893 * @attr ref android.R.styleable#View_background 18894 */ 18895 @RemotableViewMethod 18896 public void setBackgroundResource(@DrawableRes int resid) { 18897 if (resid != 0 && resid == mBackgroundResource) { 18898 return; 18899 } 18900 18901 Drawable d = null; 18902 if (resid != 0) { 18903 d = mContext.getDrawable(resid); 18904 } 18905 setBackground(d); 18906 18907 mBackgroundResource = resid; 18908 } 18909 18910 /** 18911 * Set the background to a given Drawable, or remove the background. If the 18912 * background has padding, this View's padding is set to the background's 18913 * padding. However, when a background is removed, this View's padding isn't 18914 * touched. If setting the padding is desired, please use 18915 * {@link #setPadding(int, int, int, int)}. 18916 * 18917 * @param background The Drawable to use as the background, or null to remove the 18918 * background 18919 */ 18920 public void setBackground(Drawable background) { 18921 //noinspection deprecation 18922 setBackgroundDrawable(background); 18923 } 18924 18925 /** 18926 * @deprecated use {@link #setBackground(Drawable)} instead 18927 */ 18928 @Deprecated 18929 public void setBackgroundDrawable(Drawable background) { 18930 computeOpaqueFlags(); 18931 18932 if (background == mBackground) { 18933 return; 18934 } 18935 18936 boolean requestLayout = false; 18937 18938 mBackgroundResource = 0; 18939 18940 /* 18941 * Regardless of whether we're setting a new background or not, we want 18942 * to clear the previous drawable. setVisible first while we still have the callback set. 18943 */ 18944 if (mBackground != null) { 18945 if (isAttachedToWindow()) { 18946 mBackground.setVisible(false, false); 18947 } 18948 mBackground.setCallback(null); 18949 unscheduleDrawable(mBackground); 18950 } 18951 18952 if (background != null) { 18953 Rect padding = sThreadLocal.get(); 18954 if (padding == null) { 18955 padding = new Rect(); 18956 sThreadLocal.set(padding); 18957 } 18958 resetResolvedDrawablesInternal(); 18959 background.setLayoutDirection(getLayoutDirection()); 18960 if (background.getPadding(padding)) { 18961 resetResolvedPaddingInternal(); 18962 switch (background.getLayoutDirection()) { 18963 case LAYOUT_DIRECTION_RTL: 18964 mUserPaddingLeftInitial = padding.right; 18965 mUserPaddingRightInitial = padding.left; 18966 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 18967 break; 18968 case LAYOUT_DIRECTION_LTR: 18969 default: 18970 mUserPaddingLeftInitial = padding.left; 18971 mUserPaddingRightInitial = padding.right; 18972 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 18973 } 18974 mLeftPaddingDefined = false; 18975 mRightPaddingDefined = false; 18976 } 18977 18978 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 18979 // if it has a different minimum size, we should layout again 18980 if (mBackground == null 18981 || mBackground.getMinimumHeight() != background.getMinimumHeight() 18982 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 18983 requestLayout = true; 18984 } 18985 18986 // Set mBackground before we set this as the callback and start making other 18987 // background drawable state change calls. In particular, the setVisible call below 18988 // can result in drawables attempting to start animations or otherwise invalidate, 18989 // which requires the view set as the callback (us) to recognize the drawable as 18990 // belonging to it as per verifyDrawable. 18991 mBackground = background; 18992 if (background.isStateful()) { 18993 background.setState(getDrawableState()); 18994 } 18995 if (isAttachedToWindow()) { 18996 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 18997 } 18998 18999 applyBackgroundTint(); 19000 19001 // Set callback last, since the view may still be initializing. 19002 background.setCallback(this); 19003 19004 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19005 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19006 requestLayout = true; 19007 } 19008 } else { 19009 /* Remove the background */ 19010 mBackground = null; 19011 if ((mViewFlags & WILL_NOT_DRAW) != 0 19012 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 19013 mPrivateFlags |= PFLAG_SKIP_DRAW; 19014 } 19015 19016 /* 19017 * When the background is set, we try to apply its padding to this 19018 * View. When the background is removed, we don't touch this View's 19019 * padding. This is noted in the Javadocs. Hence, we don't need to 19020 * requestLayout(), the invalidate() below is sufficient. 19021 */ 19022 19023 // The old background's minimum size could have affected this 19024 // View's layout, so let's requestLayout 19025 requestLayout = true; 19026 } 19027 19028 computeOpaqueFlags(); 19029 19030 if (requestLayout) { 19031 requestLayout(); 19032 } 19033 19034 mBackgroundSizeChanged = true; 19035 invalidate(true); 19036 invalidateOutline(); 19037 } 19038 19039 /** 19040 * Gets the background drawable 19041 * 19042 * @return The drawable used as the background for this view, if any. 19043 * 19044 * @see #setBackground(Drawable) 19045 * 19046 * @attr ref android.R.styleable#View_background 19047 */ 19048 public Drawable getBackground() { 19049 return mBackground; 19050 } 19051 19052 /** 19053 * Applies a tint to the background drawable. Does not modify the current tint 19054 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19055 * <p> 19056 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 19057 * mutate the drawable and apply the specified tint and tint mode using 19058 * {@link Drawable#setTintList(ColorStateList)}. 19059 * 19060 * @param tint the tint to apply, may be {@code null} to clear tint 19061 * 19062 * @attr ref android.R.styleable#View_backgroundTint 19063 * @see #getBackgroundTintList() 19064 * @see Drawable#setTintList(ColorStateList) 19065 */ 19066 public void setBackgroundTintList(@Nullable ColorStateList tint) { 19067 if (mBackgroundTint == null) { 19068 mBackgroundTint = new TintInfo(); 19069 } 19070 mBackgroundTint.mTintList = tint; 19071 mBackgroundTint.mHasTintList = true; 19072 19073 applyBackgroundTint(); 19074 } 19075 19076 /** 19077 * Return the tint applied to the background drawable, if specified. 19078 * 19079 * @return the tint applied to the background drawable 19080 * @attr ref android.R.styleable#View_backgroundTint 19081 * @see #setBackgroundTintList(ColorStateList) 19082 */ 19083 @Nullable 19084 public ColorStateList getBackgroundTintList() { 19085 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 19086 } 19087 19088 /** 19089 * Specifies the blending mode used to apply the tint specified by 19090 * {@link #setBackgroundTintList(ColorStateList)}} to the background 19091 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19092 * 19093 * @param tintMode the blending mode used to apply the tint, may be 19094 * {@code null} to clear tint 19095 * @attr ref android.R.styleable#View_backgroundTintMode 19096 * @see #getBackgroundTintMode() 19097 * @see Drawable#setTintMode(PorterDuff.Mode) 19098 */ 19099 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19100 if (mBackgroundTint == null) { 19101 mBackgroundTint = new TintInfo(); 19102 } 19103 mBackgroundTint.mTintMode = tintMode; 19104 mBackgroundTint.mHasTintMode = true; 19105 19106 applyBackgroundTint(); 19107 } 19108 19109 /** 19110 * Return the blending mode used to apply the tint to the background 19111 * drawable, if specified. 19112 * 19113 * @return the blending mode used to apply the tint to the background 19114 * drawable 19115 * @attr ref android.R.styleable#View_backgroundTintMode 19116 * @see #setBackgroundTintMode(PorterDuff.Mode) 19117 */ 19118 @Nullable 19119 public PorterDuff.Mode getBackgroundTintMode() { 19120 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 19121 } 19122 19123 private void applyBackgroundTint() { 19124 if (mBackground != null && mBackgroundTint != null) { 19125 final TintInfo tintInfo = mBackgroundTint; 19126 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19127 mBackground = mBackground.mutate(); 19128 19129 if (tintInfo.mHasTintList) { 19130 mBackground.setTintList(tintInfo.mTintList); 19131 } 19132 19133 if (tintInfo.mHasTintMode) { 19134 mBackground.setTintMode(tintInfo.mTintMode); 19135 } 19136 19137 // The drawable (or one of its children) may not have been 19138 // stateful before applying the tint, so let's try again. 19139 if (mBackground.isStateful()) { 19140 mBackground.setState(getDrawableState()); 19141 } 19142 } 19143 } 19144 } 19145 19146 /** 19147 * Returns the drawable used as the foreground of this View. The 19148 * foreground drawable, if non-null, is always drawn on top of the view's content. 19149 * 19150 * @return a Drawable or null if no foreground was set 19151 * 19152 * @see #onDrawForeground(Canvas) 19153 */ 19154 public Drawable getForeground() { 19155 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19156 } 19157 19158 /** 19159 * Supply a Drawable that is to be rendered on top of all of the content in the view. 19160 * 19161 * @param foreground the Drawable to be drawn on top of the children 19162 * 19163 * @attr ref android.R.styleable#View_foreground 19164 */ 19165 public void setForeground(Drawable foreground) { 19166 if (mForegroundInfo == null) { 19167 if (foreground == null) { 19168 // Nothing to do. 19169 return; 19170 } 19171 mForegroundInfo = new ForegroundInfo(); 19172 } 19173 19174 if (foreground == mForegroundInfo.mDrawable) { 19175 // Nothing to do 19176 return; 19177 } 19178 19179 if (mForegroundInfo.mDrawable != null) { 19180 if (isAttachedToWindow()) { 19181 mForegroundInfo.mDrawable.setVisible(false, false); 19182 } 19183 mForegroundInfo.mDrawable.setCallback(null); 19184 unscheduleDrawable(mForegroundInfo.mDrawable); 19185 } 19186 19187 mForegroundInfo.mDrawable = foreground; 19188 mForegroundInfo.mBoundsChanged = true; 19189 if (foreground != null) { 19190 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19191 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19192 } 19193 foreground.setLayoutDirection(getLayoutDirection()); 19194 if (foreground.isStateful()) { 19195 foreground.setState(getDrawableState()); 19196 } 19197 applyForegroundTint(); 19198 if (isAttachedToWindow()) { 19199 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 19200 } 19201 // Set callback last, since the view may still be initializing. 19202 foreground.setCallback(this); 19203 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) { 19204 mPrivateFlags |= PFLAG_SKIP_DRAW; 19205 } 19206 requestLayout(); 19207 invalidate(); 19208 } 19209 19210 /** 19211 * Magic bit used to support features of framework-internal window decor implementation details. 19212 * This used to live exclusively in FrameLayout. 19213 * 19214 * @return true if the foreground should draw inside the padding region or false 19215 * if it should draw inset by the view's padding 19216 * @hide internal use only; only used by FrameLayout and internal screen layouts. 19217 */ 19218 public boolean isForegroundInsidePadding() { 19219 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 19220 } 19221 19222 /** 19223 * Describes how the foreground is positioned. 19224 * 19225 * @return foreground gravity. 19226 * 19227 * @see #setForegroundGravity(int) 19228 * 19229 * @attr ref android.R.styleable#View_foregroundGravity 19230 */ 19231 public int getForegroundGravity() { 19232 return mForegroundInfo != null ? mForegroundInfo.mGravity 19233 : Gravity.START | Gravity.TOP; 19234 } 19235 19236 /** 19237 * Describes how the foreground is positioned. Defaults to START and TOP. 19238 * 19239 * @param gravity see {@link android.view.Gravity} 19240 * 19241 * @see #getForegroundGravity() 19242 * 19243 * @attr ref android.R.styleable#View_foregroundGravity 19244 */ 19245 public void setForegroundGravity(int gravity) { 19246 if (mForegroundInfo == null) { 19247 mForegroundInfo = new ForegroundInfo(); 19248 } 19249 19250 if (mForegroundInfo.mGravity != gravity) { 19251 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 19252 gravity |= Gravity.START; 19253 } 19254 19255 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 19256 gravity |= Gravity.TOP; 19257 } 19258 19259 mForegroundInfo.mGravity = gravity; 19260 requestLayout(); 19261 } 19262 } 19263 19264 /** 19265 * Applies a tint to the foreground drawable. Does not modify the current tint 19266 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19267 * <p> 19268 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 19269 * mutate the drawable and apply the specified tint and tint mode using 19270 * {@link Drawable#setTintList(ColorStateList)}. 19271 * 19272 * @param tint the tint to apply, may be {@code null} to clear tint 19273 * 19274 * @attr ref android.R.styleable#View_foregroundTint 19275 * @see #getForegroundTintList() 19276 * @see Drawable#setTintList(ColorStateList) 19277 */ 19278 public void setForegroundTintList(@Nullable ColorStateList tint) { 19279 if (mForegroundInfo == null) { 19280 mForegroundInfo = new ForegroundInfo(); 19281 } 19282 if (mForegroundInfo.mTintInfo == null) { 19283 mForegroundInfo.mTintInfo = new TintInfo(); 19284 } 19285 mForegroundInfo.mTintInfo.mTintList = tint; 19286 mForegroundInfo.mTintInfo.mHasTintList = true; 19287 19288 applyForegroundTint(); 19289 } 19290 19291 /** 19292 * Return the tint applied to the foreground drawable, if specified. 19293 * 19294 * @return the tint applied to the foreground drawable 19295 * @attr ref android.R.styleable#View_foregroundTint 19296 * @see #setForegroundTintList(ColorStateList) 19297 */ 19298 @Nullable 19299 public ColorStateList getForegroundTintList() { 19300 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19301 ? mForegroundInfo.mTintInfo.mTintList : null; 19302 } 19303 19304 /** 19305 * Specifies the blending mode used to apply the tint specified by 19306 * {@link #setForegroundTintList(ColorStateList)}} to the background 19307 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19308 * 19309 * @param tintMode the blending mode used to apply the tint, may be 19310 * {@code null} to clear tint 19311 * @attr ref android.R.styleable#View_foregroundTintMode 19312 * @see #getForegroundTintMode() 19313 * @see Drawable#setTintMode(PorterDuff.Mode) 19314 */ 19315 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19316 if (mForegroundInfo == null) { 19317 mForegroundInfo = new ForegroundInfo(); 19318 } 19319 if (mForegroundInfo.mTintInfo == null) { 19320 mForegroundInfo.mTintInfo = new TintInfo(); 19321 } 19322 mForegroundInfo.mTintInfo.mTintMode = tintMode; 19323 mForegroundInfo.mTintInfo.mHasTintMode = true; 19324 19325 applyForegroundTint(); 19326 } 19327 19328 /** 19329 * Return the blending mode used to apply the tint to the foreground 19330 * drawable, if specified. 19331 * 19332 * @return the blending mode used to apply the tint to the foreground 19333 * drawable 19334 * @attr ref android.R.styleable#View_foregroundTintMode 19335 * @see #setForegroundTintMode(PorterDuff.Mode) 19336 */ 19337 @Nullable 19338 public PorterDuff.Mode getForegroundTintMode() { 19339 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19340 ? mForegroundInfo.mTintInfo.mTintMode : null; 19341 } 19342 19343 private void applyForegroundTint() { 19344 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 19345 && mForegroundInfo.mTintInfo != null) { 19346 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 19347 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19348 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 19349 19350 if (tintInfo.mHasTintList) { 19351 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 19352 } 19353 19354 if (tintInfo.mHasTintMode) { 19355 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 19356 } 19357 19358 // The drawable (or one of its children) may not have been 19359 // stateful before applying the tint, so let's try again. 19360 if (mForegroundInfo.mDrawable.isStateful()) { 19361 mForegroundInfo.mDrawable.setState(getDrawableState()); 19362 } 19363 } 19364 } 19365 } 19366 19367 /** 19368 * Draw any foreground content for this view. 19369 * 19370 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 19371 * drawable or other view-specific decorations. The foreground is drawn on top of the 19372 * primary view content.</p> 19373 * 19374 * @param canvas canvas to draw into 19375 */ 19376 public void onDrawForeground(Canvas canvas) { 19377 onDrawScrollIndicators(canvas); 19378 onDrawScrollBars(canvas); 19379 19380 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19381 if (foreground != null) { 19382 if (mForegroundInfo.mBoundsChanged) { 19383 mForegroundInfo.mBoundsChanged = false; 19384 final Rect selfBounds = mForegroundInfo.mSelfBounds; 19385 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 19386 19387 if (mForegroundInfo.mInsidePadding) { 19388 selfBounds.set(0, 0, getWidth(), getHeight()); 19389 } else { 19390 selfBounds.set(getPaddingLeft(), getPaddingTop(), 19391 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 19392 } 19393 19394 final int ld = getLayoutDirection(); 19395 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 19396 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 19397 foreground.setBounds(overlayBounds); 19398 } 19399 19400 foreground.draw(canvas); 19401 } 19402 } 19403 19404 /** 19405 * Sets the padding. The view may add on the space required to display 19406 * the scrollbars, depending on the style and visibility of the scrollbars. 19407 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 19408 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 19409 * from the values set in this call. 19410 * 19411 * @attr ref android.R.styleable#View_padding 19412 * @attr ref android.R.styleable#View_paddingBottom 19413 * @attr ref android.R.styleable#View_paddingLeft 19414 * @attr ref android.R.styleable#View_paddingRight 19415 * @attr ref android.R.styleable#View_paddingTop 19416 * @param left the left padding in pixels 19417 * @param top the top padding in pixels 19418 * @param right the right padding in pixels 19419 * @param bottom the bottom padding in pixels 19420 */ 19421 public void setPadding(int left, int top, int right, int bottom) { 19422 resetResolvedPaddingInternal(); 19423 19424 mUserPaddingStart = UNDEFINED_PADDING; 19425 mUserPaddingEnd = UNDEFINED_PADDING; 19426 19427 mUserPaddingLeftInitial = left; 19428 mUserPaddingRightInitial = right; 19429 19430 mLeftPaddingDefined = true; 19431 mRightPaddingDefined = true; 19432 19433 internalSetPadding(left, top, right, bottom); 19434 } 19435 19436 /** 19437 * @hide 19438 */ 19439 protected void internalSetPadding(int left, int top, int right, int bottom) { 19440 mUserPaddingLeft = left; 19441 mUserPaddingRight = right; 19442 mUserPaddingBottom = bottom; 19443 19444 final int viewFlags = mViewFlags; 19445 boolean changed = false; 19446 19447 // Common case is there are no scroll bars. 19448 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 19449 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 19450 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 19451 ? 0 : getVerticalScrollbarWidth(); 19452 switch (mVerticalScrollbarPosition) { 19453 case SCROLLBAR_POSITION_DEFAULT: 19454 if (isLayoutRtl()) { 19455 left += offset; 19456 } else { 19457 right += offset; 19458 } 19459 break; 19460 case SCROLLBAR_POSITION_RIGHT: 19461 right += offset; 19462 break; 19463 case SCROLLBAR_POSITION_LEFT: 19464 left += offset; 19465 break; 19466 } 19467 } 19468 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 19469 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 19470 ? 0 : getHorizontalScrollbarHeight(); 19471 } 19472 } 19473 19474 if (mPaddingLeft != left) { 19475 changed = true; 19476 mPaddingLeft = left; 19477 } 19478 if (mPaddingTop != top) { 19479 changed = true; 19480 mPaddingTop = top; 19481 } 19482 if (mPaddingRight != right) { 19483 changed = true; 19484 mPaddingRight = right; 19485 } 19486 if (mPaddingBottom != bottom) { 19487 changed = true; 19488 mPaddingBottom = bottom; 19489 } 19490 19491 if (changed) { 19492 requestLayout(); 19493 invalidateOutline(); 19494 } 19495 } 19496 19497 /** 19498 * Sets the relative padding. The view may add on the space required to display 19499 * the scrollbars, depending on the style and visibility of the scrollbars. 19500 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 19501 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 19502 * from the values set in this call. 19503 * 19504 * @attr ref android.R.styleable#View_padding 19505 * @attr ref android.R.styleable#View_paddingBottom 19506 * @attr ref android.R.styleable#View_paddingStart 19507 * @attr ref android.R.styleable#View_paddingEnd 19508 * @attr ref android.R.styleable#View_paddingTop 19509 * @param start the start padding in pixels 19510 * @param top the top padding in pixels 19511 * @param end the end padding in pixels 19512 * @param bottom the bottom padding in pixels 19513 */ 19514 public void setPaddingRelative(int start, int top, int end, int bottom) { 19515 resetResolvedPaddingInternal(); 19516 19517 mUserPaddingStart = start; 19518 mUserPaddingEnd = end; 19519 mLeftPaddingDefined = true; 19520 mRightPaddingDefined = true; 19521 19522 switch(getLayoutDirection()) { 19523 case LAYOUT_DIRECTION_RTL: 19524 mUserPaddingLeftInitial = end; 19525 mUserPaddingRightInitial = start; 19526 internalSetPadding(end, top, start, bottom); 19527 break; 19528 case LAYOUT_DIRECTION_LTR: 19529 default: 19530 mUserPaddingLeftInitial = start; 19531 mUserPaddingRightInitial = end; 19532 internalSetPadding(start, top, end, bottom); 19533 } 19534 } 19535 19536 /** 19537 * Returns the top padding of this view. 19538 * 19539 * @return the top padding in pixels 19540 */ 19541 public int getPaddingTop() { 19542 return mPaddingTop; 19543 } 19544 19545 /** 19546 * Returns the bottom padding of this view. If there are inset and enabled 19547 * scrollbars, this value may include the space required to display the 19548 * scrollbars as well. 19549 * 19550 * @return the bottom padding in pixels 19551 */ 19552 public int getPaddingBottom() { 19553 return mPaddingBottom; 19554 } 19555 19556 /** 19557 * Returns the left padding of this view. If there are inset and enabled 19558 * scrollbars, this value may include the space required to display the 19559 * scrollbars as well. 19560 * 19561 * @return the left padding in pixels 19562 */ 19563 public int getPaddingLeft() { 19564 if (!isPaddingResolved()) { 19565 resolvePadding(); 19566 } 19567 return mPaddingLeft; 19568 } 19569 19570 /** 19571 * Returns the start padding of this view depending on its resolved layout direction. 19572 * If there are inset and enabled scrollbars, this value may include the space 19573 * required to display the scrollbars as well. 19574 * 19575 * @return the start padding in pixels 19576 */ 19577 public int getPaddingStart() { 19578 if (!isPaddingResolved()) { 19579 resolvePadding(); 19580 } 19581 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19582 mPaddingRight : mPaddingLeft; 19583 } 19584 19585 /** 19586 * Returns the right padding of this view. If there are inset and enabled 19587 * scrollbars, this value may include the space required to display the 19588 * scrollbars as well. 19589 * 19590 * @return the right padding in pixels 19591 */ 19592 public int getPaddingRight() { 19593 if (!isPaddingResolved()) { 19594 resolvePadding(); 19595 } 19596 return mPaddingRight; 19597 } 19598 19599 /** 19600 * Returns the end padding of this view depending on its resolved layout direction. 19601 * If there are inset and enabled scrollbars, this value may include the space 19602 * required to display the scrollbars as well. 19603 * 19604 * @return the end padding in pixels 19605 */ 19606 public int getPaddingEnd() { 19607 if (!isPaddingResolved()) { 19608 resolvePadding(); 19609 } 19610 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19611 mPaddingLeft : mPaddingRight; 19612 } 19613 19614 /** 19615 * Return if the padding has been set through relative values 19616 * {@link #setPaddingRelative(int, int, int, int)} or through 19617 * @attr ref android.R.styleable#View_paddingStart or 19618 * @attr ref android.R.styleable#View_paddingEnd 19619 * 19620 * @return true if the padding is relative or false if it is not. 19621 */ 19622 public boolean isPaddingRelative() { 19623 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 19624 } 19625 19626 Insets computeOpticalInsets() { 19627 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 19628 } 19629 19630 /** 19631 * @hide 19632 */ 19633 public void resetPaddingToInitialValues() { 19634 if (isRtlCompatibilityMode()) { 19635 mPaddingLeft = mUserPaddingLeftInitial; 19636 mPaddingRight = mUserPaddingRightInitial; 19637 return; 19638 } 19639 if (isLayoutRtl()) { 19640 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 19641 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 19642 } else { 19643 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 19644 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 19645 } 19646 } 19647 19648 /** 19649 * @hide 19650 */ 19651 public Insets getOpticalInsets() { 19652 if (mLayoutInsets == null) { 19653 mLayoutInsets = computeOpticalInsets(); 19654 } 19655 return mLayoutInsets; 19656 } 19657 19658 /** 19659 * Set this view's optical insets. 19660 * 19661 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 19662 * property. Views that compute their own optical insets should call it as part of measurement. 19663 * This method does not request layout. If you are setting optical insets outside of 19664 * measure/layout itself you will want to call requestLayout() yourself. 19665 * </p> 19666 * @hide 19667 */ 19668 public void setOpticalInsets(Insets insets) { 19669 mLayoutInsets = insets; 19670 } 19671 19672 /** 19673 * Changes the selection state of this view. A view can be selected or not. 19674 * Note that selection is not the same as focus. Views are typically 19675 * selected in the context of an AdapterView like ListView or GridView; 19676 * the selected view is the view that is highlighted. 19677 * 19678 * @param selected true if the view must be selected, false otherwise 19679 */ 19680 public void setSelected(boolean selected) { 19681 //noinspection DoubleNegation 19682 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 19683 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 19684 if (!selected) resetPressedState(); 19685 invalidate(true); 19686 refreshDrawableState(); 19687 dispatchSetSelected(selected); 19688 if (selected) { 19689 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 19690 } else { 19691 notifyViewAccessibilityStateChangedIfNeeded( 19692 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 19693 } 19694 } 19695 } 19696 19697 /** 19698 * Dispatch setSelected to all of this View's children. 19699 * 19700 * @see #setSelected(boolean) 19701 * 19702 * @param selected The new selected state 19703 */ 19704 protected void dispatchSetSelected(boolean selected) { 19705 } 19706 19707 /** 19708 * Indicates the selection state of this view. 19709 * 19710 * @return true if the view is selected, false otherwise 19711 */ 19712 @ViewDebug.ExportedProperty 19713 public boolean isSelected() { 19714 return (mPrivateFlags & PFLAG_SELECTED) != 0; 19715 } 19716 19717 /** 19718 * Changes the activated state of this view. A view can be activated or not. 19719 * Note that activation is not the same as selection. Selection is 19720 * a transient property, representing the view (hierarchy) the user is 19721 * currently interacting with. Activation is a longer-term state that the 19722 * user can move views in and out of. For example, in a list view with 19723 * single or multiple selection enabled, the views in the current selection 19724 * set are activated. (Um, yeah, we are deeply sorry about the terminology 19725 * here.) The activated state is propagated down to children of the view it 19726 * is set on. 19727 * 19728 * @param activated true if the view must be activated, false otherwise 19729 */ 19730 public void setActivated(boolean activated) { 19731 //noinspection DoubleNegation 19732 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 19733 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 19734 invalidate(true); 19735 refreshDrawableState(); 19736 dispatchSetActivated(activated); 19737 } 19738 } 19739 19740 /** 19741 * Dispatch setActivated to all of this View's children. 19742 * 19743 * @see #setActivated(boolean) 19744 * 19745 * @param activated The new activated state 19746 */ 19747 protected void dispatchSetActivated(boolean activated) { 19748 } 19749 19750 /** 19751 * Indicates the activation state of this view. 19752 * 19753 * @return true if the view is activated, false otherwise 19754 */ 19755 @ViewDebug.ExportedProperty 19756 public boolean isActivated() { 19757 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 19758 } 19759 19760 /** 19761 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 19762 * observer can be used to get notifications when global events, like 19763 * layout, happen. 19764 * 19765 * The returned ViewTreeObserver observer is not guaranteed to remain 19766 * valid for the lifetime of this View. If the caller of this method keeps 19767 * a long-lived reference to ViewTreeObserver, it should always check for 19768 * the return value of {@link ViewTreeObserver#isAlive()}. 19769 * 19770 * @return The ViewTreeObserver for this view's hierarchy. 19771 */ 19772 public ViewTreeObserver getViewTreeObserver() { 19773 if (mAttachInfo != null) { 19774 return mAttachInfo.mTreeObserver; 19775 } 19776 if (mFloatingTreeObserver == null) { 19777 mFloatingTreeObserver = new ViewTreeObserver(mContext); 19778 } 19779 return mFloatingTreeObserver; 19780 } 19781 19782 /** 19783 * <p>Finds the topmost view in the current view hierarchy.</p> 19784 * 19785 * @return the topmost view containing this view 19786 */ 19787 public View getRootView() { 19788 if (mAttachInfo != null) { 19789 final View v = mAttachInfo.mRootView; 19790 if (v != null) { 19791 return v; 19792 } 19793 } 19794 19795 View parent = this; 19796 19797 while (parent.mParent != null && parent.mParent instanceof View) { 19798 parent = (View) parent.mParent; 19799 } 19800 19801 return parent; 19802 } 19803 19804 /** 19805 * Transforms a motion event from view-local coordinates to on-screen 19806 * coordinates. 19807 * 19808 * @param ev the view-local motion event 19809 * @return false if the transformation could not be applied 19810 * @hide 19811 */ 19812 public boolean toGlobalMotionEvent(MotionEvent ev) { 19813 final AttachInfo info = mAttachInfo; 19814 if (info == null) { 19815 return false; 19816 } 19817 19818 final Matrix m = info.mTmpMatrix; 19819 m.set(Matrix.IDENTITY_MATRIX); 19820 transformMatrixToGlobal(m); 19821 ev.transform(m); 19822 return true; 19823 } 19824 19825 /** 19826 * Transforms a motion event from on-screen coordinates to view-local 19827 * coordinates. 19828 * 19829 * @param ev the on-screen motion event 19830 * @return false if the transformation could not be applied 19831 * @hide 19832 */ 19833 public boolean toLocalMotionEvent(MotionEvent ev) { 19834 final AttachInfo info = mAttachInfo; 19835 if (info == null) { 19836 return false; 19837 } 19838 19839 final Matrix m = info.mTmpMatrix; 19840 m.set(Matrix.IDENTITY_MATRIX); 19841 transformMatrixToLocal(m); 19842 ev.transform(m); 19843 return true; 19844 } 19845 19846 /** 19847 * Modifies the input matrix such that it maps view-local coordinates to 19848 * on-screen coordinates. 19849 * 19850 * @param m input matrix to modify 19851 * @hide 19852 */ 19853 public void transformMatrixToGlobal(Matrix m) { 19854 final ViewParent parent = mParent; 19855 if (parent instanceof View) { 19856 final View vp = (View) parent; 19857 vp.transformMatrixToGlobal(m); 19858 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 19859 } else if (parent instanceof ViewRootImpl) { 19860 final ViewRootImpl vr = (ViewRootImpl) parent; 19861 vr.transformMatrixToGlobal(m); 19862 m.preTranslate(0, -vr.mCurScrollY); 19863 } 19864 19865 m.preTranslate(mLeft, mTop); 19866 19867 if (!hasIdentityMatrix()) { 19868 m.preConcat(getMatrix()); 19869 } 19870 } 19871 19872 /** 19873 * Modifies the input matrix such that it maps on-screen coordinates to 19874 * view-local coordinates. 19875 * 19876 * @param m input matrix to modify 19877 * @hide 19878 */ 19879 public void transformMatrixToLocal(Matrix m) { 19880 final ViewParent parent = mParent; 19881 if (parent instanceof View) { 19882 final View vp = (View) parent; 19883 vp.transformMatrixToLocal(m); 19884 m.postTranslate(vp.mScrollX, vp.mScrollY); 19885 } else if (parent instanceof ViewRootImpl) { 19886 final ViewRootImpl vr = (ViewRootImpl) parent; 19887 vr.transformMatrixToLocal(m); 19888 m.postTranslate(0, vr.mCurScrollY); 19889 } 19890 19891 m.postTranslate(-mLeft, -mTop); 19892 19893 if (!hasIdentityMatrix()) { 19894 m.postConcat(getInverseMatrix()); 19895 } 19896 } 19897 19898 /** 19899 * @hide 19900 */ 19901 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 19902 @ViewDebug.IntToString(from = 0, to = "x"), 19903 @ViewDebug.IntToString(from = 1, to = "y") 19904 }) 19905 public int[] getLocationOnScreen() { 19906 int[] location = new int[2]; 19907 getLocationOnScreen(location); 19908 return location; 19909 } 19910 19911 /** 19912 * <p>Computes the coordinates of this view on the screen. The argument 19913 * must be an array of two integers. After the method returns, the array 19914 * contains the x and y location in that order.</p> 19915 * 19916 * @param outLocation an array of two integers in which to hold the coordinates 19917 */ 19918 public void getLocationOnScreen(@Size(2) int[] outLocation) { 19919 getLocationInWindow(outLocation); 19920 19921 final AttachInfo info = mAttachInfo; 19922 if (info != null) { 19923 outLocation[0] += info.mWindowLeft; 19924 outLocation[1] += info.mWindowTop; 19925 } 19926 } 19927 19928 /** 19929 * <p>Computes the coordinates of this view in its window. The argument 19930 * must be an array of two integers. After the method returns, the array 19931 * contains the x and y location in that order.</p> 19932 * 19933 * @param outLocation an array of two integers in which to hold the coordinates 19934 */ 19935 public void getLocationInWindow(@Size(2) int[] outLocation) { 19936 if (outLocation == null || outLocation.length < 2) { 19937 throw new IllegalArgumentException("outLocation must be an array of two integers"); 19938 } 19939 19940 outLocation[0] = 0; 19941 outLocation[1] = 0; 19942 19943 transformFromViewToWindowSpace(outLocation); 19944 } 19945 19946 /** @hide */ 19947 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 19948 if (inOutLocation == null || inOutLocation.length < 2) { 19949 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 19950 } 19951 19952 if (mAttachInfo == null) { 19953 // When the view is not attached to a window, this method does not make sense 19954 inOutLocation[0] = inOutLocation[1] = 0; 19955 return; 19956 } 19957 19958 float position[] = mAttachInfo.mTmpTransformLocation; 19959 position[0] = inOutLocation[0]; 19960 position[1] = inOutLocation[1]; 19961 19962 if (!hasIdentityMatrix()) { 19963 getMatrix().mapPoints(position); 19964 } 19965 19966 position[0] += mLeft; 19967 position[1] += mTop; 19968 19969 ViewParent viewParent = mParent; 19970 while (viewParent instanceof View) { 19971 final View view = (View) viewParent; 19972 19973 position[0] -= view.mScrollX; 19974 position[1] -= view.mScrollY; 19975 19976 if (!view.hasIdentityMatrix()) { 19977 view.getMatrix().mapPoints(position); 19978 } 19979 19980 position[0] += view.mLeft; 19981 position[1] += view.mTop; 19982 19983 viewParent = view.mParent; 19984 } 19985 19986 if (viewParent instanceof ViewRootImpl) { 19987 // *cough* 19988 final ViewRootImpl vr = (ViewRootImpl) viewParent; 19989 position[1] -= vr.mCurScrollY; 19990 } 19991 19992 inOutLocation[0] = Math.round(position[0]); 19993 inOutLocation[1] = Math.round(position[1]); 19994 } 19995 19996 /** 19997 * {@hide} 19998 * @param id the id of the view to be found 19999 * @return the view of the specified id, null if cannot be found 20000 */ 20001 protected View findViewTraversal(@IdRes int id) { 20002 if (id == mID) { 20003 return this; 20004 } 20005 return null; 20006 } 20007 20008 /** 20009 * {@hide} 20010 * @param tag the tag of the view to be found 20011 * @return the view of specified tag, null if cannot be found 20012 */ 20013 protected View findViewWithTagTraversal(Object tag) { 20014 if (tag != null && tag.equals(mTag)) { 20015 return this; 20016 } 20017 return null; 20018 } 20019 20020 /** 20021 * {@hide} 20022 * @param predicate The predicate to evaluate. 20023 * @param childToSkip If not null, ignores this child during the recursive traversal. 20024 * @return The first view that matches the predicate or null. 20025 */ 20026 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 20027 if (predicate.apply(this)) { 20028 return this; 20029 } 20030 return null; 20031 } 20032 20033 /** 20034 * Look for a child view with the given id. If this view has the given 20035 * id, return this view. 20036 * 20037 * @param id The id to search for. 20038 * @return The view that has the given id in the hierarchy or null 20039 */ 20040 @Nullable 20041 public final View findViewById(@IdRes int id) { 20042 if (id < 0) { 20043 return null; 20044 } 20045 return findViewTraversal(id); 20046 } 20047 20048 /** 20049 * Finds a view by its unuque and stable accessibility id. 20050 * 20051 * @param accessibilityId The searched accessibility id. 20052 * @return The found view. 20053 */ 20054 final View findViewByAccessibilityId(int accessibilityId) { 20055 if (accessibilityId < 0) { 20056 return null; 20057 } 20058 View view = findViewByAccessibilityIdTraversal(accessibilityId); 20059 if (view != null) { 20060 return view.includeForAccessibility() ? view : null; 20061 } 20062 return null; 20063 } 20064 20065 /** 20066 * Performs the traversal to find a view by its unuque and stable accessibility id. 20067 * 20068 * <strong>Note:</strong>This method does not stop at the root namespace 20069 * boundary since the user can touch the screen at an arbitrary location 20070 * potentially crossing the root namespace bounday which will send an 20071 * accessibility event to accessibility services and they should be able 20072 * to obtain the event source. Also accessibility ids are guaranteed to be 20073 * unique in the window. 20074 * 20075 * @param accessibilityId The accessibility id. 20076 * @return The found view. 20077 * 20078 * @hide 20079 */ 20080 public View findViewByAccessibilityIdTraversal(int accessibilityId) { 20081 if (getAccessibilityViewId() == accessibilityId) { 20082 return this; 20083 } 20084 return null; 20085 } 20086 20087 /** 20088 * Look for a child view with the given tag. If this view has the given 20089 * tag, return this view. 20090 * 20091 * @param tag The tag to search for, using "tag.equals(getTag())". 20092 * @return The View that has the given tag in the hierarchy or null 20093 */ 20094 public final View findViewWithTag(Object tag) { 20095 if (tag == null) { 20096 return null; 20097 } 20098 return findViewWithTagTraversal(tag); 20099 } 20100 20101 /** 20102 * {@hide} 20103 * Look for a child view that matches the specified predicate. 20104 * If this view matches the predicate, return this view. 20105 * 20106 * @param predicate The predicate to evaluate. 20107 * @return The first view that matches the predicate or null. 20108 */ 20109 public final View findViewByPredicate(Predicate<View> predicate) { 20110 return findViewByPredicateTraversal(predicate, null); 20111 } 20112 20113 /** 20114 * {@hide} 20115 * Look for a child view that matches the specified predicate, 20116 * starting with the specified view and its descendents and then 20117 * recusively searching the ancestors and siblings of that view 20118 * until this view is reached. 20119 * 20120 * This method is useful in cases where the predicate does not match 20121 * a single unique view (perhaps multiple views use the same id) 20122 * and we are trying to find the view that is "closest" in scope to the 20123 * starting view. 20124 * 20125 * @param start The view to start from. 20126 * @param predicate The predicate to evaluate. 20127 * @return The first view that matches the predicate or null. 20128 */ 20129 public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) { 20130 View childToSkip = null; 20131 for (;;) { 20132 View view = start.findViewByPredicateTraversal(predicate, childToSkip); 20133 if (view != null || start == this) { 20134 return view; 20135 } 20136 20137 ViewParent parent = start.getParent(); 20138 if (parent == null || !(parent instanceof View)) { 20139 return null; 20140 } 20141 20142 childToSkip = start; 20143 start = (View) parent; 20144 } 20145 } 20146 20147 /** 20148 * Sets the identifier for this view. The identifier does not have to be 20149 * unique in this view's hierarchy. The identifier should be a positive 20150 * number. 20151 * 20152 * @see #NO_ID 20153 * @see #getId() 20154 * @see #findViewById(int) 20155 * 20156 * @param id a number used to identify the view 20157 * 20158 * @attr ref android.R.styleable#View_id 20159 */ 20160 public void setId(@IdRes int id) { 20161 mID = id; 20162 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 20163 mID = generateViewId(); 20164 } 20165 } 20166 20167 /** 20168 * {@hide} 20169 * 20170 * @param isRoot true if the view belongs to the root namespace, false 20171 * otherwise 20172 */ 20173 public void setIsRootNamespace(boolean isRoot) { 20174 if (isRoot) { 20175 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 20176 } else { 20177 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 20178 } 20179 } 20180 20181 /** 20182 * {@hide} 20183 * 20184 * @return true if the view belongs to the root namespace, false otherwise 20185 */ 20186 public boolean isRootNamespace() { 20187 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 20188 } 20189 20190 /** 20191 * Returns this view's identifier. 20192 * 20193 * @return a positive integer used to identify the view or {@link #NO_ID} 20194 * if the view has no ID 20195 * 20196 * @see #setId(int) 20197 * @see #findViewById(int) 20198 * @attr ref android.R.styleable#View_id 20199 */ 20200 @IdRes 20201 @ViewDebug.CapturedViewProperty 20202 public int getId() { 20203 return mID; 20204 } 20205 20206 /** 20207 * Returns this view's tag. 20208 * 20209 * @return the Object stored in this view as a tag, or {@code null} if not 20210 * set 20211 * 20212 * @see #setTag(Object) 20213 * @see #getTag(int) 20214 */ 20215 @ViewDebug.ExportedProperty 20216 public Object getTag() { 20217 return mTag; 20218 } 20219 20220 /** 20221 * Sets the tag associated with this view. A tag can be used to mark 20222 * a view in its hierarchy and does not have to be unique within the 20223 * hierarchy. Tags can also be used to store data within a view without 20224 * resorting to another data structure. 20225 * 20226 * @param tag an Object to tag the view with 20227 * 20228 * @see #getTag() 20229 * @see #setTag(int, Object) 20230 */ 20231 public void setTag(final Object tag) { 20232 mTag = tag; 20233 } 20234 20235 /** 20236 * Returns the tag associated with this view and the specified key. 20237 * 20238 * @param key The key identifying the tag 20239 * 20240 * @return the Object stored in this view as a tag, or {@code null} if not 20241 * set 20242 * 20243 * @see #setTag(int, Object) 20244 * @see #getTag() 20245 */ 20246 public Object getTag(int key) { 20247 if (mKeyedTags != null) return mKeyedTags.get(key); 20248 return null; 20249 } 20250 20251 /** 20252 * Sets a tag associated with this view and a key. A tag can be used 20253 * to mark a view in its hierarchy and does not have to be unique within 20254 * the hierarchy. Tags can also be used to store data within a view 20255 * without resorting to another data structure. 20256 * 20257 * The specified key should be an id declared in the resources of the 20258 * application to ensure it is unique (see the <a 20259 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 20260 * Keys identified as belonging to 20261 * the Android framework or not associated with any package will cause 20262 * an {@link IllegalArgumentException} to be thrown. 20263 * 20264 * @param key The key identifying the tag 20265 * @param tag An Object to tag the view with 20266 * 20267 * @throws IllegalArgumentException If they specified key is not valid 20268 * 20269 * @see #setTag(Object) 20270 * @see #getTag(int) 20271 */ 20272 public void setTag(int key, final Object tag) { 20273 // If the package id is 0x00 or 0x01, it's either an undefined package 20274 // or a framework id 20275 if ((key >>> 24) < 2) { 20276 throw new IllegalArgumentException("The key must be an application-specific " 20277 + "resource id."); 20278 } 20279 20280 setKeyedTag(key, tag); 20281 } 20282 20283 /** 20284 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 20285 * framework id. 20286 * 20287 * @hide 20288 */ 20289 public void setTagInternal(int key, Object tag) { 20290 if ((key >>> 24) != 0x1) { 20291 throw new IllegalArgumentException("The key must be a framework-specific " 20292 + "resource id."); 20293 } 20294 20295 setKeyedTag(key, tag); 20296 } 20297 20298 private void setKeyedTag(int key, Object tag) { 20299 if (mKeyedTags == null) { 20300 mKeyedTags = new SparseArray<Object>(2); 20301 } 20302 20303 mKeyedTags.put(key, tag); 20304 } 20305 20306 /** 20307 * Prints information about this view in the log output, with the tag 20308 * {@link #VIEW_LOG_TAG}. 20309 * 20310 * @hide 20311 */ 20312 public void debug() { 20313 debug(0); 20314 } 20315 20316 /** 20317 * Prints information about this view in the log output, with the tag 20318 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 20319 * indentation defined by the <code>depth</code>. 20320 * 20321 * @param depth the indentation level 20322 * 20323 * @hide 20324 */ 20325 protected void debug(int depth) { 20326 String output = debugIndent(depth - 1); 20327 20328 output += "+ " + this; 20329 int id = getId(); 20330 if (id != -1) { 20331 output += " (id=" + id + ")"; 20332 } 20333 Object tag = getTag(); 20334 if (tag != null) { 20335 output += " (tag=" + tag + ")"; 20336 } 20337 Log.d(VIEW_LOG_TAG, output); 20338 20339 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 20340 output = debugIndent(depth) + " FOCUSED"; 20341 Log.d(VIEW_LOG_TAG, output); 20342 } 20343 20344 output = debugIndent(depth); 20345 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 20346 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 20347 + "} "; 20348 Log.d(VIEW_LOG_TAG, output); 20349 20350 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 20351 || mPaddingBottom != 0) { 20352 output = debugIndent(depth); 20353 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 20354 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 20355 Log.d(VIEW_LOG_TAG, output); 20356 } 20357 20358 output = debugIndent(depth); 20359 output += "mMeasureWidth=" + mMeasuredWidth + 20360 " mMeasureHeight=" + mMeasuredHeight; 20361 Log.d(VIEW_LOG_TAG, output); 20362 20363 output = debugIndent(depth); 20364 if (mLayoutParams == null) { 20365 output += "BAD! no layout params"; 20366 } else { 20367 output = mLayoutParams.debug(output); 20368 } 20369 Log.d(VIEW_LOG_TAG, output); 20370 20371 output = debugIndent(depth); 20372 output += "flags={"; 20373 output += View.printFlags(mViewFlags); 20374 output += "}"; 20375 Log.d(VIEW_LOG_TAG, output); 20376 20377 output = debugIndent(depth); 20378 output += "privateFlags={"; 20379 output += View.printPrivateFlags(mPrivateFlags); 20380 output += "}"; 20381 Log.d(VIEW_LOG_TAG, output); 20382 } 20383 20384 /** 20385 * Creates a string of whitespaces used for indentation. 20386 * 20387 * @param depth the indentation level 20388 * @return a String containing (depth * 2 + 3) * 2 white spaces 20389 * 20390 * @hide 20391 */ 20392 protected static String debugIndent(int depth) { 20393 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 20394 for (int i = 0; i < (depth * 2) + 3; i++) { 20395 spaces.append(' ').append(' '); 20396 } 20397 return spaces.toString(); 20398 } 20399 20400 /** 20401 * <p>Return the offset of the widget's text baseline from the widget's top 20402 * boundary. If this widget does not support baseline alignment, this 20403 * method returns -1. </p> 20404 * 20405 * @return the offset of the baseline within the widget's bounds or -1 20406 * if baseline alignment is not supported 20407 */ 20408 @ViewDebug.ExportedProperty(category = "layout") 20409 public int getBaseline() { 20410 return -1; 20411 } 20412 20413 /** 20414 * Returns whether the view hierarchy is currently undergoing a layout pass. This 20415 * information is useful to avoid situations such as calling {@link #requestLayout()} during 20416 * a layout pass. 20417 * 20418 * @return whether the view hierarchy is currently undergoing a layout pass 20419 */ 20420 public boolean isInLayout() { 20421 ViewRootImpl viewRoot = getViewRootImpl(); 20422 return (viewRoot != null && viewRoot.isInLayout()); 20423 } 20424 20425 /** 20426 * Call this when something has changed which has invalidated the 20427 * layout of this view. This will schedule a layout pass of the view 20428 * tree. This should not be called while the view hierarchy is currently in a layout 20429 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 20430 * end of the current layout pass (and then layout will run again) or after the current 20431 * frame is drawn and the next layout occurs. 20432 * 20433 * <p>Subclasses which override this method should call the superclass method to 20434 * handle possible request-during-layout errors correctly.</p> 20435 */ 20436 @CallSuper 20437 public void requestLayout() { 20438 if (mMeasureCache != null) mMeasureCache.clear(); 20439 20440 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 20441 // Only trigger request-during-layout logic if this is the view requesting it, 20442 // not the views in its parent hierarchy 20443 ViewRootImpl viewRoot = getViewRootImpl(); 20444 if (viewRoot != null && viewRoot.isInLayout()) { 20445 if (!viewRoot.requestLayoutDuringLayout(this)) { 20446 return; 20447 } 20448 } 20449 mAttachInfo.mViewRequestingLayout = this; 20450 } 20451 20452 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20453 mPrivateFlags |= PFLAG_INVALIDATED; 20454 20455 if (mParent != null && !mParent.isLayoutRequested()) { 20456 mParent.requestLayout(); 20457 } 20458 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 20459 mAttachInfo.mViewRequestingLayout = null; 20460 } 20461 } 20462 20463 /** 20464 * Forces this view to be laid out during the next layout pass. 20465 * This method does not call requestLayout() or forceLayout() 20466 * on the parent. 20467 */ 20468 public void forceLayout() { 20469 if (mMeasureCache != null) mMeasureCache.clear(); 20470 20471 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20472 mPrivateFlags |= PFLAG_INVALIDATED; 20473 } 20474 20475 /** 20476 * <p> 20477 * This is called to find out how big a view should be. The parent 20478 * supplies constraint information in the width and height parameters. 20479 * </p> 20480 * 20481 * <p> 20482 * The actual measurement work of a view is performed in 20483 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 20484 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 20485 * </p> 20486 * 20487 * 20488 * @param widthMeasureSpec Horizontal space requirements as imposed by the 20489 * parent 20490 * @param heightMeasureSpec Vertical space requirements as imposed by the 20491 * parent 20492 * 20493 * @see #onMeasure(int, int) 20494 */ 20495 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 20496 boolean optical = isLayoutModeOptical(this); 20497 if (optical != isLayoutModeOptical(mParent)) { 20498 Insets insets = getOpticalInsets(); 20499 int oWidth = insets.left + insets.right; 20500 int oHeight = insets.top + insets.bottom; 20501 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 20502 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 20503 } 20504 20505 // Suppress sign extension for the low bytes 20506 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 20507 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 20508 20509 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 20510 20511 // Optimize layout by avoiding an extra EXACTLY pass when the view is 20512 // already measured as the correct size. In API 23 and below, this 20513 // extra pass is required to make LinearLayout re-distribute weight. 20514 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 20515 || heightMeasureSpec != mOldHeightMeasureSpec; 20516 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 20517 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 20518 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 20519 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 20520 final boolean needsLayout = specChanged 20521 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 20522 20523 if (forceLayout || needsLayout) { 20524 // first clears the measured dimension flag 20525 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 20526 20527 resolveRtlPropertiesIfNeeded(); 20528 20529 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 20530 if (cacheIndex < 0 || sIgnoreMeasureCache) { 20531 // measure ourselves, this should set the measured dimension flag back 20532 onMeasure(widthMeasureSpec, heightMeasureSpec); 20533 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20534 } else { 20535 long value = mMeasureCache.valueAt(cacheIndex); 20536 // Casting a long to int drops the high 32 bits, no mask needed 20537 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 20538 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20539 } 20540 20541 // flag not set, setMeasuredDimension() was not invoked, we raise 20542 // an exception to warn the developer 20543 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 20544 throw new IllegalStateException("View with id " + getId() + ": " 20545 + getClass().getName() + "#onMeasure() did not set the" 20546 + " measured dimension by calling" 20547 + " setMeasuredDimension()"); 20548 } 20549 20550 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 20551 } 20552 20553 mOldWidthMeasureSpec = widthMeasureSpec; 20554 mOldHeightMeasureSpec = heightMeasureSpec; 20555 20556 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 20557 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 20558 } 20559 20560 /** 20561 * <p> 20562 * Measure the view and its content to determine the measured width and the 20563 * measured height. This method is invoked by {@link #measure(int, int)} and 20564 * should be overridden by subclasses to provide accurate and efficient 20565 * measurement of their contents. 20566 * </p> 20567 * 20568 * <p> 20569 * <strong>CONTRACT:</strong> When overriding this method, you 20570 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 20571 * measured width and height of this view. Failure to do so will trigger an 20572 * <code>IllegalStateException</code>, thrown by 20573 * {@link #measure(int, int)}. Calling the superclass' 20574 * {@link #onMeasure(int, int)} is a valid use. 20575 * </p> 20576 * 20577 * <p> 20578 * The base class implementation of measure defaults to the background size, 20579 * unless a larger size is allowed by the MeasureSpec. Subclasses should 20580 * override {@link #onMeasure(int, int)} to provide better measurements of 20581 * their content. 20582 * </p> 20583 * 20584 * <p> 20585 * If this method is overridden, it is the subclass's responsibility to make 20586 * sure the measured height and width are at least the view's minimum height 20587 * and width ({@link #getSuggestedMinimumHeight()} and 20588 * {@link #getSuggestedMinimumWidth()}). 20589 * </p> 20590 * 20591 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 20592 * The requirements are encoded with 20593 * {@link android.view.View.MeasureSpec}. 20594 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 20595 * The requirements are encoded with 20596 * {@link android.view.View.MeasureSpec}. 20597 * 20598 * @see #getMeasuredWidth() 20599 * @see #getMeasuredHeight() 20600 * @see #setMeasuredDimension(int, int) 20601 * @see #getSuggestedMinimumHeight() 20602 * @see #getSuggestedMinimumWidth() 20603 * @see android.view.View.MeasureSpec#getMode(int) 20604 * @see android.view.View.MeasureSpec#getSize(int) 20605 */ 20606 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 20607 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 20608 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 20609 } 20610 20611 /** 20612 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 20613 * measured width and measured height. Failing to do so will trigger an 20614 * exception at measurement time.</p> 20615 * 20616 * @param measuredWidth The measured width of this view. May be a complex 20617 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20618 * {@link #MEASURED_STATE_TOO_SMALL}. 20619 * @param measuredHeight The measured height of this view. May be a complex 20620 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20621 * {@link #MEASURED_STATE_TOO_SMALL}. 20622 */ 20623 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 20624 boolean optical = isLayoutModeOptical(this); 20625 if (optical != isLayoutModeOptical(mParent)) { 20626 Insets insets = getOpticalInsets(); 20627 int opticalWidth = insets.left + insets.right; 20628 int opticalHeight = insets.top + insets.bottom; 20629 20630 measuredWidth += optical ? opticalWidth : -opticalWidth; 20631 measuredHeight += optical ? opticalHeight : -opticalHeight; 20632 } 20633 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 20634 } 20635 20636 /** 20637 * Sets the measured dimension without extra processing for things like optical bounds. 20638 * Useful for reapplying consistent values that have already been cooked with adjustments 20639 * for optical bounds, etc. such as those from the measurement cache. 20640 * 20641 * @param measuredWidth The measured width of this view. May be a complex 20642 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20643 * {@link #MEASURED_STATE_TOO_SMALL}. 20644 * @param measuredHeight The measured height of this view. May be a complex 20645 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20646 * {@link #MEASURED_STATE_TOO_SMALL}. 20647 */ 20648 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 20649 mMeasuredWidth = measuredWidth; 20650 mMeasuredHeight = measuredHeight; 20651 20652 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 20653 } 20654 20655 /** 20656 * Merge two states as returned by {@link #getMeasuredState()}. 20657 * @param curState The current state as returned from a view or the result 20658 * of combining multiple views. 20659 * @param newState The new view state to combine. 20660 * @return Returns a new integer reflecting the combination of the two 20661 * states. 20662 */ 20663 public static int combineMeasuredStates(int curState, int newState) { 20664 return curState | newState; 20665 } 20666 20667 /** 20668 * Version of {@link #resolveSizeAndState(int, int, int)} 20669 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 20670 */ 20671 public static int resolveSize(int size, int measureSpec) { 20672 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 20673 } 20674 20675 /** 20676 * Utility to reconcile a desired size and state, with constraints imposed 20677 * by a MeasureSpec. Will take the desired size, unless a different size 20678 * is imposed by the constraints. The returned value is a compound integer, 20679 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 20680 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 20681 * resulting size is smaller than the size the view wants to be. 20682 * 20683 * @param size How big the view wants to be. 20684 * @param measureSpec Constraints imposed by the parent. 20685 * @param childMeasuredState Size information bit mask for the view's 20686 * children. 20687 * @return Size information bit mask as defined by 20688 * {@link #MEASURED_SIZE_MASK} and 20689 * {@link #MEASURED_STATE_TOO_SMALL}. 20690 */ 20691 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 20692 final int specMode = MeasureSpec.getMode(measureSpec); 20693 final int specSize = MeasureSpec.getSize(measureSpec); 20694 final int result; 20695 switch (specMode) { 20696 case MeasureSpec.AT_MOST: 20697 if (specSize < size) { 20698 result = specSize | MEASURED_STATE_TOO_SMALL; 20699 } else { 20700 result = size; 20701 } 20702 break; 20703 case MeasureSpec.EXACTLY: 20704 result = specSize; 20705 break; 20706 case MeasureSpec.UNSPECIFIED: 20707 default: 20708 result = size; 20709 } 20710 return result | (childMeasuredState & MEASURED_STATE_MASK); 20711 } 20712 20713 /** 20714 * Utility to return a default size. Uses the supplied size if the 20715 * MeasureSpec imposed no constraints. Will get larger if allowed 20716 * by the MeasureSpec. 20717 * 20718 * @param size Default size for this view 20719 * @param measureSpec Constraints imposed by the parent 20720 * @return The size this view should be. 20721 */ 20722 public static int getDefaultSize(int size, int measureSpec) { 20723 int result = size; 20724 int specMode = MeasureSpec.getMode(measureSpec); 20725 int specSize = MeasureSpec.getSize(measureSpec); 20726 20727 switch (specMode) { 20728 case MeasureSpec.UNSPECIFIED: 20729 result = size; 20730 break; 20731 case MeasureSpec.AT_MOST: 20732 case MeasureSpec.EXACTLY: 20733 result = specSize; 20734 break; 20735 } 20736 return result; 20737 } 20738 20739 /** 20740 * Returns the suggested minimum height that the view should use. This 20741 * returns the maximum of the view's minimum height 20742 * and the background's minimum height 20743 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 20744 * <p> 20745 * When being used in {@link #onMeasure(int, int)}, the caller should still 20746 * ensure the returned height is within the requirements of the parent. 20747 * 20748 * @return The suggested minimum height of the view. 20749 */ 20750 protected int getSuggestedMinimumHeight() { 20751 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 20752 20753 } 20754 20755 /** 20756 * Returns the suggested minimum width that the view should use. This 20757 * returns the maximum of the view's minimum width 20758 * and the background's minimum width 20759 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 20760 * <p> 20761 * When being used in {@link #onMeasure(int, int)}, the caller should still 20762 * ensure the returned width is within the requirements of the parent. 20763 * 20764 * @return The suggested minimum width of the view. 20765 */ 20766 protected int getSuggestedMinimumWidth() { 20767 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 20768 } 20769 20770 /** 20771 * Returns the minimum height of the view. 20772 * 20773 * @return the minimum height the view will try to be, in pixels 20774 * 20775 * @see #setMinimumHeight(int) 20776 * 20777 * @attr ref android.R.styleable#View_minHeight 20778 */ 20779 public int getMinimumHeight() { 20780 return mMinHeight; 20781 } 20782 20783 /** 20784 * Sets the minimum height of the view. It is not guaranteed the view will 20785 * be able to achieve this minimum height (for example, if its parent layout 20786 * constrains it with less available height). 20787 * 20788 * @param minHeight The minimum height the view will try to be, in pixels 20789 * 20790 * @see #getMinimumHeight() 20791 * 20792 * @attr ref android.R.styleable#View_minHeight 20793 */ 20794 @RemotableViewMethod 20795 public void setMinimumHeight(int minHeight) { 20796 mMinHeight = minHeight; 20797 requestLayout(); 20798 } 20799 20800 /** 20801 * Returns the minimum width of the view. 20802 * 20803 * @return the minimum width the view will try to be, in pixels 20804 * 20805 * @see #setMinimumWidth(int) 20806 * 20807 * @attr ref android.R.styleable#View_minWidth 20808 */ 20809 public int getMinimumWidth() { 20810 return mMinWidth; 20811 } 20812 20813 /** 20814 * Sets the minimum width of the view. It is not guaranteed the view will 20815 * be able to achieve this minimum width (for example, if its parent layout 20816 * constrains it with less available width). 20817 * 20818 * @param minWidth The minimum width the view will try to be, in pixels 20819 * 20820 * @see #getMinimumWidth() 20821 * 20822 * @attr ref android.R.styleable#View_minWidth 20823 */ 20824 public void setMinimumWidth(int minWidth) { 20825 mMinWidth = minWidth; 20826 requestLayout(); 20827 20828 } 20829 20830 /** 20831 * Get the animation currently associated with this view. 20832 * 20833 * @return The animation that is currently playing or 20834 * scheduled to play for this view. 20835 */ 20836 public Animation getAnimation() { 20837 return mCurrentAnimation; 20838 } 20839 20840 /** 20841 * Start the specified animation now. 20842 * 20843 * @param animation the animation to start now 20844 */ 20845 public void startAnimation(Animation animation) { 20846 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 20847 setAnimation(animation); 20848 invalidateParentCaches(); 20849 invalidate(true); 20850 } 20851 20852 /** 20853 * Cancels any animations for this view. 20854 */ 20855 public void clearAnimation() { 20856 if (mCurrentAnimation != null) { 20857 mCurrentAnimation.detach(); 20858 } 20859 mCurrentAnimation = null; 20860 invalidateParentIfNeeded(); 20861 } 20862 20863 /** 20864 * Sets the next animation to play for this view. 20865 * If you want the animation to play immediately, use 20866 * {@link #startAnimation(android.view.animation.Animation)} instead. 20867 * This method provides allows fine-grained 20868 * control over the start time and invalidation, but you 20869 * must make sure that 1) the animation has a start time set, and 20870 * 2) the view's parent (which controls animations on its children) 20871 * will be invalidated when the animation is supposed to 20872 * start. 20873 * 20874 * @param animation The next animation, or null. 20875 */ 20876 public void setAnimation(Animation animation) { 20877 mCurrentAnimation = animation; 20878 20879 if (animation != null) { 20880 // If the screen is off assume the animation start time is now instead of 20881 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 20882 // would cause the animation to start when the screen turns back on 20883 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 20884 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 20885 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 20886 } 20887 animation.reset(); 20888 } 20889 } 20890 20891 /** 20892 * Invoked by a parent ViewGroup to notify the start of the animation 20893 * currently associated with this view. If you override this method, 20894 * always call super.onAnimationStart(); 20895 * 20896 * @see #setAnimation(android.view.animation.Animation) 20897 * @see #getAnimation() 20898 */ 20899 @CallSuper 20900 protected void onAnimationStart() { 20901 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 20902 } 20903 20904 /** 20905 * Invoked by a parent ViewGroup to notify the end of the animation 20906 * currently associated with this view. If you override this method, 20907 * always call super.onAnimationEnd(); 20908 * 20909 * @see #setAnimation(android.view.animation.Animation) 20910 * @see #getAnimation() 20911 */ 20912 @CallSuper 20913 protected void onAnimationEnd() { 20914 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 20915 } 20916 20917 /** 20918 * Invoked if there is a Transform that involves alpha. Subclass that can 20919 * draw themselves with the specified alpha should return true, and then 20920 * respect that alpha when their onDraw() is called. If this returns false 20921 * then the view may be redirected to draw into an offscreen buffer to 20922 * fulfill the request, which will look fine, but may be slower than if the 20923 * subclass handles it internally. The default implementation returns false. 20924 * 20925 * @param alpha The alpha (0..255) to apply to the view's drawing 20926 * @return true if the view can draw with the specified alpha. 20927 */ 20928 protected boolean onSetAlpha(int alpha) { 20929 return false; 20930 } 20931 20932 /** 20933 * This is used by the RootView to perform an optimization when 20934 * the view hierarchy contains one or several SurfaceView. 20935 * SurfaceView is always considered transparent, but its children are not, 20936 * therefore all View objects remove themselves from the global transparent 20937 * region (passed as a parameter to this function). 20938 * 20939 * @param region The transparent region for this ViewAncestor (window). 20940 * 20941 * @return Returns true if the effective visibility of the view at this 20942 * point is opaque, regardless of the transparent region; returns false 20943 * if it is possible for underlying windows to be seen behind the view. 20944 * 20945 * {@hide} 20946 */ 20947 public boolean gatherTransparentRegion(Region region) { 20948 final AttachInfo attachInfo = mAttachInfo; 20949 if (region != null && attachInfo != null) { 20950 final int pflags = mPrivateFlags; 20951 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 20952 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 20953 // remove it from the transparent region. 20954 final int[] location = attachInfo.mTransparentLocation; 20955 getLocationInWindow(location); 20956 // When a view has Z value, then it will be better to leave some area below the view 20957 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 20958 // the bottom part needs more offset than the left, top and right parts due to the 20959 // spot light effects. 20960 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 20961 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 20962 location[0] + mRight - mLeft + shadowOffset, 20963 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 20964 } else { 20965 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 20966 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 20967 // the background drawable's non-transparent parts from this transparent region. 20968 applyDrawableToTransparentRegion(mBackground, region); 20969 } 20970 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20971 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 20972 // Similarly, we remove the foreground drawable's non-transparent parts. 20973 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 20974 } 20975 } 20976 } 20977 return true; 20978 } 20979 20980 /** 20981 * Play a sound effect for this view. 20982 * 20983 * <p>The framework will play sound effects for some built in actions, such as 20984 * clicking, but you may wish to play these effects in your widget, 20985 * for instance, for internal navigation. 20986 * 20987 * <p>The sound effect will only be played if sound effects are enabled by the user, and 20988 * {@link #isSoundEffectsEnabled()} is true. 20989 * 20990 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 20991 */ 20992 public void playSoundEffect(int soundConstant) { 20993 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 20994 return; 20995 } 20996 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 20997 } 20998 20999 /** 21000 * BZZZTT!!1! 21001 * 21002 * <p>Provide haptic feedback to the user for this view. 21003 * 21004 * <p>The framework will provide haptic feedback for some built in actions, 21005 * such as long presses, but you may wish to provide feedback for your 21006 * own widget. 21007 * 21008 * <p>The feedback will only be performed if 21009 * {@link #isHapticFeedbackEnabled()} is true. 21010 * 21011 * @param feedbackConstant One of the constants defined in 21012 * {@link HapticFeedbackConstants} 21013 */ 21014 public boolean performHapticFeedback(int feedbackConstant) { 21015 return performHapticFeedback(feedbackConstant, 0); 21016 } 21017 21018 /** 21019 * BZZZTT!!1! 21020 * 21021 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 21022 * 21023 * @param feedbackConstant One of the constants defined in 21024 * {@link HapticFeedbackConstants} 21025 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 21026 */ 21027 public boolean performHapticFeedback(int feedbackConstant, int flags) { 21028 if (mAttachInfo == null) { 21029 return false; 21030 } 21031 //noinspection SimplifiableIfStatement 21032 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 21033 && !isHapticFeedbackEnabled()) { 21034 return false; 21035 } 21036 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 21037 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 21038 } 21039 21040 /** 21041 * Request that the visibility of the status bar or other screen/window 21042 * decorations be changed. 21043 * 21044 * <p>This method is used to put the over device UI into temporary modes 21045 * where the user's attention is focused more on the application content, 21046 * by dimming or hiding surrounding system affordances. This is typically 21047 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 21048 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 21049 * to be placed behind the action bar (and with these flags other system 21050 * affordances) so that smooth transitions between hiding and showing them 21051 * can be done. 21052 * 21053 * <p>Two representative examples of the use of system UI visibility is 21054 * implementing a content browsing application (like a magazine reader) 21055 * and a video playing application. 21056 * 21057 * <p>The first code shows a typical implementation of a View in a content 21058 * browsing application. In this implementation, the application goes 21059 * into a content-oriented mode by hiding the status bar and action bar, 21060 * and putting the navigation elements into lights out mode. The user can 21061 * then interact with content while in this mode. Such an application should 21062 * provide an easy way for the user to toggle out of the mode (such as to 21063 * check information in the status bar or access notifications). In the 21064 * implementation here, this is done simply by tapping on the content. 21065 * 21066 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 21067 * content} 21068 * 21069 * <p>This second code sample shows a typical implementation of a View 21070 * in a video playing application. In this situation, while the video is 21071 * playing the application would like to go into a complete full-screen mode, 21072 * to use as much of the display as possible for the video. When in this state 21073 * the user can not interact with the application; the system intercepts 21074 * touching on the screen to pop the UI out of full screen mode. See 21075 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 21076 * 21077 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 21078 * content} 21079 * 21080 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 21081 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 21082 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 21083 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 21084 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 21085 */ 21086 public void setSystemUiVisibility(int visibility) { 21087 if (visibility != mSystemUiVisibility) { 21088 mSystemUiVisibility = visibility; 21089 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 21090 mParent.recomputeViewAttributes(this); 21091 } 21092 } 21093 } 21094 21095 /** 21096 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 21097 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 21098 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 21099 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 21100 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 21101 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 21102 */ 21103 public int getSystemUiVisibility() { 21104 return mSystemUiVisibility; 21105 } 21106 21107 /** 21108 * Returns the current system UI visibility that is currently set for 21109 * the entire window. This is the combination of the 21110 * {@link #setSystemUiVisibility(int)} values supplied by all of the 21111 * views in the window. 21112 */ 21113 public int getWindowSystemUiVisibility() { 21114 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 21115 } 21116 21117 /** 21118 * Override to find out when the window's requested system UI visibility 21119 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 21120 * This is different from the callbacks received through 21121 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 21122 * in that this is only telling you about the local request of the window, 21123 * not the actual values applied by the system. 21124 */ 21125 public void onWindowSystemUiVisibilityChanged(int visible) { 21126 } 21127 21128 /** 21129 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 21130 * the view hierarchy. 21131 */ 21132 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 21133 onWindowSystemUiVisibilityChanged(visible); 21134 } 21135 21136 /** 21137 * Set a listener to receive callbacks when the visibility of the system bar changes. 21138 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 21139 */ 21140 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 21141 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 21142 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 21143 mParent.recomputeViewAttributes(this); 21144 } 21145 } 21146 21147 /** 21148 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 21149 * the view hierarchy. 21150 */ 21151 public void dispatchSystemUiVisibilityChanged(int visibility) { 21152 ListenerInfo li = mListenerInfo; 21153 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 21154 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 21155 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 21156 } 21157 } 21158 21159 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 21160 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 21161 if (val != mSystemUiVisibility) { 21162 setSystemUiVisibility(val); 21163 return true; 21164 } 21165 return false; 21166 } 21167 21168 /** @hide */ 21169 public void setDisabledSystemUiVisibility(int flags) { 21170 if (mAttachInfo != null) { 21171 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 21172 mAttachInfo.mDisabledSystemUiVisibility = flags; 21173 if (mParent != null) { 21174 mParent.recomputeViewAttributes(this); 21175 } 21176 } 21177 } 21178 } 21179 21180 /** 21181 * Creates an image that the system displays during the drag and drop 21182 * operation. This is called a "drag shadow". The default implementation 21183 * for a DragShadowBuilder based on a View returns an image that has exactly the same 21184 * appearance as the given View. The default also positions the center of the drag shadow 21185 * directly under the touch point. If no View is provided (the constructor with no parameters 21186 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 21187 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 21188 * default is an invisible drag shadow. 21189 * <p> 21190 * You are not required to use the View you provide to the constructor as the basis of the 21191 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 21192 * anything you want as the drag shadow. 21193 * </p> 21194 * <p> 21195 * You pass a DragShadowBuilder object to the system when you start the drag. The system 21196 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 21197 * size and position of the drag shadow. It uses this data to construct a 21198 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 21199 * so that your application can draw the shadow image in the Canvas. 21200 * </p> 21201 * 21202 * <div class="special reference"> 21203 * <h3>Developer Guides</h3> 21204 * <p>For a guide to implementing drag and drop features, read the 21205 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 21206 * </div> 21207 */ 21208 public static class DragShadowBuilder { 21209 private final WeakReference<View> mView; 21210 21211 /** 21212 * Constructs a shadow image builder based on a View. By default, the resulting drag 21213 * shadow will have the same appearance and dimensions as the View, with the touch point 21214 * over the center of the View. 21215 * @param view A View. Any View in scope can be used. 21216 */ 21217 public DragShadowBuilder(View view) { 21218 mView = new WeakReference<View>(view); 21219 } 21220 21221 /** 21222 * Construct a shadow builder object with no associated View. This 21223 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 21224 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 21225 * to supply the drag shadow's dimensions and appearance without 21226 * reference to any View object. If they are not overridden, then the result is an 21227 * invisible drag shadow. 21228 */ 21229 public DragShadowBuilder() { 21230 mView = new WeakReference<View>(null); 21231 } 21232 21233 /** 21234 * Returns the View object that had been passed to the 21235 * {@link #View.DragShadowBuilder(View)} 21236 * constructor. If that View parameter was {@code null} or if the 21237 * {@link #View.DragShadowBuilder()} 21238 * constructor was used to instantiate the builder object, this method will return 21239 * null. 21240 * 21241 * @return The View object associate with this builder object. 21242 */ 21243 @SuppressWarnings({"JavadocReference"}) 21244 final public View getView() { 21245 return mView.get(); 21246 } 21247 21248 /** 21249 * Provides the metrics for the shadow image. These include the dimensions of 21250 * the shadow image, and the point within that shadow that should 21251 * be centered under the touch location while dragging. 21252 * <p> 21253 * The default implementation sets the dimensions of the shadow to be the 21254 * same as the dimensions of the View itself and centers the shadow under 21255 * the touch point. 21256 * </p> 21257 * 21258 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 21259 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 21260 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 21261 * image. 21262 * 21263 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 21264 * shadow image that should be underneath the touch point during the drag and drop 21265 * operation. Your application must set {@link android.graphics.Point#x} to the 21266 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 21267 */ 21268 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 21269 final View view = mView.get(); 21270 if (view != null) { 21271 outShadowSize.set(view.getWidth(), view.getHeight()); 21272 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 21273 } else { 21274 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 21275 } 21276 } 21277 21278 /** 21279 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 21280 * based on the dimensions it received from the 21281 * {@link #onProvideShadowMetrics(Point, Point)} callback. 21282 * 21283 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 21284 */ 21285 public void onDrawShadow(Canvas canvas) { 21286 final View view = mView.get(); 21287 if (view != null) { 21288 view.draw(canvas); 21289 } else { 21290 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 21291 } 21292 } 21293 } 21294 21295 /** 21296 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 21297 * startDragAndDrop()} for newer platform versions. 21298 */ 21299 @Deprecated 21300 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 21301 Object myLocalState, int flags) { 21302 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 21303 } 21304 21305 /** 21306 * Starts a drag and drop operation. When your application calls this method, it passes a 21307 * {@link android.view.View.DragShadowBuilder} object to the system. The 21308 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 21309 * to get metrics for the drag shadow, and then calls the object's 21310 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 21311 * <p> 21312 * Once the system has the drag shadow, it begins the drag and drop operation by sending 21313 * drag events to all the View objects in your application that are currently visible. It does 21314 * this either by calling the View object's drag listener (an implementation of 21315 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 21316 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 21317 * Both are passed a {@link android.view.DragEvent} object that has a 21318 * {@link android.view.DragEvent#getAction()} value of 21319 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 21320 * </p> 21321 * <p> 21322 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 21323 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 21324 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 21325 * to the View the user selected for dragging. 21326 * </p> 21327 * @param data A {@link android.content.ClipData} object pointing to the data to be 21328 * transferred by the drag and drop operation. 21329 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21330 * drag shadow. 21331 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 21332 * drop operation. When dispatching drag events to views in the same activity this object 21333 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 21334 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 21335 * will return null). 21336 * <p> 21337 * myLocalState is a lightweight mechanism for the sending information from the dragged View 21338 * to the target Views. For example, it can contain flags that differentiate between a 21339 * a copy operation and a move operation. 21340 * </p> 21341 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 21342 * flags, or any combination of the following: 21343 * <ul> 21344 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 21345 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 21346 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 21347 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 21348 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 21349 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 21350 * </ul> 21351 * @return {@code true} if the method completes successfully, or 21352 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 21353 * do a drag, and so no drag operation is in progress. 21354 */ 21355 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 21356 Object myLocalState, int flags) { 21357 if (ViewDebug.DEBUG_DRAG) { 21358 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 21359 } 21360 if (mAttachInfo == null) { 21361 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 21362 return false; 21363 } 21364 21365 if (data != null) { 21366 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 21367 } 21368 21369 boolean okay = false; 21370 21371 Point shadowSize = new Point(); 21372 Point shadowTouchPoint = new Point(); 21373 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 21374 21375 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 21376 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 21377 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 21378 } 21379 21380 if (ViewDebug.DEBUG_DRAG) { 21381 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 21382 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 21383 } 21384 if (mAttachInfo.mDragSurface != null) { 21385 mAttachInfo.mDragSurface.release(); 21386 } 21387 mAttachInfo.mDragSurface = new Surface(); 21388 try { 21389 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 21390 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 21391 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 21392 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 21393 if (mAttachInfo.mDragToken != null) { 21394 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21395 try { 21396 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21397 shadowBuilder.onDrawShadow(canvas); 21398 } finally { 21399 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21400 } 21401 21402 final ViewRootImpl root = getViewRootImpl(); 21403 21404 // Cache the local state object for delivery with DragEvents 21405 root.setLocalDragState(myLocalState); 21406 21407 // repurpose 'shadowSize' for the last touch point 21408 root.getLastTouchPoint(shadowSize); 21409 21410 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 21411 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 21412 shadowTouchPoint.x, shadowTouchPoint.y, data); 21413 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 21414 } 21415 } catch (Exception e) { 21416 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 21417 mAttachInfo.mDragSurface.destroy(); 21418 mAttachInfo.mDragSurface = null; 21419 } 21420 21421 return okay; 21422 } 21423 21424 /** 21425 * Cancels an ongoing drag and drop operation. 21426 * <p> 21427 * A {@link android.view.DragEvent} object with 21428 * {@link android.view.DragEvent#getAction()} value of 21429 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 21430 * {@link android.view.DragEvent#getResult()} value of {@code false} 21431 * will be sent to every 21432 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 21433 * even if they are not currently visible. 21434 * </p> 21435 * <p> 21436 * This method can be called on any View in the same window as the View on which 21437 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 21438 * was called. 21439 * </p> 21440 */ 21441 public final void cancelDragAndDrop() { 21442 if (ViewDebug.DEBUG_DRAG) { 21443 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 21444 } 21445 if (mAttachInfo == null) { 21446 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 21447 return; 21448 } 21449 if (mAttachInfo.mDragToken != null) { 21450 try { 21451 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 21452 } catch (Exception e) { 21453 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 21454 } 21455 mAttachInfo.mDragToken = null; 21456 } else { 21457 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 21458 } 21459 } 21460 21461 /** 21462 * Updates the drag shadow for the ongoing drag and drop operation. 21463 * 21464 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21465 * new drag shadow. 21466 */ 21467 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 21468 if (ViewDebug.DEBUG_DRAG) { 21469 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 21470 } 21471 if (mAttachInfo == null) { 21472 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 21473 return; 21474 } 21475 if (mAttachInfo.mDragToken != null) { 21476 try { 21477 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21478 try { 21479 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21480 shadowBuilder.onDrawShadow(canvas); 21481 } finally { 21482 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21483 } 21484 } catch (Exception e) { 21485 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 21486 } 21487 } else { 21488 Log.e(VIEW_LOG_TAG, "No active drag"); 21489 } 21490 } 21491 21492 /** 21493 * Starts a move from {startX, startY}, the amount of the movement will be the offset 21494 * between {startX, startY} and the new cursor positon. 21495 * @param startX horizontal coordinate where the move started. 21496 * @param startY vertical coordinate where the move started. 21497 * @return whether moving was started successfully. 21498 * @hide 21499 */ 21500 public final boolean startMovingTask(float startX, float startY) { 21501 if (ViewDebug.DEBUG_POSITIONING) { 21502 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 21503 } 21504 try { 21505 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 21506 } catch (RemoteException e) { 21507 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 21508 } 21509 return false; 21510 } 21511 21512 /** 21513 * Handles drag events sent by the system following a call to 21514 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 21515 * startDragAndDrop()}. 21516 *<p> 21517 * When the system calls this method, it passes a 21518 * {@link android.view.DragEvent} object. A call to 21519 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 21520 * in DragEvent. The method uses these to determine what is happening in the drag and drop 21521 * operation. 21522 * @param event The {@link android.view.DragEvent} sent by the system. 21523 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 21524 * in DragEvent, indicating the type of drag event represented by this object. 21525 * @return {@code true} if the method was successful, otherwise {@code false}. 21526 * <p> 21527 * The method should return {@code true} in response to an action type of 21528 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 21529 * operation. 21530 * </p> 21531 * <p> 21532 * The method should also return {@code true} in response to an action type of 21533 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 21534 * {@code false} if it didn't. 21535 * </p> 21536 * <p> 21537 * For all other events, the return value is ignored. 21538 * </p> 21539 */ 21540 public boolean onDragEvent(DragEvent event) { 21541 return false; 21542 } 21543 21544 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 21545 boolean dispatchDragEnterExitInPreN(DragEvent event) { 21546 return callDragEventHandler(event); 21547 } 21548 21549 /** 21550 * Detects if this View is enabled and has a drag event listener. 21551 * If both are true, then it calls the drag event listener with the 21552 * {@link android.view.DragEvent} it received. If the drag event listener returns 21553 * {@code true}, then dispatchDragEvent() returns {@code true}. 21554 * <p> 21555 * For all other cases, the method calls the 21556 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 21557 * method and returns its result. 21558 * </p> 21559 * <p> 21560 * This ensures that a drag event is always consumed, even if the View does not have a drag 21561 * event listener. However, if the View has a listener and the listener returns true, then 21562 * onDragEvent() is not called. 21563 * </p> 21564 */ 21565 public boolean dispatchDragEvent(DragEvent event) { 21566 event.mEventHandlerWasCalled = true; 21567 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 21568 event.mAction == DragEvent.ACTION_DROP) { 21569 // About to deliver an event with coordinates to this view. Notify that now this view 21570 // has drag focus. This will send exit/enter events as needed. 21571 getViewRootImpl().setDragFocus(this, event); 21572 } 21573 return callDragEventHandler(event); 21574 } 21575 21576 final boolean callDragEventHandler(DragEvent event) { 21577 final boolean result; 21578 21579 ListenerInfo li = mListenerInfo; 21580 //noinspection SimplifiableIfStatement 21581 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 21582 && li.mOnDragListener.onDrag(this, event)) { 21583 result = true; 21584 } else { 21585 result = onDragEvent(event); 21586 } 21587 21588 switch (event.mAction) { 21589 case DragEvent.ACTION_DRAG_ENTERED: { 21590 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 21591 refreshDrawableState(); 21592 } break; 21593 case DragEvent.ACTION_DRAG_EXITED: { 21594 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 21595 refreshDrawableState(); 21596 } break; 21597 case DragEvent.ACTION_DRAG_ENDED: { 21598 mPrivateFlags2 &= ~View.DRAG_MASK; 21599 refreshDrawableState(); 21600 } break; 21601 } 21602 21603 return result; 21604 } 21605 21606 boolean canAcceptDrag() { 21607 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 21608 } 21609 21610 /** 21611 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 21612 * it is ever exposed at all. 21613 * @hide 21614 */ 21615 public void onCloseSystemDialogs(String reason) { 21616 } 21617 21618 /** 21619 * Given a Drawable whose bounds have been set to draw into this view, 21620 * update a Region being computed for 21621 * {@link #gatherTransparentRegion(android.graphics.Region)} so 21622 * that any non-transparent parts of the Drawable are removed from the 21623 * given transparent region. 21624 * 21625 * @param dr The Drawable whose transparency is to be applied to the region. 21626 * @param region A Region holding the current transparency information, 21627 * where any parts of the region that are set are considered to be 21628 * transparent. On return, this region will be modified to have the 21629 * transparency information reduced by the corresponding parts of the 21630 * Drawable that are not transparent. 21631 * {@hide} 21632 */ 21633 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 21634 if (DBG) { 21635 Log.i("View", "Getting transparent region for: " + this); 21636 } 21637 final Region r = dr.getTransparentRegion(); 21638 final Rect db = dr.getBounds(); 21639 final AttachInfo attachInfo = mAttachInfo; 21640 if (r != null && attachInfo != null) { 21641 final int w = getRight()-getLeft(); 21642 final int h = getBottom()-getTop(); 21643 if (db.left > 0) { 21644 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 21645 r.op(0, 0, db.left, h, Region.Op.UNION); 21646 } 21647 if (db.right < w) { 21648 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 21649 r.op(db.right, 0, w, h, Region.Op.UNION); 21650 } 21651 if (db.top > 0) { 21652 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 21653 r.op(0, 0, w, db.top, Region.Op.UNION); 21654 } 21655 if (db.bottom < h) { 21656 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 21657 r.op(0, db.bottom, w, h, Region.Op.UNION); 21658 } 21659 final int[] location = attachInfo.mTransparentLocation; 21660 getLocationInWindow(location); 21661 r.translate(location[0], location[1]); 21662 region.op(r, Region.Op.INTERSECT); 21663 } else { 21664 region.op(db, Region.Op.DIFFERENCE); 21665 } 21666 } 21667 21668 private void checkForLongClick(int delayOffset, float x, float y) { 21669 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 21670 mHasPerformedLongPress = false; 21671 21672 if (mPendingCheckForLongPress == null) { 21673 mPendingCheckForLongPress = new CheckForLongPress(); 21674 } 21675 mPendingCheckForLongPress.setAnchor(x, y); 21676 mPendingCheckForLongPress.rememberWindowAttachCount(); 21677 mPendingCheckForLongPress.rememberPressedState(); 21678 postDelayed(mPendingCheckForLongPress, 21679 ViewConfiguration.getLongPressTimeout() - delayOffset); 21680 } 21681 } 21682 21683 /** 21684 * Inflate a view from an XML resource. This convenience method wraps the {@link 21685 * LayoutInflater} class, which provides a full range of options for view inflation. 21686 * 21687 * @param context The Context object for your activity or application. 21688 * @param resource The resource ID to inflate 21689 * @param root A view group that will be the parent. Used to properly inflate the 21690 * layout_* parameters. 21691 * @see LayoutInflater 21692 */ 21693 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 21694 LayoutInflater factory = LayoutInflater.from(context); 21695 return factory.inflate(resource, root); 21696 } 21697 21698 /** 21699 * Scroll the view with standard behavior for scrolling beyond the normal 21700 * content boundaries. Views that call this method should override 21701 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 21702 * results of an over-scroll operation. 21703 * 21704 * Views can use this method to handle any touch or fling-based scrolling. 21705 * 21706 * @param deltaX Change in X in pixels 21707 * @param deltaY Change in Y in pixels 21708 * @param scrollX Current X scroll value in pixels before applying deltaX 21709 * @param scrollY Current Y scroll value in pixels before applying deltaY 21710 * @param scrollRangeX Maximum content scroll range along the X axis 21711 * @param scrollRangeY Maximum content scroll range along the Y axis 21712 * @param maxOverScrollX Number of pixels to overscroll by in either direction 21713 * along the X axis. 21714 * @param maxOverScrollY Number of pixels to overscroll by in either direction 21715 * along the Y axis. 21716 * @param isTouchEvent true if this scroll operation is the result of a touch event. 21717 * @return true if scrolling was clamped to an over-scroll boundary along either 21718 * axis, false otherwise. 21719 */ 21720 @SuppressWarnings({"UnusedParameters"}) 21721 protected boolean overScrollBy(int deltaX, int deltaY, 21722 int scrollX, int scrollY, 21723 int scrollRangeX, int scrollRangeY, 21724 int maxOverScrollX, int maxOverScrollY, 21725 boolean isTouchEvent) { 21726 final int overScrollMode = mOverScrollMode; 21727 final boolean canScrollHorizontal = 21728 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 21729 final boolean canScrollVertical = 21730 computeVerticalScrollRange() > computeVerticalScrollExtent(); 21731 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 21732 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 21733 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 21734 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 21735 21736 int newScrollX = scrollX + deltaX; 21737 if (!overScrollHorizontal) { 21738 maxOverScrollX = 0; 21739 } 21740 21741 int newScrollY = scrollY + deltaY; 21742 if (!overScrollVertical) { 21743 maxOverScrollY = 0; 21744 } 21745 21746 // Clamp values if at the limits and record 21747 final int left = -maxOverScrollX; 21748 final int right = maxOverScrollX + scrollRangeX; 21749 final int top = -maxOverScrollY; 21750 final int bottom = maxOverScrollY + scrollRangeY; 21751 21752 boolean clampedX = false; 21753 if (newScrollX > right) { 21754 newScrollX = right; 21755 clampedX = true; 21756 } else if (newScrollX < left) { 21757 newScrollX = left; 21758 clampedX = true; 21759 } 21760 21761 boolean clampedY = false; 21762 if (newScrollY > bottom) { 21763 newScrollY = bottom; 21764 clampedY = true; 21765 } else if (newScrollY < top) { 21766 newScrollY = top; 21767 clampedY = true; 21768 } 21769 21770 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 21771 21772 return clampedX || clampedY; 21773 } 21774 21775 /** 21776 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 21777 * respond to the results of an over-scroll operation. 21778 * 21779 * @param scrollX New X scroll value in pixels 21780 * @param scrollY New Y scroll value in pixels 21781 * @param clampedX True if scrollX was clamped to an over-scroll boundary 21782 * @param clampedY True if scrollY was clamped to an over-scroll boundary 21783 */ 21784 protected void onOverScrolled(int scrollX, int scrollY, 21785 boolean clampedX, boolean clampedY) { 21786 // Intentionally empty. 21787 } 21788 21789 /** 21790 * Returns the over-scroll mode for this view. The result will be 21791 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21792 * (allow over-scrolling only if the view content is larger than the container), 21793 * or {@link #OVER_SCROLL_NEVER}. 21794 * 21795 * @return This view's over-scroll mode. 21796 */ 21797 public int getOverScrollMode() { 21798 return mOverScrollMode; 21799 } 21800 21801 /** 21802 * Set the over-scroll mode for this view. Valid over-scroll modes are 21803 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21804 * (allow over-scrolling only if the view content is larger than the container), 21805 * or {@link #OVER_SCROLL_NEVER}. 21806 * 21807 * Setting the over-scroll mode of a view will have an effect only if the 21808 * view is capable of scrolling. 21809 * 21810 * @param overScrollMode The new over-scroll mode for this view. 21811 */ 21812 public void setOverScrollMode(int overScrollMode) { 21813 if (overScrollMode != OVER_SCROLL_ALWAYS && 21814 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 21815 overScrollMode != OVER_SCROLL_NEVER) { 21816 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 21817 } 21818 mOverScrollMode = overScrollMode; 21819 } 21820 21821 /** 21822 * Enable or disable nested scrolling for this view. 21823 * 21824 * <p>If this property is set to true the view will be permitted to initiate nested 21825 * scrolling operations with a compatible parent view in the current hierarchy. If this 21826 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 21827 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 21828 * the nested scroll.</p> 21829 * 21830 * @param enabled true to enable nested scrolling, false to disable 21831 * 21832 * @see #isNestedScrollingEnabled() 21833 */ 21834 public void setNestedScrollingEnabled(boolean enabled) { 21835 if (enabled) { 21836 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 21837 } else { 21838 stopNestedScroll(); 21839 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 21840 } 21841 } 21842 21843 /** 21844 * Returns true if nested scrolling is enabled for this view. 21845 * 21846 * <p>If nested scrolling is enabled and this View class implementation supports it, 21847 * this view will act as a nested scrolling child view when applicable, forwarding data 21848 * about the scroll operation in progress to a compatible and cooperating nested scrolling 21849 * parent.</p> 21850 * 21851 * @return true if nested scrolling is enabled 21852 * 21853 * @see #setNestedScrollingEnabled(boolean) 21854 */ 21855 public boolean isNestedScrollingEnabled() { 21856 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 21857 PFLAG3_NESTED_SCROLLING_ENABLED; 21858 } 21859 21860 /** 21861 * Begin a nestable scroll operation along the given axes. 21862 * 21863 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 21864 * 21865 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 21866 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 21867 * In the case of touch scrolling the nested scroll will be terminated automatically in 21868 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 21869 * In the event of programmatic scrolling the caller must explicitly call 21870 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 21871 * 21872 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 21873 * If it returns false the caller may ignore the rest of this contract until the next scroll. 21874 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 21875 * 21876 * <p>At each incremental step of the scroll the caller should invoke 21877 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 21878 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 21879 * parent at least partially consumed the scroll and the caller should adjust the amount it 21880 * scrolls by.</p> 21881 * 21882 * <p>After applying the remainder of the scroll delta the caller should invoke 21883 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 21884 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 21885 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 21886 * </p> 21887 * 21888 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 21889 * {@link #SCROLL_AXIS_VERTICAL}. 21890 * @return true if a cooperative parent was found and nested scrolling has been enabled for 21891 * the current gesture. 21892 * 21893 * @see #stopNestedScroll() 21894 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21895 * @see #dispatchNestedScroll(int, int, int, int, int[]) 21896 */ 21897 public boolean startNestedScroll(int axes) { 21898 if (hasNestedScrollingParent()) { 21899 // Already in progress 21900 return true; 21901 } 21902 if (isNestedScrollingEnabled()) { 21903 ViewParent p = getParent(); 21904 View child = this; 21905 while (p != null) { 21906 try { 21907 if (p.onStartNestedScroll(child, this, axes)) { 21908 mNestedScrollingParent = p; 21909 p.onNestedScrollAccepted(child, this, axes); 21910 return true; 21911 } 21912 } catch (AbstractMethodError e) { 21913 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 21914 "method onStartNestedScroll", e); 21915 // Allow the search upward to continue 21916 } 21917 if (p instanceof View) { 21918 child = (View) p; 21919 } 21920 p = p.getParent(); 21921 } 21922 } 21923 return false; 21924 } 21925 21926 /** 21927 * Stop a nested scroll in progress. 21928 * 21929 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 21930 * 21931 * @see #startNestedScroll(int) 21932 */ 21933 public void stopNestedScroll() { 21934 if (mNestedScrollingParent != null) { 21935 mNestedScrollingParent.onStopNestedScroll(this); 21936 mNestedScrollingParent = null; 21937 } 21938 } 21939 21940 /** 21941 * Returns true if this view has a nested scrolling parent. 21942 * 21943 * <p>The presence of a nested scrolling parent indicates that this view has initiated 21944 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 21945 * 21946 * @return whether this view has a nested scrolling parent 21947 */ 21948 public boolean hasNestedScrollingParent() { 21949 return mNestedScrollingParent != null; 21950 } 21951 21952 /** 21953 * Dispatch one step of a nested scroll in progress. 21954 * 21955 * <p>Implementations of views that support nested scrolling should call this to report 21956 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 21957 * is not currently in progress or nested scrolling is not 21958 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 21959 * 21960 * <p>Compatible View implementations should also call 21961 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 21962 * consuming a component of the scroll event themselves.</p> 21963 * 21964 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 21965 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 21966 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 21967 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 21968 * @param offsetInWindow Optional. If not null, on return this will contain the offset 21969 * in local view coordinates of this view from before this operation 21970 * to after it completes. View implementations may use this to adjust 21971 * expected input coordinate tracking. 21972 * @return true if the event was dispatched, false if it could not be dispatched. 21973 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21974 */ 21975 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 21976 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 21977 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21978 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 21979 int startX = 0; 21980 int startY = 0; 21981 if (offsetInWindow != null) { 21982 getLocationInWindow(offsetInWindow); 21983 startX = offsetInWindow[0]; 21984 startY = offsetInWindow[1]; 21985 } 21986 21987 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 21988 dxUnconsumed, dyUnconsumed); 21989 21990 if (offsetInWindow != null) { 21991 getLocationInWindow(offsetInWindow); 21992 offsetInWindow[0] -= startX; 21993 offsetInWindow[1] -= startY; 21994 } 21995 return true; 21996 } else if (offsetInWindow != null) { 21997 // No motion, no dispatch. Keep offsetInWindow up to date. 21998 offsetInWindow[0] = 0; 21999 offsetInWindow[1] = 0; 22000 } 22001 } 22002 return false; 22003 } 22004 22005 /** 22006 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 22007 * 22008 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 22009 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 22010 * scrolling operation to consume some or all of the scroll operation before the child view 22011 * consumes it.</p> 22012 * 22013 * @param dx Horizontal scroll distance in pixels 22014 * @param dy Vertical scroll distance in pixels 22015 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 22016 * and consumed[1] the consumed dy. 22017 * @param offsetInWindow Optional. If not null, on return this will contain the offset 22018 * in local view coordinates of this view from before this operation 22019 * to after it completes. View implementations may use this to adjust 22020 * expected input coordinate tracking. 22021 * @return true if the parent consumed some or all of the scroll delta 22022 * @see #dispatchNestedScroll(int, int, int, int, int[]) 22023 */ 22024 public boolean dispatchNestedPreScroll(int dx, int dy, 22025 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 22026 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22027 if (dx != 0 || dy != 0) { 22028 int startX = 0; 22029 int startY = 0; 22030 if (offsetInWindow != null) { 22031 getLocationInWindow(offsetInWindow); 22032 startX = offsetInWindow[0]; 22033 startY = offsetInWindow[1]; 22034 } 22035 22036 if (consumed == null) { 22037 if (mTempNestedScrollConsumed == null) { 22038 mTempNestedScrollConsumed = new int[2]; 22039 } 22040 consumed = mTempNestedScrollConsumed; 22041 } 22042 consumed[0] = 0; 22043 consumed[1] = 0; 22044 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 22045 22046 if (offsetInWindow != null) { 22047 getLocationInWindow(offsetInWindow); 22048 offsetInWindow[0] -= startX; 22049 offsetInWindow[1] -= startY; 22050 } 22051 return consumed[0] != 0 || consumed[1] != 0; 22052 } else if (offsetInWindow != null) { 22053 offsetInWindow[0] = 0; 22054 offsetInWindow[1] = 0; 22055 } 22056 } 22057 return false; 22058 } 22059 22060 /** 22061 * Dispatch a fling to a nested scrolling parent. 22062 * 22063 * <p>This method should be used to indicate that a nested scrolling child has detected 22064 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 22065 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 22066 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 22067 * along a scrollable axis.</p> 22068 * 22069 * <p>If a nested scrolling child view would normally fling but it is at the edge of 22070 * its own content, it can use this method to delegate the fling to its nested scrolling 22071 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 22072 * 22073 * @param velocityX Horizontal fling velocity in pixels per second 22074 * @param velocityY Vertical fling velocity in pixels per second 22075 * @param consumed true if the child consumed the fling, false otherwise 22076 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 22077 */ 22078 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 22079 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22080 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 22081 } 22082 return false; 22083 } 22084 22085 /** 22086 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 22087 * 22088 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 22089 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 22090 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 22091 * before the child view consumes it. If this method returns <code>true</code>, a nested 22092 * parent view consumed the fling and this view should not scroll as a result.</p> 22093 * 22094 * <p>For a better user experience, only one view in a nested scrolling chain should consume 22095 * the fling at a time. If a parent view consumed the fling this method will return false. 22096 * Custom view implementations should account for this in two ways:</p> 22097 * 22098 * <ul> 22099 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 22100 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 22101 * position regardless.</li> 22102 * <li>If a nested parent does consume the fling, this view should not scroll at all, 22103 * even to settle back to a valid idle position.</li> 22104 * </ul> 22105 * 22106 * <p>Views should also not offer fling velocities to nested parent views along an axis 22107 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 22108 * should not offer a horizontal fling velocity to its parents since scrolling along that 22109 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 22110 * 22111 * @param velocityX Horizontal fling velocity in pixels per second 22112 * @param velocityY Vertical fling velocity in pixels per second 22113 * @return true if a nested scrolling parent consumed the fling 22114 */ 22115 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 22116 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22117 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 22118 } 22119 return false; 22120 } 22121 22122 /** 22123 * Gets a scale factor that determines the distance the view should scroll 22124 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 22125 * @return The vertical scroll scale factor. 22126 * @hide 22127 */ 22128 protected float getVerticalScrollFactor() { 22129 if (mVerticalScrollFactor == 0) { 22130 TypedValue outValue = new TypedValue(); 22131 if (!mContext.getTheme().resolveAttribute( 22132 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 22133 throw new IllegalStateException( 22134 "Expected theme to define listPreferredItemHeight."); 22135 } 22136 mVerticalScrollFactor = outValue.getDimension( 22137 mContext.getResources().getDisplayMetrics()); 22138 } 22139 return mVerticalScrollFactor; 22140 } 22141 22142 /** 22143 * Gets a scale factor that determines the distance the view should scroll 22144 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 22145 * @return The horizontal scroll scale factor. 22146 * @hide 22147 */ 22148 protected float getHorizontalScrollFactor() { 22149 // TODO: Should use something else. 22150 return getVerticalScrollFactor(); 22151 } 22152 22153 /** 22154 * Return the value specifying the text direction or policy that was set with 22155 * {@link #setTextDirection(int)}. 22156 * 22157 * @return the defined text direction. It can be one of: 22158 * 22159 * {@link #TEXT_DIRECTION_INHERIT}, 22160 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22161 * {@link #TEXT_DIRECTION_ANY_RTL}, 22162 * {@link #TEXT_DIRECTION_LTR}, 22163 * {@link #TEXT_DIRECTION_RTL}, 22164 * {@link #TEXT_DIRECTION_LOCALE}, 22165 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22166 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22167 * 22168 * @attr ref android.R.styleable#View_textDirection 22169 * 22170 * @hide 22171 */ 22172 @ViewDebug.ExportedProperty(category = "text", mapping = { 22173 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22174 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22175 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22176 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22177 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22178 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22179 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22180 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22181 }) 22182 public int getRawTextDirection() { 22183 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 22184 } 22185 22186 /** 22187 * Set the text direction. 22188 * 22189 * @param textDirection the direction to set. Should be one of: 22190 * 22191 * {@link #TEXT_DIRECTION_INHERIT}, 22192 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22193 * {@link #TEXT_DIRECTION_ANY_RTL}, 22194 * {@link #TEXT_DIRECTION_LTR}, 22195 * {@link #TEXT_DIRECTION_RTL}, 22196 * {@link #TEXT_DIRECTION_LOCALE} 22197 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22198 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 22199 * 22200 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 22201 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 22202 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 22203 * 22204 * @attr ref android.R.styleable#View_textDirection 22205 */ 22206 public void setTextDirection(int textDirection) { 22207 if (getRawTextDirection() != textDirection) { 22208 // Reset the current text direction and the resolved one 22209 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 22210 resetResolvedTextDirection(); 22211 // Set the new text direction 22212 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 22213 // Do resolution 22214 resolveTextDirection(); 22215 // Notify change 22216 onRtlPropertiesChanged(getLayoutDirection()); 22217 // Refresh 22218 requestLayout(); 22219 invalidate(true); 22220 } 22221 } 22222 22223 /** 22224 * Return the resolved text direction. 22225 * 22226 * @return the resolved text direction. Returns one of: 22227 * 22228 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22229 * {@link #TEXT_DIRECTION_ANY_RTL}, 22230 * {@link #TEXT_DIRECTION_LTR}, 22231 * {@link #TEXT_DIRECTION_RTL}, 22232 * {@link #TEXT_DIRECTION_LOCALE}, 22233 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22234 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22235 * 22236 * @attr ref android.R.styleable#View_textDirection 22237 */ 22238 @ViewDebug.ExportedProperty(category = "text", mapping = { 22239 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22240 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22241 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22242 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22243 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22244 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22245 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22246 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22247 }) 22248 public int getTextDirection() { 22249 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 22250 } 22251 22252 /** 22253 * Resolve the text direction. 22254 * 22255 * @return true if resolution has been done, false otherwise. 22256 * 22257 * @hide 22258 */ 22259 public boolean resolveTextDirection() { 22260 // Reset any previous text direction resolution 22261 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22262 22263 if (hasRtlSupport()) { 22264 // Set resolved text direction flag depending on text direction flag 22265 final int textDirection = getRawTextDirection(); 22266 switch(textDirection) { 22267 case TEXT_DIRECTION_INHERIT: 22268 if (!canResolveTextDirection()) { 22269 // We cannot do the resolution if there is no parent, so use the default one 22270 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22271 // Resolution will need to happen again later 22272 return false; 22273 } 22274 22275 // Parent has not yet resolved, so we still return the default 22276 try { 22277 if (!mParent.isTextDirectionResolved()) { 22278 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22279 // Resolution will need to happen again later 22280 return false; 22281 } 22282 } catch (AbstractMethodError e) { 22283 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22284 " does not fully implement ViewParent", e); 22285 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 22286 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22287 return true; 22288 } 22289 22290 // Set current resolved direction to the same value as the parent's one 22291 int parentResolvedDirection; 22292 try { 22293 parentResolvedDirection = mParent.getTextDirection(); 22294 } catch (AbstractMethodError e) { 22295 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22296 " does not fully implement ViewParent", e); 22297 parentResolvedDirection = TEXT_DIRECTION_LTR; 22298 } 22299 switch (parentResolvedDirection) { 22300 case TEXT_DIRECTION_FIRST_STRONG: 22301 case TEXT_DIRECTION_ANY_RTL: 22302 case TEXT_DIRECTION_LTR: 22303 case TEXT_DIRECTION_RTL: 22304 case TEXT_DIRECTION_LOCALE: 22305 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22306 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22307 mPrivateFlags2 |= 22308 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22309 break; 22310 default: 22311 // Default resolved direction is "first strong" heuristic 22312 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22313 } 22314 break; 22315 case TEXT_DIRECTION_FIRST_STRONG: 22316 case TEXT_DIRECTION_ANY_RTL: 22317 case TEXT_DIRECTION_LTR: 22318 case TEXT_DIRECTION_RTL: 22319 case TEXT_DIRECTION_LOCALE: 22320 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22321 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22322 // Resolved direction is the same as text direction 22323 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22324 break; 22325 default: 22326 // Default resolved direction is "first strong" heuristic 22327 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22328 } 22329 } else { 22330 // Default resolved direction is "first strong" heuristic 22331 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22332 } 22333 22334 // Set to resolved 22335 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 22336 return true; 22337 } 22338 22339 /** 22340 * Check if text direction resolution can be done. 22341 * 22342 * @return true if text direction resolution can be done otherwise return false. 22343 */ 22344 public boolean canResolveTextDirection() { 22345 switch (getRawTextDirection()) { 22346 case TEXT_DIRECTION_INHERIT: 22347 if (mParent != null) { 22348 try { 22349 return mParent.canResolveTextDirection(); 22350 } catch (AbstractMethodError e) { 22351 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22352 " does not fully implement ViewParent", e); 22353 } 22354 } 22355 return false; 22356 22357 default: 22358 return true; 22359 } 22360 } 22361 22362 /** 22363 * Reset resolved text direction. Text direction will be resolved during a call to 22364 * {@link #onMeasure(int, int)}. 22365 * 22366 * @hide 22367 */ 22368 public void resetResolvedTextDirection() { 22369 // Reset any previous text direction resolution 22370 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22371 // Set to default value 22372 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22373 } 22374 22375 /** 22376 * @return true if text direction is inherited. 22377 * 22378 * @hide 22379 */ 22380 public boolean isTextDirectionInherited() { 22381 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 22382 } 22383 22384 /** 22385 * @return true if text direction is resolved. 22386 */ 22387 public boolean isTextDirectionResolved() { 22388 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 22389 } 22390 22391 /** 22392 * Return the value specifying the text alignment or policy that was set with 22393 * {@link #setTextAlignment(int)}. 22394 * 22395 * @return the defined text alignment. It can be one of: 22396 * 22397 * {@link #TEXT_ALIGNMENT_INHERIT}, 22398 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22399 * {@link #TEXT_ALIGNMENT_CENTER}, 22400 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22401 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22402 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22403 * {@link #TEXT_ALIGNMENT_VIEW_END} 22404 * 22405 * @attr ref android.R.styleable#View_textAlignment 22406 * 22407 * @hide 22408 */ 22409 @ViewDebug.ExportedProperty(category = "text", mapping = { 22410 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22411 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22412 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22413 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22414 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22415 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22416 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22417 }) 22418 @TextAlignment 22419 public int getRawTextAlignment() { 22420 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 22421 } 22422 22423 /** 22424 * Set the text alignment. 22425 * 22426 * @param textAlignment The text alignment to set. Should be one of 22427 * 22428 * {@link #TEXT_ALIGNMENT_INHERIT}, 22429 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22430 * {@link #TEXT_ALIGNMENT_CENTER}, 22431 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22432 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22433 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22434 * {@link #TEXT_ALIGNMENT_VIEW_END} 22435 * 22436 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 22437 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 22438 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 22439 * 22440 * @attr ref android.R.styleable#View_textAlignment 22441 */ 22442 public void setTextAlignment(@TextAlignment int textAlignment) { 22443 if (textAlignment != getRawTextAlignment()) { 22444 // Reset the current and resolved text alignment 22445 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 22446 resetResolvedTextAlignment(); 22447 // Set the new text alignment 22448 mPrivateFlags2 |= 22449 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 22450 // Do resolution 22451 resolveTextAlignment(); 22452 // Notify change 22453 onRtlPropertiesChanged(getLayoutDirection()); 22454 // Refresh 22455 requestLayout(); 22456 invalidate(true); 22457 } 22458 } 22459 22460 /** 22461 * Return the resolved text alignment. 22462 * 22463 * @return the resolved text alignment. Returns one of: 22464 * 22465 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22466 * {@link #TEXT_ALIGNMENT_CENTER}, 22467 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22468 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22469 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22470 * {@link #TEXT_ALIGNMENT_VIEW_END} 22471 * 22472 * @attr ref android.R.styleable#View_textAlignment 22473 */ 22474 @ViewDebug.ExportedProperty(category = "text", mapping = { 22475 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22476 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22477 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22478 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22479 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22480 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22481 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22482 }) 22483 @TextAlignment 22484 public int getTextAlignment() { 22485 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 22486 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 22487 } 22488 22489 /** 22490 * Resolve the text alignment. 22491 * 22492 * @return true if resolution has been done, false otherwise. 22493 * 22494 * @hide 22495 */ 22496 public boolean resolveTextAlignment() { 22497 // Reset any previous text alignment resolution 22498 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22499 22500 if (hasRtlSupport()) { 22501 // Set resolved text alignment flag depending on text alignment flag 22502 final int textAlignment = getRawTextAlignment(); 22503 switch (textAlignment) { 22504 case TEXT_ALIGNMENT_INHERIT: 22505 // Check if we can resolve the text alignment 22506 if (!canResolveTextAlignment()) { 22507 // We cannot do the resolution if there is no parent so use the default 22508 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22509 // Resolution will need to happen again later 22510 return false; 22511 } 22512 22513 // Parent has not yet resolved, so we still return the default 22514 try { 22515 if (!mParent.isTextAlignmentResolved()) { 22516 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22517 // Resolution will need to happen again later 22518 return false; 22519 } 22520 } catch (AbstractMethodError e) { 22521 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22522 " does not fully implement ViewParent", e); 22523 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 22524 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22525 return true; 22526 } 22527 22528 int parentResolvedTextAlignment; 22529 try { 22530 parentResolvedTextAlignment = mParent.getTextAlignment(); 22531 } catch (AbstractMethodError e) { 22532 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22533 " does not fully implement ViewParent", e); 22534 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 22535 } 22536 switch (parentResolvedTextAlignment) { 22537 case TEXT_ALIGNMENT_GRAVITY: 22538 case TEXT_ALIGNMENT_TEXT_START: 22539 case TEXT_ALIGNMENT_TEXT_END: 22540 case TEXT_ALIGNMENT_CENTER: 22541 case TEXT_ALIGNMENT_VIEW_START: 22542 case TEXT_ALIGNMENT_VIEW_END: 22543 // Resolved text alignment is the same as the parent resolved 22544 // text alignment 22545 mPrivateFlags2 |= 22546 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22547 break; 22548 default: 22549 // Use default resolved text alignment 22550 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22551 } 22552 break; 22553 case TEXT_ALIGNMENT_GRAVITY: 22554 case TEXT_ALIGNMENT_TEXT_START: 22555 case TEXT_ALIGNMENT_TEXT_END: 22556 case TEXT_ALIGNMENT_CENTER: 22557 case TEXT_ALIGNMENT_VIEW_START: 22558 case TEXT_ALIGNMENT_VIEW_END: 22559 // Resolved text alignment is the same as text alignment 22560 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22561 break; 22562 default: 22563 // Use default resolved text alignment 22564 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22565 } 22566 } else { 22567 // Use default resolved text alignment 22568 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22569 } 22570 22571 // Set the resolved 22572 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22573 return true; 22574 } 22575 22576 /** 22577 * Check if text alignment resolution can be done. 22578 * 22579 * @return true if text alignment resolution can be done otherwise return false. 22580 */ 22581 public boolean canResolveTextAlignment() { 22582 switch (getRawTextAlignment()) { 22583 case TEXT_DIRECTION_INHERIT: 22584 if (mParent != null) { 22585 try { 22586 return mParent.canResolveTextAlignment(); 22587 } catch (AbstractMethodError e) { 22588 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22589 " does not fully implement ViewParent", e); 22590 } 22591 } 22592 return false; 22593 22594 default: 22595 return true; 22596 } 22597 } 22598 22599 /** 22600 * Reset resolved text alignment. Text alignment will be resolved during a call to 22601 * {@link #onMeasure(int, int)}. 22602 * 22603 * @hide 22604 */ 22605 public void resetResolvedTextAlignment() { 22606 // Reset any previous text alignment resolution 22607 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22608 // Set to default 22609 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22610 } 22611 22612 /** 22613 * @return true if text alignment is inherited. 22614 * 22615 * @hide 22616 */ 22617 public boolean isTextAlignmentInherited() { 22618 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 22619 } 22620 22621 /** 22622 * @return true if text alignment is resolved. 22623 */ 22624 public boolean isTextAlignmentResolved() { 22625 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22626 } 22627 22628 /** 22629 * Generate a value suitable for use in {@link #setId(int)}. 22630 * This value will not collide with ID values generated at build time by aapt for R.id. 22631 * 22632 * @return a generated ID value 22633 */ 22634 public static int generateViewId() { 22635 for (;;) { 22636 final int result = sNextGeneratedId.get(); 22637 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 22638 int newValue = result + 1; 22639 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 22640 if (sNextGeneratedId.compareAndSet(result, newValue)) { 22641 return result; 22642 } 22643 } 22644 } 22645 22646 private static boolean isViewIdGenerated(int id) { 22647 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 22648 } 22649 22650 /** 22651 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 22652 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 22653 * a normal View or a ViewGroup with 22654 * {@link android.view.ViewGroup#isTransitionGroup()} true. 22655 * @hide 22656 */ 22657 public void captureTransitioningViews(List<View> transitioningViews) { 22658 if (getVisibility() == View.VISIBLE) { 22659 transitioningViews.add(this); 22660 } 22661 } 22662 22663 /** 22664 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 22665 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 22666 * @hide 22667 */ 22668 public void findNamedViews(Map<String, View> namedElements) { 22669 if (getVisibility() == VISIBLE || mGhostView != null) { 22670 String transitionName = getTransitionName(); 22671 if (transitionName != null) { 22672 namedElements.put(transitionName, this); 22673 } 22674 } 22675 } 22676 22677 /** 22678 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 22679 * The default implementation does not care the location or event types, but some subclasses 22680 * may use it (such as WebViews). 22681 * @param event The MotionEvent from a mouse 22682 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 22683 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 22684 * @see PointerIcon 22685 */ 22686 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 22687 final float x = event.getX(pointerIndex); 22688 final float y = event.getY(pointerIndex); 22689 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 22690 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 22691 } 22692 return mPointerIcon; 22693 } 22694 22695 /** 22696 * Set the pointer icon for the current view. 22697 * Passing {@code null} will restore the pointer icon to its default value. 22698 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 22699 */ 22700 public void setPointerIcon(PointerIcon pointerIcon) { 22701 mPointerIcon = pointerIcon; 22702 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 22703 return; 22704 } 22705 try { 22706 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 22707 } catch (RemoteException e) { 22708 } 22709 } 22710 22711 /** 22712 * Gets the pointer icon for the current view. 22713 */ 22714 public PointerIcon getPointerIcon() { 22715 return mPointerIcon; 22716 } 22717 22718 // 22719 // Properties 22720 // 22721 /** 22722 * A Property wrapper around the <code>alpha</code> functionality handled by the 22723 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 22724 */ 22725 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 22726 @Override 22727 public void setValue(View object, float value) { 22728 object.setAlpha(value); 22729 } 22730 22731 @Override 22732 public Float get(View object) { 22733 return object.getAlpha(); 22734 } 22735 }; 22736 22737 /** 22738 * A Property wrapper around the <code>translationX</code> functionality handled by the 22739 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 22740 */ 22741 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 22742 @Override 22743 public void setValue(View object, float value) { 22744 object.setTranslationX(value); 22745 } 22746 22747 @Override 22748 public Float get(View object) { 22749 return object.getTranslationX(); 22750 } 22751 }; 22752 22753 /** 22754 * A Property wrapper around the <code>translationY</code> functionality handled by the 22755 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 22756 */ 22757 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 22758 @Override 22759 public void setValue(View object, float value) { 22760 object.setTranslationY(value); 22761 } 22762 22763 @Override 22764 public Float get(View object) { 22765 return object.getTranslationY(); 22766 } 22767 }; 22768 22769 /** 22770 * A Property wrapper around the <code>translationZ</code> functionality handled by the 22771 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 22772 */ 22773 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 22774 @Override 22775 public void setValue(View object, float value) { 22776 object.setTranslationZ(value); 22777 } 22778 22779 @Override 22780 public Float get(View object) { 22781 return object.getTranslationZ(); 22782 } 22783 }; 22784 22785 /** 22786 * A Property wrapper around the <code>x</code> functionality handled by the 22787 * {@link View#setX(float)} and {@link View#getX()} methods. 22788 */ 22789 public static final Property<View, Float> X = new FloatProperty<View>("x") { 22790 @Override 22791 public void setValue(View object, float value) { 22792 object.setX(value); 22793 } 22794 22795 @Override 22796 public Float get(View object) { 22797 return object.getX(); 22798 } 22799 }; 22800 22801 /** 22802 * A Property wrapper around the <code>y</code> functionality handled by the 22803 * {@link View#setY(float)} and {@link View#getY()} methods. 22804 */ 22805 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 22806 @Override 22807 public void setValue(View object, float value) { 22808 object.setY(value); 22809 } 22810 22811 @Override 22812 public Float get(View object) { 22813 return object.getY(); 22814 } 22815 }; 22816 22817 /** 22818 * A Property wrapper around the <code>z</code> functionality handled by the 22819 * {@link View#setZ(float)} and {@link View#getZ()} methods. 22820 */ 22821 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 22822 @Override 22823 public void setValue(View object, float value) { 22824 object.setZ(value); 22825 } 22826 22827 @Override 22828 public Float get(View object) { 22829 return object.getZ(); 22830 } 22831 }; 22832 22833 /** 22834 * A Property wrapper around the <code>rotation</code> functionality handled by the 22835 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 22836 */ 22837 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 22838 @Override 22839 public void setValue(View object, float value) { 22840 object.setRotation(value); 22841 } 22842 22843 @Override 22844 public Float get(View object) { 22845 return object.getRotation(); 22846 } 22847 }; 22848 22849 /** 22850 * A Property wrapper around the <code>rotationX</code> functionality handled by the 22851 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 22852 */ 22853 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 22854 @Override 22855 public void setValue(View object, float value) { 22856 object.setRotationX(value); 22857 } 22858 22859 @Override 22860 public Float get(View object) { 22861 return object.getRotationX(); 22862 } 22863 }; 22864 22865 /** 22866 * A Property wrapper around the <code>rotationY</code> functionality handled by the 22867 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 22868 */ 22869 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 22870 @Override 22871 public void setValue(View object, float value) { 22872 object.setRotationY(value); 22873 } 22874 22875 @Override 22876 public Float get(View object) { 22877 return object.getRotationY(); 22878 } 22879 }; 22880 22881 /** 22882 * A Property wrapper around the <code>scaleX</code> functionality handled by the 22883 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 22884 */ 22885 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 22886 @Override 22887 public void setValue(View object, float value) { 22888 object.setScaleX(value); 22889 } 22890 22891 @Override 22892 public Float get(View object) { 22893 return object.getScaleX(); 22894 } 22895 }; 22896 22897 /** 22898 * A Property wrapper around the <code>scaleY</code> functionality handled by the 22899 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 22900 */ 22901 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 22902 @Override 22903 public void setValue(View object, float value) { 22904 object.setScaleY(value); 22905 } 22906 22907 @Override 22908 public Float get(View object) { 22909 return object.getScaleY(); 22910 } 22911 }; 22912 22913 /** 22914 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 22915 * Each MeasureSpec represents a requirement for either the width or the height. 22916 * A MeasureSpec is comprised of a size and a mode. There are three possible 22917 * modes: 22918 * <dl> 22919 * <dt>UNSPECIFIED</dt> 22920 * <dd> 22921 * The parent has not imposed any constraint on the child. It can be whatever size 22922 * it wants. 22923 * </dd> 22924 * 22925 * <dt>EXACTLY</dt> 22926 * <dd> 22927 * The parent has determined an exact size for the child. The child is going to be 22928 * given those bounds regardless of how big it wants to be. 22929 * </dd> 22930 * 22931 * <dt>AT_MOST</dt> 22932 * <dd> 22933 * The child can be as large as it wants up to the specified size. 22934 * </dd> 22935 * </dl> 22936 * 22937 * MeasureSpecs are implemented as ints to reduce object allocation. This class 22938 * is provided to pack and unpack the <size, mode> tuple into the int. 22939 */ 22940 public static class MeasureSpec { 22941 private static final int MODE_SHIFT = 30; 22942 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 22943 22944 /** @hide */ 22945 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 22946 @Retention(RetentionPolicy.SOURCE) 22947 public @interface MeasureSpecMode {} 22948 22949 /** 22950 * Measure specification mode: The parent has not imposed any constraint 22951 * on the child. It can be whatever size it wants. 22952 */ 22953 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 22954 22955 /** 22956 * Measure specification mode: The parent has determined an exact size 22957 * for the child. The child is going to be given those bounds regardless 22958 * of how big it wants to be. 22959 */ 22960 public static final int EXACTLY = 1 << MODE_SHIFT; 22961 22962 /** 22963 * Measure specification mode: The child can be as large as it wants up 22964 * to the specified size. 22965 */ 22966 public static final int AT_MOST = 2 << MODE_SHIFT; 22967 22968 /** 22969 * Creates a measure specification based on the supplied size and mode. 22970 * 22971 * The mode must always be one of the following: 22972 * <ul> 22973 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 22974 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 22975 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 22976 * </ul> 22977 * 22978 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 22979 * implementation was such that the order of arguments did not matter 22980 * and overflow in either value could impact the resulting MeasureSpec. 22981 * {@link android.widget.RelativeLayout} was affected by this bug. 22982 * Apps targeting API levels greater than 17 will get the fixed, more strict 22983 * behavior.</p> 22984 * 22985 * @param size the size of the measure specification 22986 * @param mode the mode of the measure specification 22987 * @return the measure specification based on size and mode 22988 */ 22989 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 22990 @MeasureSpecMode int mode) { 22991 if (sUseBrokenMakeMeasureSpec) { 22992 return size + mode; 22993 } else { 22994 return (size & ~MODE_MASK) | (mode & MODE_MASK); 22995 } 22996 } 22997 22998 /** 22999 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 23000 * will automatically get a size of 0. Older apps expect this. 23001 * 23002 * @hide internal use only for compatibility with system widgets and older apps 23003 */ 23004 public static int makeSafeMeasureSpec(int size, int mode) { 23005 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 23006 return 0; 23007 } 23008 return makeMeasureSpec(size, mode); 23009 } 23010 23011 /** 23012 * Extracts the mode from the supplied measure specification. 23013 * 23014 * @param measureSpec the measure specification to extract the mode from 23015 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 23016 * {@link android.view.View.MeasureSpec#AT_MOST} or 23017 * {@link android.view.View.MeasureSpec#EXACTLY} 23018 */ 23019 @MeasureSpecMode 23020 public static int getMode(int measureSpec) { 23021 //noinspection ResourceType 23022 return (measureSpec & MODE_MASK); 23023 } 23024 23025 /** 23026 * Extracts the size from the supplied measure specification. 23027 * 23028 * @param measureSpec the measure specification to extract the size from 23029 * @return the size in pixels defined in the supplied measure specification 23030 */ 23031 public static int getSize(int measureSpec) { 23032 return (measureSpec & ~MODE_MASK); 23033 } 23034 23035 static int adjust(int measureSpec, int delta) { 23036 final int mode = getMode(measureSpec); 23037 int size = getSize(measureSpec); 23038 if (mode == UNSPECIFIED) { 23039 // No need to adjust size for UNSPECIFIED mode. 23040 return makeMeasureSpec(size, UNSPECIFIED); 23041 } 23042 size += delta; 23043 if (size < 0) { 23044 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 23045 ") spec: " + toString(measureSpec) + " delta: " + delta); 23046 size = 0; 23047 } 23048 return makeMeasureSpec(size, mode); 23049 } 23050 23051 /** 23052 * Returns a String representation of the specified measure 23053 * specification. 23054 * 23055 * @param measureSpec the measure specification to convert to a String 23056 * @return a String with the following format: "MeasureSpec: MODE SIZE" 23057 */ 23058 public static String toString(int measureSpec) { 23059 int mode = getMode(measureSpec); 23060 int size = getSize(measureSpec); 23061 23062 StringBuilder sb = new StringBuilder("MeasureSpec: "); 23063 23064 if (mode == UNSPECIFIED) 23065 sb.append("UNSPECIFIED "); 23066 else if (mode == EXACTLY) 23067 sb.append("EXACTLY "); 23068 else if (mode == AT_MOST) 23069 sb.append("AT_MOST "); 23070 else 23071 sb.append(mode).append(" "); 23072 23073 sb.append(size); 23074 return sb.toString(); 23075 } 23076 } 23077 23078 private final class CheckForLongPress implements Runnable { 23079 private int mOriginalWindowAttachCount; 23080 private float mX; 23081 private float mY; 23082 private boolean mOriginalPressedState; 23083 23084 @Override 23085 public void run() { 23086 if ((mOriginalPressedState == isPressed()) && (mParent != null) 23087 && mOriginalWindowAttachCount == mWindowAttachCount) { 23088 if (performLongClick(mX, mY)) { 23089 mHasPerformedLongPress = true; 23090 } 23091 } 23092 } 23093 23094 public void setAnchor(float x, float y) { 23095 mX = x; 23096 mY = y; 23097 } 23098 23099 public void rememberWindowAttachCount() { 23100 mOriginalWindowAttachCount = mWindowAttachCount; 23101 } 23102 23103 public void rememberPressedState() { 23104 mOriginalPressedState = isPressed(); 23105 } 23106 } 23107 23108 private final class CheckForTap implements Runnable { 23109 public float x; 23110 public float y; 23111 23112 @Override 23113 public void run() { 23114 mPrivateFlags &= ~PFLAG_PREPRESSED; 23115 setPressed(true, x, y); 23116 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 23117 } 23118 } 23119 23120 private final class PerformClick implements Runnable { 23121 @Override 23122 public void run() { 23123 performClick(); 23124 } 23125 } 23126 23127 /** 23128 * This method returns a ViewPropertyAnimator object, which can be used to animate 23129 * specific properties on this View. 23130 * 23131 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 23132 */ 23133 public ViewPropertyAnimator animate() { 23134 if (mAnimator == null) { 23135 mAnimator = new ViewPropertyAnimator(this); 23136 } 23137 return mAnimator; 23138 } 23139 23140 /** 23141 * Sets the name of the View to be used to identify Views in Transitions. 23142 * Names should be unique in the View hierarchy. 23143 * 23144 * @param transitionName The name of the View to uniquely identify it for Transitions. 23145 */ 23146 public final void setTransitionName(String transitionName) { 23147 mTransitionName = transitionName; 23148 } 23149 23150 /** 23151 * Returns the name of the View to be used to identify Views in Transitions. 23152 * Names should be unique in the View hierarchy. 23153 * 23154 * <p>This returns null if the View has not been given a name.</p> 23155 * 23156 * @return The name used of the View to be used to identify Views in Transitions or null 23157 * if no name has been given. 23158 */ 23159 @ViewDebug.ExportedProperty 23160 public String getTransitionName() { 23161 return mTransitionName; 23162 } 23163 23164 /** 23165 * @hide 23166 */ 23167 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 23168 // Do nothing. 23169 } 23170 23171 /** 23172 * Interface definition for a callback to be invoked when a hardware key event is 23173 * dispatched to this view. The callback will be invoked before the key event is 23174 * given to the view. This is only useful for hardware keyboards; a software input 23175 * method has no obligation to trigger this listener. 23176 */ 23177 public interface OnKeyListener { 23178 /** 23179 * Called when a hardware key is dispatched to a view. This allows listeners to 23180 * get a chance to respond before the target view. 23181 * <p>Key presses in software keyboards will generally NOT trigger this method, 23182 * although some may elect to do so in some situations. Do not assume a 23183 * software input method has to be key-based; even if it is, it may use key presses 23184 * in a different way than you expect, so there is no way to reliably catch soft 23185 * input key presses. 23186 * 23187 * @param v The view the key has been dispatched to. 23188 * @param keyCode The code for the physical key that was pressed 23189 * @param event The KeyEvent object containing full information about 23190 * the event. 23191 * @return True if the listener has consumed the event, false otherwise. 23192 */ 23193 boolean onKey(View v, int keyCode, KeyEvent event); 23194 } 23195 23196 /** 23197 * Interface definition for a callback to be invoked when a touch event is 23198 * dispatched to this view. The callback will be invoked before the touch 23199 * event is given to the view. 23200 */ 23201 public interface OnTouchListener { 23202 /** 23203 * Called when a touch event is dispatched to a view. This allows listeners to 23204 * get a chance to respond before the target view. 23205 * 23206 * @param v The view the touch event has been dispatched to. 23207 * @param event The MotionEvent object containing full information about 23208 * the event. 23209 * @return True if the listener has consumed the event, false otherwise. 23210 */ 23211 boolean onTouch(View v, MotionEvent event); 23212 } 23213 23214 /** 23215 * Interface definition for a callback to be invoked when a hover event is 23216 * dispatched to this view. The callback will be invoked before the hover 23217 * event is given to the view. 23218 */ 23219 public interface OnHoverListener { 23220 /** 23221 * Called when a hover event is dispatched to a view. This allows listeners to 23222 * get a chance to respond before the target view. 23223 * 23224 * @param v The view the hover event has been dispatched to. 23225 * @param event The MotionEvent object containing full information about 23226 * the event. 23227 * @return True if the listener has consumed the event, false otherwise. 23228 */ 23229 boolean onHover(View v, MotionEvent event); 23230 } 23231 23232 /** 23233 * Interface definition for a callback to be invoked when a generic motion event is 23234 * dispatched to this view. The callback will be invoked before the generic motion 23235 * event is given to the view. 23236 */ 23237 public interface OnGenericMotionListener { 23238 /** 23239 * Called when a generic motion event is dispatched to a view. This allows listeners to 23240 * get a chance to respond before the target view. 23241 * 23242 * @param v The view the generic motion event has been dispatched to. 23243 * @param event The MotionEvent object containing full information about 23244 * the event. 23245 * @return True if the listener has consumed the event, false otherwise. 23246 */ 23247 boolean onGenericMotion(View v, MotionEvent event); 23248 } 23249 23250 /** 23251 * Interface definition for a callback to be invoked when a view has been clicked and held. 23252 */ 23253 public interface OnLongClickListener { 23254 /** 23255 * Called when a view has been clicked and held. 23256 * 23257 * @param v The view that was clicked and held. 23258 * 23259 * @return true if the callback consumed the long click, false otherwise. 23260 */ 23261 boolean onLongClick(View v); 23262 } 23263 23264 /** 23265 * Interface definition for a callback to be invoked when a drag is being dispatched 23266 * to this view. The callback will be invoked before the hosting view's own 23267 * onDrag(event) method. If the listener wants to fall back to the hosting view's 23268 * onDrag(event) behavior, it should return 'false' from this callback. 23269 * 23270 * <div class="special reference"> 23271 * <h3>Developer Guides</h3> 23272 * <p>For a guide to implementing drag and drop features, read the 23273 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 23274 * </div> 23275 */ 23276 public interface OnDragListener { 23277 /** 23278 * Called when a drag event is dispatched to a view. This allows listeners 23279 * to get a chance to override base View behavior. 23280 * 23281 * @param v The View that received the drag event. 23282 * @param event The {@link android.view.DragEvent} object for the drag event. 23283 * @return {@code true} if the drag event was handled successfully, or {@code false} 23284 * if the drag event was not handled. Note that {@code false} will trigger the View 23285 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 23286 */ 23287 boolean onDrag(View v, DragEvent event); 23288 } 23289 23290 /** 23291 * Interface definition for a callback to be invoked when the focus state of 23292 * a view changed. 23293 */ 23294 public interface OnFocusChangeListener { 23295 /** 23296 * Called when the focus state of a view has changed. 23297 * 23298 * @param v The view whose state has changed. 23299 * @param hasFocus The new focus state of v. 23300 */ 23301 void onFocusChange(View v, boolean hasFocus); 23302 } 23303 23304 /** 23305 * Interface definition for a callback to be invoked when a view is clicked. 23306 */ 23307 public interface OnClickListener { 23308 /** 23309 * Called when a view has been clicked. 23310 * 23311 * @param v The view that was clicked. 23312 */ 23313 void onClick(View v); 23314 } 23315 23316 /** 23317 * Interface definition for a callback to be invoked when a view is context clicked. 23318 */ 23319 public interface OnContextClickListener { 23320 /** 23321 * Called when a view is context clicked. 23322 * 23323 * @param v The view that has been context clicked. 23324 * @return true if the callback consumed the context click, false otherwise. 23325 */ 23326 boolean onContextClick(View v); 23327 } 23328 23329 /** 23330 * Interface definition for a callback to be invoked when the context menu 23331 * for this view is being built. 23332 */ 23333 public interface OnCreateContextMenuListener { 23334 /** 23335 * Called when the context menu for this view is being built. It is not 23336 * safe to hold onto the menu after this method returns. 23337 * 23338 * @param menu The context menu that is being built 23339 * @param v The view for which the context menu is being built 23340 * @param menuInfo Extra information about the item for which the 23341 * context menu should be shown. This information will vary 23342 * depending on the class of v. 23343 */ 23344 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 23345 } 23346 23347 /** 23348 * Interface definition for a callback to be invoked when the status bar changes 23349 * visibility. This reports <strong>global</strong> changes to the system UI 23350 * state, not what the application is requesting. 23351 * 23352 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 23353 */ 23354 public interface OnSystemUiVisibilityChangeListener { 23355 /** 23356 * Called when the status bar changes visibility because of a call to 23357 * {@link View#setSystemUiVisibility(int)}. 23358 * 23359 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 23360 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 23361 * This tells you the <strong>global</strong> state of these UI visibility 23362 * flags, not what your app is currently applying. 23363 */ 23364 public void onSystemUiVisibilityChange(int visibility); 23365 } 23366 23367 /** 23368 * Interface definition for a callback to be invoked when this view is attached 23369 * or detached from its window. 23370 */ 23371 public interface OnAttachStateChangeListener { 23372 /** 23373 * Called when the view is attached to a window. 23374 * @param v The view that was attached 23375 */ 23376 public void onViewAttachedToWindow(View v); 23377 /** 23378 * Called when the view is detached from a window. 23379 * @param v The view that was detached 23380 */ 23381 public void onViewDetachedFromWindow(View v); 23382 } 23383 23384 /** 23385 * Listener for applying window insets on a view in a custom way. 23386 * 23387 * <p>Apps may choose to implement this interface if they want to apply custom policy 23388 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 23389 * is set, its 23390 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 23391 * method will be called instead of the View's own 23392 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 23393 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 23394 * the View's normal behavior as part of its own.</p> 23395 */ 23396 public interface OnApplyWindowInsetsListener { 23397 /** 23398 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 23399 * on a View, this listener method will be called instead of the view's own 23400 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 23401 * 23402 * @param v The view applying window insets 23403 * @param insets The insets to apply 23404 * @return The insets supplied, minus any insets that were consumed 23405 */ 23406 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 23407 } 23408 23409 private final class UnsetPressedState implements Runnable { 23410 @Override 23411 public void run() { 23412 setPressed(false); 23413 } 23414 } 23415 23416 /** 23417 * Base class for derived classes that want to save and restore their own 23418 * state in {@link android.view.View#onSaveInstanceState()}. 23419 */ 23420 public static class BaseSavedState extends AbsSavedState { 23421 String mStartActivityRequestWhoSaved; 23422 23423 /** 23424 * Constructor used when reading from a parcel. Reads the state of the superclass. 23425 * 23426 * @param source parcel to read from 23427 */ 23428 public BaseSavedState(Parcel source) { 23429 this(source, null); 23430 } 23431 23432 /** 23433 * Constructor used when reading from a parcel using a given class loader. 23434 * Reads the state of the superclass. 23435 * 23436 * @param source parcel to read from 23437 * @param loader ClassLoader to use for reading 23438 */ 23439 public BaseSavedState(Parcel source, ClassLoader loader) { 23440 super(source, loader); 23441 mStartActivityRequestWhoSaved = source.readString(); 23442 } 23443 23444 /** 23445 * Constructor called by derived classes when creating their SavedState objects 23446 * 23447 * @param superState The state of the superclass of this view 23448 */ 23449 public BaseSavedState(Parcelable superState) { 23450 super(superState); 23451 } 23452 23453 @Override 23454 public void writeToParcel(Parcel out, int flags) { 23455 super.writeToParcel(out, flags); 23456 out.writeString(mStartActivityRequestWhoSaved); 23457 } 23458 23459 public static final Parcelable.Creator<BaseSavedState> CREATOR 23460 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 23461 @Override 23462 public BaseSavedState createFromParcel(Parcel in) { 23463 return new BaseSavedState(in); 23464 } 23465 23466 @Override 23467 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 23468 return new BaseSavedState(in, loader); 23469 } 23470 23471 @Override 23472 public BaseSavedState[] newArray(int size) { 23473 return new BaseSavedState[size]; 23474 } 23475 }; 23476 } 23477 23478 /** 23479 * A set of information given to a view when it is attached to its parent 23480 * window. 23481 */ 23482 final static class AttachInfo { 23483 interface Callbacks { 23484 void playSoundEffect(int effectId); 23485 boolean performHapticFeedback(int effectId, boolean always); 23486 } 23487 23488 /** 23489 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 23490 * to a Handler. This class contains the target (View) to invalidate and 23491 * the coordinates of the dirty rectangle. 23492 * 23493 * For performance purposes, this class also implements a pool of up to 23494 * POOL_LIMIT objects that get reused. This reduces memory allocations 23495 * whenever possible. 23496 */ 23497 static class InvalidateInfo { 23498 private static final int POOL_LIMIT = 10; 23499 23500 private static final SynchronizedPool<InvalidateInfo> sPool = 23501 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 23502 23503 View target; 23504 23505 int left; 23506 int top; 23507 int right; 23508 int bottom; 23509 23510 public static InvalidateInfo obtain() { 23511 InvalidateInfo instance = sPool.acquire(); 23512 return (instance != null) ? instance : new InvalidateInfo(); 23513 } 23514 23515 public void recycle() { 23516 target = null; 23517 sPool.release(this); 23518 } 23519 } 23520 23521 final IWindowSession mSession; 23522 23523 final IWindow mWindow; 23524 23525 final IBinder mWindowToken; 23526 23527 final Display mDisplay; 23528 23529 final Callbacks mRootCallbacks; 23530 23531 IWindowId mIWindowId; 23532 WindowId mWindowId; 23533 23534 /** 23535 * The top view of the hierarchy. 23536 */ 23537 View mRootView; 23538 23539 IBinder mPanelParentWindowToken; 23540 23541 boolean mHardwareAccelerated; 23542 boolean mHardwareAccelerationRequested; 23543 ThreadedRenderer mThreadedRenderer; 23544 List<RenderNode> mPendingAnimatingRenderNodes; 23545 23546 /** 23547 * The state of the display to which the window is attached, as reported 23548 * by {@link Display#getState()}. Note that the display state constants 23549 * declared by {@link Display} do not exactly line up with the screen state 23550 * constants declared by {@link View} (there are more display states than 23551 * screen states). 23552 */ 23553 int mDisplayState = Display.STATE_UNKNOWN; 23554 23555 /** 23556 * Scale factor used by the compatibility mode 23557 */ 23558 float mApplicationScale; 23559 23560 /** 23561 * Indicates whether the application is in compatibility mode 23562 */ 23563 boolean mScalingRequired; 23564 23565 /** 23566 * Left position of this view's window 23567 */ 23568 int mWindowLeft; 23569 23570 /** 23571 * Top position of this view's window 23572 */ 23573 int mWindowTop; 23574 23575 /** 23576 * Indicates whether views need to use 32-bit drawing caches 23577 */ 23578 boolean mUse32BitDrawingCache; 23579 23580 /** 23581 * For windows that are full-screen but using insets to layout inside 23582 * of the screen areas, these are the current insets to appear inside 23583 * the overscan area of the display. 23584 */ 23585 final Rect mOverscanInsets = new Rect(); 23586 23587 /** 23588 * For windows that are full-screen but using insets to layout inside 23589 * of the screen decorations, these are the current insets for the 23590 * content of the window. 23591 */ 23592 final Rect mContentInsets = new Rect(); 23593 23594 /** 23595 * For windows that are full-screen but using insets to layout inside 23596 * of the screen decorations, these are the current insets for the 23597 * actual visible parts of the window. 23598 */ 23599 final Rect mVisibleInsets = new Rect(); 23600 23601 /** 23602 * For windows that are full-screen but using insets to layout inside 23603 * of the screen decorations, these are the current insets for the 23604 * stable system windows. 23605 */ 23606 final Rect mStableInsets = new Rect(); 23607 23608 /** 23609 * For windows that include areas that are not covered by real surface these are the outsets 23610 * for real surface. 23611 */ 23612 final Rect mOutsets = new Rect(); 23613 23614 /** 23615 * In multi-window we force show the navigation bar. Because we don't want that the surface 23616 * size changes in this mode, we instead have a flag whether the navigation bar size should 23617 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 23618 */ 23619 boolean mAlwaysConsumeNavBar; 23620 23621 /** 23622 * The internal insets given by this window. This value is 23623 * supplied by the client (through 23624 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 23625 * be given to the window manager when changed to be used in laying 23626 * out windows behind it. 23627 */ 23628 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 23629 = new ViewTreeObserver.InternalInsetsInfo(); 23630 23631 /** 23632 * Set to true when mGivenInternalInsets is non-empty. 23633 */ 23634 boolean mHasNonEmptyGivenInternalInsets; 23635 23636 /** 23637 * All views in the window's hierarchy that serve as scroll containers, 23638 * used to determine if the window can be resized or must be panned 23639 * to adjust for a soft input area. 23640 */ 23641 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 23642 23643 final KeyEvent.DispatcherState mKeyDispatchState 23644 = new KeyEvent.DispatcherState(); 23645 23646 /** 23647 * Indicates whether the view's window currently has the focus. 23648 */ 23649 boolean mHasWindowFocus; 23650 23651 /** 23652 * The current visibility of the window. 23653 */ 23654 int mWindowVisibility; 23655 23656 /** 23657 * Indicates the time at which drawing started to occur. 23658 */ 23659 long mDrawingTime; 23660 23661 /** 23662 * Indicates whether or not ignoring the DIRTY_MASK flags. 23663 */ 23664 boolean mIgnoreDirtyState; 23665 23666 /** 23667 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 23668 * to avoid clearing that flag prematurely. 23669 */ 23670 boolean mSetIgnoreDirtyState = false; 23671 23672 /** 23673 * Indicates whether the view's window is currently in touch mode. 23674 */ 23675 boolean mInTouchMode; 23676 23677 /** 23678 * Indicates whether the view has requested unbuffered input dispatching for the current 23679 * event stream. 23680 */ 23681 boolean mUnbufferedDispatchRequested; 23682 23683 /** 23684 * Indicates that ViewAncestor should trigger a global layout change 23685 * the next time it performs a traversal 23686 */ 23687 boolean mRecomputeGlobalAttributes; 23688 23689 /** 23690 * Always report new attributes at next traversal. 23691 */ 23692 boolean mForceReportNewAttributes; 23693 23694 /** 23695 * Set during a traveral if any views want to keep the screen on. 23696 */ 23697 boolean mKeepScreenOn; 23698 23699 /** 23700 * Set during a traveral if the light center needs to be updated. 23701 */ 23702 boolean mNeedsUpdateLightCenter; 23703 23704 /** 23705 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 23706 */ 23707 int mSystemUiVisibility; 23708 23709 /** 23710 * Hack to force certain system UI visibility flags to be cleared. 23711 */ 23712 int mDisabledSystemUiVisibility; 23713 23714 /** 23715 * Last global system UI visibility reported by the window manager. 23716 */ 23717 int mGlobalSystemUiVisibility = -1; 23718 23719 /** 23720 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 23721 * attached. 23722 */ 23723 boolean mHasSystemUiListeners; 23724 23725 /** 23726 * Set if the window has requested to extend into the overscan region 23727 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 23728 */ 23729 boolean mOverscanRequested; 23730 23731 /** 23732 * Set if the visibility of any views has changed. 23733 */ 23734 boolean mViewVisibilityChanged; 23735 23736 /** 23737 * Set to true if a view has been scrolled. 23738 */ 23739 boolean mViewScrollChanged; 23740 23741 /** 23742 * Set to true if high contrast mode enabled 23743 */ 23744 boolean mHighContrastText; 23745 23746 /** 23747 * Set to true if a pointer event is currently being handled. 23748 */ 23749 boolean mHandlingPointerEvent; 23750 23751 /** 23752 * Global to the view hierarchy used as a temporary for dealing with 23753 * x/y points in the transparent region computations. 23754 */ 23755 final int[] mTransparentLocation = new int[2]; 23756 23757 /** 23758 * Global to the view hierarchy used as a temporary for dealing with 23759 * x/y points in the ViewGroup.invalidateChild implementation. 23760 */ 23761 final int[] mInvalidateChildLocation = new int[2]; 23762 23763 /** 23764 * Global to the view hierarchy used as a temporary for dealing with 23765 * computing absolute on-screen location. 23766 */ 23767 final int[] mTmpLocation = new int[2]; 23768 23769 /** 23770 * Global to the view hierarchy used as a temporary for dealing with 23771 * x/y location when view is transformed. 23772 */ 23773 final float[] mTmpTransformLocation = new float[2]; 23774 23775 /** 23776 * The view tree observer used to dispatch global events like 23777 * layout, pre-draw, touch mode change, etc. 23778 */ 23779 final ViewTreeObserver mTreeObserver; 23780 23781 /** 23782 * A Canvas used by the view hierarchy to perform bitmap caching. 23783 */ 23784 Canvas mCanvas; 23785 23786 /** 23787 * The view root impl. 23788 */ 23789 final ViewRootImpl mViewRootImpl; 23790 23791 /** 23792 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 23793 * handler can be used to pump events in the UI events queue. 23794 */ 23795 final Handler mHandler; 23796 23797 /** 23798 * Temporary for use in computing invalidate rectangles while 23799 * calling up the hierarchy. 23800 */ 23801 final Rect mTmpInvalRect = new Rect(); 23802 23803 /** 23804 * Temporary for use in computing hit areas with transformed views 23805 */ 23806 final RectF mTmpTransformRect = new RectF(); 23807 23808 /** 23809 * Temporary for use in computing hit areas with transformed views 23810 */ 23811 final RectF mTmpTransformRect1 = new RectF(); 23812 23813 /** 23814 * Temporary list of rectanges. 23815 */ 23816 final List<RectF> mTmpRectList = new ArrayList<>(); 23817 23818 /** 23819 * Temporary for use in transforming invalidation rect 23820 */ 23821 final Matrix mTmpMatrix = new Matrix(); 23822 23823 /** 23824 * Temporary for use in transforming invalidation rect 23825 */ 23826 final Transformation mTmpTransformation = new Transformation(); 23827 23828 /** 23829 * Temporary for use in querying outlines from OutlineProviders 23830 */ 23831 final Outline mTmpOutline = new Outline(); 23832 23833 /** 23834 * Temporary list for use in collecting focusable descendents of a view. 23835 */ 23836 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 23837 23838 /** 23839 * The id of the window for accessibility purposes. 23840 */ 23841 int mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 23842 23843 /** 23844 * Flags related to accessibility processing. 23845 * 23846 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 23847 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 23848 */ 23849 int mAccessibilityFetchFlags; 23850 23851 /** 23852 * The drawable for highlighting accessibility focus. 23853 */ 23854 Drawable mAccessibilityFocusDrawable; 23855 23856 /** 23857 * Show where the margins, bounds and layout bounds are for each view. 23858 */ 23859 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 23860 23861 /** 23862 * Point used to compute visible regions. 23863 */ 23864 final Point mPoint = new Point(); 23865 23866 /** 23867 * Used to track which View originated a requestLayout() call, used when 23868 * requestLayout() is called during layout. 23869 */ 23870 View mViewRequestingLayout; 23871 23872 /** 23873 * Used to track views that need (at least) a partial relayout at their current size 23874 * during the next traversal. 23875 */ 23876 List<View> mPartialLayoutViews = new ArrayList<>(); 23877 23878 /** 23879 * Swapped with mPartialLayoutViews during layout to avoid concurrent 23880 * modification. Lazily assigned during ViewRootImpl layout. 23881 */ 23882 List<View> mEmptyPartialLayoutViews; 23883 23884 /** 23885 * Used to track the identity of the current drag operation. 23886 */ 23887 IBinder mDragToken; 23888 23889 /** 23890 * The drag shadow surface for the current drag operation. 23891 */ 23892 public Surface mDragSurface; 23893 23894 23895 /** 23896 * The view that currently has a tooltip displayed. 23897 */ 23898 View mTooltipHost; 23899 23900 /** 23901 * Creates a new set of attachment information with the specified 23902 * events handler and thread. 23903 * 23904 * @param handler the events handler the view must use 23905 */ 23906 AttachInfo(IWindowSession session, IWindow window, Display display, 23907 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 23908 Context context) { 23909 mSession = session; 23910 mWindow = window; 23911 mWindowToken = window.asBinder(); 23912 mDisplay = display; 23913 mViewRootImpl = viewRootImpl; 23914 mHandler = handler; 23915 mRootCallbacks = effectPlayer; 23916 mTreeObserver = new ViewTreeObserver(context); 23917 } 23918 } 23919 23920 /** 23921 * <p>ScrollabilityCache holds various fields used by a View when scrolling 23922 * is supported. This avoids keeping too many unused fields in most 23923 * instances of View.</p> 23924 */ 23925 private static class ScrollabilityCache implements Runnable { 23926 23927 /** 23928 * Scrollbars are not visible 23929 */ 23930 public static final int OFF = 0; 23931 23932 /** 23933 * Scrollbars are visible 23934 */ 23935 public static final int ON = 1; 23936 23937 /** 23938 * Scrollbars are fading away 23939 */ 23940 public static final int FADING = 2; 23941 23942 public boolean fadeScrollBars; 23943 23944 public int fadingEdgeLength; 23945 public int scrollBarDefaultDelayBeforeFade; 23946 public int scrollBarFadeDuration; 23947 23948 public int scrollBarSize; 23949 public ScrollBarDrawable scrollBar; 23950 public float[] interpolatorValues; 23951 public View host; 23952 23953 public final Paint paint; 23954 public final Matrix matrix; 23955 public Shader shader; 23956 23957 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 23958 23959 private static final float[] OPAQUE = { 255 }; 23960 private static final float[] TRANSPARENT = { 0.0f }; 23961 23962 /** 23963 * When fading should start. This time moves into the future every time 23964 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 23965 */ 23966 public long fadeStartTime; 23967 23968 23969 /** 23970 * The current state of the scrollbars: ON, OFF, or FADING 23971 */ 23972 public int state = OFF; 23973 23974 private int mLastColor; 23975 23976 public final Rect mScrollBarBounds = new Rect(); 23977 23978 public static final int NOT_DRAGGING = 0; 23979 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 23980 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 23981 public int mScrollBarDraggingState = NOT_DRAGGING; 23982 23983 public float mScrollBarDraggingPos = 0; 23984 23985 public ScrollabilityCache(ViewConfiguration configuration, View host) { 23986 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 23987 scrollBarSize = configuration.getScaledScrollBarSize(); 23988 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 23989 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 23990 23991 paint = new Paint(); 23992 matrix = new Matrix(); 23993 // use use a height of 1, and then wack the matrix each time we 23994 // actually use it. 23995 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 23996 paint.setShader(shader); 23997 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 23998 23999 this.host = host; 24000 } 24001 24002 public void setFadeColor(int color) { 24003 if (color != mLastColor) { 24004 mLastColor = color; 24005 24006 if (color != 0) { 24007 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 24008 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 24009 paint.setShader(shader); 24010 // Restore the default transfer mode (src_over) 24011 paint.setXfermode(null); 24012 } else { 24013 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 24014 paint.setShader(shader); 24015 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 24016 } 24017 } 24018 } 24019 24020 public void run() { 24021 long now = AnimationUtils.currentAnimationTimeMillis(); 24022 if (now >= fadeStartTime) { 24023 24024 // the animation fades the scrollbars out by changing 24025 // the opacity (alpha) from fully opaque to fully 24026 // transparent 24027 int nextFrame = (int) now; 24028 int framesCount = 0; 24029 24030 Interpolator interpolator = scrollBarInterpolator; 24031 24032 // Start opaque 24033 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 24034 24035 // End transparent 24036 nextFrame += scrollBarFadeDuration; 24037 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 24038 24039 state = FADING; 24040 24041 // Kick off the fade animation 24042 host.invalidate(true); 24043 } 24044 } 24045 } 24046 24047 /** 24048 * Resuable callback for sending 24049 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 24050 */ 24051 private class SendViewScrolledAccessibilityEvent implements Runnable { 24052 public volatile boolean mIsPending; 24053 24054 public void run() { 24055 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 24056 mIsPending = false; 24057 } 24058 } 24059 24060 /** 24061 * <p> 24062 * This class represents a delegate that can be registered in a {@link View} 24063 * to enhance accessibility support via composition rather via inheritance. 24064 * It is specifically targeted to widget developers that extend basic View 24065 * classes i.e. classes in package android.view, that would like their 24066 * applications to be backwards compatible. 24067 * </p> 24068 * <div class="special reference"> 24069 * <h3>Developer Guides</h3> 24070 * <p>For more information about making applications accessible, read the 24071 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 24072 * developer guide.</p> 24073 * </div> 24074 * <p> 24075 * A scenario in which a developer would like to use an accessibility delegate 24076 * is overriding a method introduced in a later API version than the minimal API 24077 * version supported by the application. For example, the method 24078 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 24079 * in API version 4 when the accessibility APIs were first introduced. If a 24080 * developer would like his application to run on API version 4 devices (assuming 24081 * all other APIs used by the application are version 4 or lower) and take advantage 24082 * of this method, instead of overriding the method which would break the application's 24083 * backwards compatibility, he can override the corresponding method in this 24084 * delegate and register the delegate in the target View if the API version of 24085 * the system is high enough, i.e. the API version is the same as or higher than the API 24086 * version that introduced 24087 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 24088 * </p> 24089 * <p> 24090 * Here is an example implementation: 24091 * </p> 24092 * <code><pre><p> 24093 * if (Build.VERSION.SDK_INT >= 14) { 24094 * // If the API version is equal of higher than the version in 24095 * // which onInitializeAccessibilityNodeInfo was introduced we 24096 * // register a delegate with a customized implementation. 24097 * View view = findViewById(R.id.view_id); 24098 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 24099 * public void onInitializeAccessibilityNodeInfo(View host, 24100 * AccessibilityNodeInfo info) { 24101 * // Let the default implementation populate the info. 24102 * super.onInitializeAccessibilityNodeInfo(host, info); 24103 * // Set some other information. 24104 * info.setEnabled(host.isEnabled()); 24105 * } 24106 * }); 24107 * } 24108 * </code></pre></p> 24109 * <p> 24110 * This delegate contains methods that correspond to the accessibility methods 24111 * in View. If a delegate has been specified the implementation in View hands 24112 * off handling to the corresponding method in this delegate. The default 24113 * implementation the delegate methods behaves exactly as the corresponding 24114 * method in View for the case of no accessibility delegate been set. Hence, 24115 * to customize the behavior of a View method, clients can override only the 24116 * corresponding delegate method without altering the behavior of the rest 24117 * accessibility related methods of the host view. 24118 * </p> 24119 * <p> 24120 * <strong>Note:</strong> On platform versions prior to 24121 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 24122 * views in the {@code android.widget.*} package are called <i>before</i> 24123 * host methods. This prevents certain properties such as class name from 24124 * being modified by overriding 24125 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 24126 * as any changes will be overwritten by the host class. 24127 * <p> 24128 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 24129 * methods are called <i>after</i> host methods, which all properties to be 24130 * modified without being overwritten by the host class. 24131 */ 24132 public static class AccessibilityDelegate { 24133 24134 /** 24135 * Sends an accessibility event of the given type. If accessibility is not 24136 * enabled this method has no effect. 24137 * <p> 24138 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 24139 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 24140 * been set. 24141 * </p> 24142 * 24143 * @param host The View hosting the delegate. 24144 * @param eventType The type of the event to send. 24145 * 24146 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 24147 */ 24148 public void sendAccessibilityEvent(View host, int eventType) { 24149 host.sendAccessibilityEventInternal(eventType); 24150 } 24151 24152 /** 24153 * Performs the specified accessibility action on the view. For 24154 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 24155 * <p> 24156 * The default implementation behaves as 24157 * {@link View#performAccessibilityAction(int, Bundle) 24158 * View#performAccessibilityAction(int, Bundle)} for the case of 24159 * no accessibility delegate been set. 24160 * </p> 24161 * 24162 * @param action The action to perform. 24163 * @return Whether the action was performed. 24164 * 24165 * @see View#performAccessibilityAction(int, Bundle) 24166 * View#performAccessibilityAction(int, Bundle) 24167 */ 24168 public boolean performAccessibilityAction(View host, int action, Bundle args) { 24169 return host.performAccessibilityActionInternal(action, args); 24170 } 24171 24172 /** 24173 * Sends an accessibility event. This method behaves exactly as 24174 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 24175 * empty {@link AccessibilityEvent} and does not perform a check whether 24176 * accessibility is enabled. 24177 * <p> 24178 * The default implementation behaves as 24179 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24180 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 24181 * the case of no accessibility delegate been set. 24182 * </p> 24183 * 24184 * @param host The View hosting the delegate. 24185 * @param event The event to send. 24186 * 24187 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24188 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24189 */ 24190 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 24191 host.sendAccessibilityEventUncheckedInternal(event); 24192 } 24193 24194 /** 24195 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 24196 * to its children for adding their text content to the event. 24197 * <p> 24198 * The default implementation behaves as 24199 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24200 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 24201 * the case of no accessibility delegate been set. 24202 * </p> 24203 * 24204 * @param host The View hosting the delegate. 24205 * @param event The event. 24206 * @return True if the event population was completed. 24207 * 24208 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24209 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24210 */ 24211 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 24212 return host.dispatchPopulateAccessibilityEventInternal(event); 24213 } 24214 24215 /** 24216 * Gives a chance to the host View to populate the accessibility event with its 24217 * text content. 24218 * <p> 24219 * The default implementation behaves as 24220 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 24221 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 24222 * the case of no accessibility delegate been set. 24223 * </p> 24224 * 24225 * @param host The View hosting the delegate. 24226 * @param event The accessibility event which to populate. 24227 * 24228 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 24229 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 24230 */ 24231 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 24232 host.onPopulateAccessibilityEventInternal(event); 24233 } 24234 24235 /** 24236 * Initializes an {@link AccessibilityEvent} with information about the 24237 * the host View which is the event source. 24238 * <p> 24239 * The default implementation behaves as 24240 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 24241 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 24242 * the case of no accessibility delegate been set. 24243 * </p> 24244 * 24245 * @param host The View hosting the delegate. 24246 * @param event The event to initialize. 24247 * 24248 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 24249 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 24250 */ 24251 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 24252 host.onInitializeAccessibilityEventInternal(event); 24253 } 24254 24255 /** 24256 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 24257 * <p> 24258 * The default implementation behaves as 24259 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24260 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 24261 * the case of no accessibility delegate been set. 24262 * </p> 24263 * 24264 * @param host The View hosting the delegate. 24265 * @param info The instance to initialize. 24266 * 24267 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24268 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24269 */ 24270 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 24271 host.onInitializeAccessibilityNodeInfoInternal(info); 24272 } 24273 24274 /** 24275 * Called when a child of the host View has requested sending an 24276 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 24277 * to augment the event. 24278 * <p> 24279 * The default implementation behaves as 24280 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24281 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 24282 * the case of no accessibility delegate been set. 24283 * </p> 24284 * 24285 * @param host The View hosting the delegate. 24286 * @param child The child which requests sending the event. 24287 * @param event The event to be sent. 24288 * @return True if the event should be sent 24289 * 24290 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24291 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24292 */ 24293 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 24294 AccessibilityEvent event) { 24295 return host.onRequestSendAccessibilityEventInternal(child, event); 24296 } 24297 24298 /** 24299 * Gets the provider for managing a virtual view hierarchy rooted at this View 24300 * and reported to {@link android.accessibilityservice.AccessibilityService}s 24301 * that explore the window content. 24302 * <p> 24303 * The default implementation behaves as 24304 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 24305 * the case of no accessibility delegate been set. 24306 * </p> 24307 * 24308 * @return The provider. 24309 * 24310 * @see AccessibilityNodeProvider 24311 */ 24312 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 24313 return null; 24314 } 24315 24316 /** 24317 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 24318 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 24319 * This method is responsible for obtaining an accessibility node info from a 24320 * pool of reusable instances and calling 24321 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 24322 * view to initialize the former. 24323 * <p> 24324 * <strong>Note:</strong> The client is responsible for recycling the obtained 24325 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 24326 * creation. 24327 * </p> 24328 * <p> 24329 * The default implementation behaves as 24330 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 24331 * the case of no accessibility delegate been set. 24332 * </p> 24333 * @return A populated {@link AccessibilityNodeInfo}. 24334 * 24335 * @see AccessibilityNodeInfo 24336 * 24337 * @hide 24338 */ 24339 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 24340 return host.createAccessibilityNodeInfoInternal(); 24341 } 24342 } 24343 24344 private class MatchIdPredicate implements Predicate<View> { 24345 public int mId; 24346 24347 @Override 24348 public boolean apply(View view) { 24349 return (view.mID == mId); 24350 } 24351 } 24352 24353 private class MatchLabelForPredicate implements Predicate<View> { 24354 private int mLabeledId; 24355 24356 @Override 24357 public boolean apply(View view) { 24358 return (view.mLabelForId == mLabeledId); 24359 } 24360 } 24361 24362 private class SendViewStateChangedAccessibilityEvent implements Runnable { 24363 private int mChangeTypes = 0; 24364 private boolean mPosted; 24365 private boolean mPostedWithDelay; 24366 private long mLastEventTimeMillis; 24367 24368 @Override 24369 public void run() { 24370 mPosted = false; 24371 mPostedWithDelay = false; 24372 mLastEventTimeMillis = SystemClock.uptimeMillis(); 24373 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 24374 final AccessibilityEvent event = AccessibilityEvent.obtain(); 24375 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 24376 event.setContentChangeTypes(mChangeTypes); 24377 sendAccessibilityEventUnchecked(event); 24378 } 24379 mChangeTypes = 0; 24380 } 24381 24382 public void runOrPost(int changeType) { 24383 mChangeTypes |= changeType; 24384 24385 // If this is a live region or the child of a live region, collect 24386 // all events from this frame and send them on the next frame. 24387 if (inLiveRegion()) { 24388 // If we're already posted with a delay, remove that. 24389 if (mPostedWithDelay) { 24390 removeCallbacks(this); 24391 mPostedWithDelay = false; 24392 } 24393 // Only post if we're not already posted. 24394 if (!mPosted) { 24395 post(this); 24396 mPosted = true; 24397 } 24398 return; 24399 } 24400 24401 if (mPosted) { 24402 return; 24403 } 24404 24405 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 24406 final long minEventIntevalMillis = 24407 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 24408 if (timeSinceLastMillis >= minEventIntevalMillis) { 24409 removeCallbacks(this); 24410 run(); 24411 } else { 24412 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 24413 mPostedWithDelay = true; 24414 } 24415 } 24416 } 24417 24418 private boolean inLiveRegion() { 24419 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24420 return true; 24421 } 24422 24423 ViewParent parent = getParent(); 24424 while (parent instanceof View) { 24425 if (((View) parent).getAccessibilityLiveRegion() 24426 != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24427 return true; 24428 } 24429 parent = parent.getParent(); 24430 } 24431 24432 return false; 24433 } 24434 24435 /** 24436 * Dump all private flags in readable format, useful for documentation and 24437 * sanity checking. 24438 */ 24439 private static void dumpFlags() { 24440 final HashMap<String, String> found = Maps.newHashMap(); 24441 try { 24442 for (Field field : View.class.getDeclaredFields()) { 24443 final int modifiers = field.getModifiers(); 24444 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 24445 if (field.getType().equals(int.class)) { 24446 final int value = field.getInt(null); 24447 dumpFlag(found, field.getName(), value); 24448 } else if (field.getType().equals(int[].class)) { 24449 final int[] values = (int[]) field.get(null); 24450 for (int i = 0; i < values.length; i++) { 24451 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 24452 } 24453 } 24454 } 24455 } 24456 } catch (IllegalAccessException e) { 24457 throw new RuntimeException(e); 24458 } 24459 24460 final ArrayList<String> keys = Lists.newArrayList(); 24461 keys.addAll(found.keySet()); 24462 Collections.sort(keys); 24463 for (String key : keys) { 24464 Log.d(VIEW_LOG_TAG, found.get(key)); 24465 } 24466 } 24467 24468 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 24469 // Sort flags by prefix, then by bits, always keeping unique keys 24470 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 24471 final int prefix = name.indexOf('_'); 24472 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 24473 final String output = bits + " " + name; 24474 found.put(key, output); 24475 } 24476 24477 /** {@hide} */ 24478 public void encode(@NonNull ViewHierarchyEncoder stream) { 24479 stream.beginObject(this); 24480 encodeProperties(stream); 24481 stream.endObject(); 24482 } 24483 24484 /** {@hide} */ 24485 @CallSuper 24486 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 24487 Object resolveId = ViewDebug.resolveId(getContext(), mID); 24488 if (resolveId instanceof String) { 24489 stream.addProperty("id", (String) resolveId); 24490 } else { 24491 stream.addProperty("id", mID); 24492 } 24493 24494 stream.addProperty("misc:transformation.alpha", 24495 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 24496 stream.addProperty("misc:transitionName", getTransitionName()); 24497 24498 // layout 24499 stream.addProperty("layout:left", mLeft); 24500 stream.addProperty("layout:right", mRight); 24501 stream.addProperty("layout:top", mTop); 24502 stream.addProperty("layout:bottom", mBottom); 24503 stream.addProperty("layout:width", getWidth()); 24504 stream.addProperty("layout:height", getHeight()); 24505 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 24506 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 24507 stream.addProperty("layout:hasTransientState", hasTransientState()); 24508 stream.addProperty("layout:baseline", getBaseline()); 24509 24510 // layout params 24511 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 24512 if (layoutParams != null) { 24513 stream.addPropertyKey("layoutParams"); 24514 layoutParams.encode(stream); 24515 } 24516 24517 // scrolling 24518 stream.addProperty("scrolling:scrollX", mScrollX); 24519 stream.addProperty("scrolling:scrollY", mScrollY); 24520 24521 // padding 24522 stream.addProperty("padding:paddingLeft", mPaddingLeft); 24523 stream.addProperty("padding:paddingRight", mPaddingRight); 24524 stream.addProperty("padding:paddingTop", mPaddingTop); 24525 stream.addProperty("padding:paddingBottom", mPaddingBottom); 24526 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 24527 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 24528 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 24529 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 24530 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 24531 24532 // measurement 24533 stream.addProperty("measurement:minHeight", mMinHeight); 24534 stream.addProperty("measurement:minWidth", mMinWidth); 24535 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 24536 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 24537 24538 // drawing 24539 stream.addProperty("drawing:elevation", getElevation()); 24540 stream.addProperty("drawing:translationX", getTranslationX()); 24541 stream.addProperty("drawing:translationY", getTranslationY()); 24542 stream.addProperty("drawing:translationZ", getTranslationZ()); 24543 stream.addProperty("drawing:rotation", getRotation()); 24544 stream.addProperty("drawing:rotationX", getRotationX()); 24545 stream.addProperty("drawing:rotationY", getRotationY()); 24546 stream.addProperty("drawing:scaleX", getScaleX()); 24547 stream.addProperty("drawing:scaleY", getScaleY()); 24548 stream.addProperty("drawing:pivotX", getPivotX()); 24549 stream.addProperty("drawing:pivotY", getPivotY()); 24550 stream.addProperty("drawing:opaque", isOpaque()); 24551 stream.addProperty("drawing:alpha", getAlpha()); 24552 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 24553 stream.addProperty("drawing:shadow", hasShadow()); 24554 stream.addProperty("drawing:solidColor", getSolidColor()); 24555 stream.addProperty("drawing:layerType", mLayerType); 24556 stream.addProperty("drawing:willNotDraw", willNotDraw()); 24557 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 24558 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 24559 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 24560 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 24561 24562 // focus 24563 stream.addProperty("focus:hasFocus", hasFocus()); 24564 stream.addProperty("focus:isFocused", isFocused()); 24565 stream.addProperty("focus:isFocusable", isFocusable()); 24566 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 24567 24568 stream.addProperty("misc:clickable", isClickable()); 24569 stream.addProperty("misc:pressed", isPressed()); 24570 stream.addProperty("misc:selected", isSelected()); 24571 stream.addProperty("misc:touchMode", isInTouchMode()); 24572 stream.addProperty("misc:hovered", isHovered()); 24573 stream.addProperty("misc:activated", isActivated()); 24574 24575 stream.addProperty("misc:visibility", getVisibility()); 24576 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 24577 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 24578 24579 stream.addProperty("misc:enabled", isEnabled()); 24580 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 24581 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 24582 24583 // theme attributes 24584 Resources.Theme theme = getContext().getTheme(); 24585 if (theme != null) { 24586 stream.addPropertyKey("theme"); 24587 theme.encode(stream); 24588 } 24589 24590 // view attribute information 24591 int n = mAttributes != null ? mAttributes.length : 0; 24592 stream.addProperty("meta:__attrCount__", n/2); 24593 for (int i = 0; i < n; i += 2) { 24594 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 24595 } 24596 24597 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 24598 24599 // text 24600 stream.addProperty("text:textDirection", getTextDirection()); 24601 stream.addProperty("text:textAlignment", getTextAlignment()); 24602 24603 // accessibility 24604 CharSequence contentDescription = getContentDescription(); 24605 stream.addProperty("accessibility:contentDescription", 24606 contentDescription == null ? "" : contentDescription.toString()); 24607 stream.addProperty("accessibility:labelFor", getLabelFor()); 24608 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 24609 } 24610 24611 /** 24612 * Determine if this view is rendered on a round wearable device and is the main view 24613 * on the screen. 24614 */ 24615 private boolean shouldDrawRoundScrollbar() { 24616 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 24617 return false; 24618 } 24619 24620 final View rootView = getRootView(); 24621 final WindowInsets insets = getRootWindowInsets(); 24622 24623 int height = getHeight(); 24624 int width = getWidth(); 24625 int displayHeight = rootView.getHeight(); 24626 int displayWidth = rootView.getWidth(); 24627 24628 if (height != displayHeight || width != displayWidth) { 24629 return false; 24630 } 24631 24632 getLocationOnScreen(mAttachInfo.mTmpLocation); 24633 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 24634 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 24635 } 24636 24637 /** 24638 * Sets the tooltip text which will be displayed in a small popup next to the view. 24639 * <p> 24640 * The tooltip will be displayed: 24641 * <li>On long click, unless is not handled otherwise (by OnLongClickListener or a context 24642 * menu). </li> 24643 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 24644 * 24645 * @param tooltipText the tooltip text, or null if no tooltip is required 24646 */ 24647 public final void setTooltipText(@Nullable CharSequence tooltipText) { 24648 if (TextUtils.isEmpty(tooltipText)) { 24649 setFlags(0, TOOLTIP); 24650 hideTooltip(); 24651 mTooltipInfo = null; 24652 } else { 24653 setFlags(TOOLTIP, TOOLTIP); 24654 if (mTooltipInfo == null) { 24655 mTooltipInfo = new TooltipInfo(); 24656 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 24657 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 24658 } 24659 mTooltipInfo.mTooltipText = tooltipText; 24660 if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) { 24661 mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText); 24662 } 24663 } 24664 } 24665 24666 /** 24667 * To be removed once the support library has stopped using it. 24668 * 24669 * @deprecated use {@link #setTooltipText} instead 24670 */ 24671 @Deprecated 24672 public final void setTooltip(@Nullable CharSequence tooltipText) { 24673 setTooltipText(tooltipText); 24674 } 24675 24676 /** 24677 * Returns the view's tooltip text. 24678 * 24679 * @return the tooltip text 24680 */ 24681 @Nullable 24682 public final CharSequence getTooltipText() { 24683 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 24684 } 24685 24686 /** 24687 * To be removed once the support library has stopped using it. 24688 * 24689 * @deprecated use {@link #getTooltipText} instead 24690 */ 24691 @Deprecated 24692 @Nullable 24693 public final CharSequence getTooltip() { 24694 return getTooltipText(); 24695 } 24696 24697 private boolean showTooltip(int x, int y, boolean fromLongClick) { 24698 if (mAttachInfo == null) { 24699 return false; 24700 } 24701 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 24702 return false; 24703 } 24704 final CharSequence tooltipText = getTooltipText(); 24705 if (TextUtils.isEmpty(tooltipText)) { 24706 return false; 24707 } 24708 hideTooltip(); 24709 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 24710 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 24711 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 24712 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, tooltipText); 24713 mAttachInfo.mTooltipHost = this; 24714 return true; 24715 } 24716 24717 void hideTooltip() { 24718 if (mTooltipInfo == null) { 24719 return; 24720 } 24721 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24722 if (mTooltipInfo.mTooltipPopup == null) { 24723 return; 24724 } 24725 mTooltipInfo.mTooltipPopup.hide(); 24726 mTooltipInfo.mTooltipPopup = null; 24727 mTooltipInfo.mTooltipFromLongClick = false; 24728 if (mAttachInfo != null) { 24729 mAttachInfo.mTooltipHost = null; 24730 } 24731 } 24732 24733 private boolean showLongClickTooltip(int x, int y) { 24734 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24735 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24736 return showTooltip(x, y, true); 24737 } 24738 24739 private void showHoverTooltip() { 24740 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 24741 } 24742 24743 boolean dispatchTooltipHoverEvent(MotionEvent event) { 24744 if (mTooltipInfo == null) { 24745 return false; 24746 } 24747 switch(event.getAction()) { 24748 case MotionEvent.ACTION_HOVER_MOVE: 24749 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 24750 break; 24751 } 24752 if (!mTooltipInfo.mTooltipFromLongClick) { 24753 if (mTooltipInfo.mTooltipPopup == null) { 24754 // Schedule showing the tooltip after a timeout. 24755 mTooltipInfo.mAnchorX = (int) event.getX(); 24756 mTooltipInfo.mAnchorY = (int) event.getY(); 24757 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 24758 postDelayed(mTooltipInfo.mShowTooltipRunnable, 24759 ViewConfiguration.getHoverTooltipShowTimeout()); 24760 } 24761 24762 // Hide hover-triggered tooltip after a period of inactivity. 24763 // Match the timeout used by NativeInputManager to hide the mouse pointer 24764 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 24765 final int timeout; 24766 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 24767 == SYSTEM_UI_FLAG_LOW_PROFILE) { 24768 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 24769 } else { 24770 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 24771 } 24772 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24773 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 24774 } 24775 return true; 24776 24777 case MotionEvent.ACTION_HOVER_EXIT: 24778 if (!mTooltipInfo.mTooltipFromLongClick) { 24779 hideTooltip(); 24780 } 24781 break; 24782 } 24783 return false; 24784 } 24785 24786 void handleTooltipKey(KeyEvent event) { 24787 switch (event.getAction()) { 24788 case KeyEvent.ACTION_DOWN: 24789 if (event.getRepeatCount() == 0) { 24790 hideTooltip(); 24791 } 24792 break; 24793 24794 case KeyEvent.ACTION_UP: 24795 handleTooltipUp(); 24796 break; 24797 } 24798 } 24799 24800 private void handleTooltipUp() { 24801 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 24802 return; 24803 } 24804 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 24805 postDelayed(mTooltipInfo.mHideTooltipRunnable, 24806 ViewConfiguration.getLongPressTooltipHideTimeout()); 24807 } 24808 24809 /** 24810 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 24811 * is not showing. 24812 * @hide 24813 */ 24814 @TestApi 24815 public View getTooltipView() { 24816 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 24817 return null; 24818 } 24819 return mTooltipInfo.mTooltipPopup.getContentView(); 24820 } 24821} 24822