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 17 package android.view; 18 19 import android.content.ClipData; 20 import android.content.Context; 21 import android.content.res.Configuration; 22 import android.content.res.Resources; 23 import android.content.res.TypedArray; 24 import android.graphics.Bitmap; 25 import android.graphics.Camera; 26 import android.graphics.Canvas; 27 import android.graphics.Insets; 28 import android.graphics.Interpolator; 29 import android.graphics.LinearGradient; 30 import android.graphics.Matrix; 31 import android.graphics.Paint; 32 import android.graphics.PixelFormat; 33 import android.graphics.Point; 34 import android.graphics.PorterDuff; 35 import android.graphics.PorterDuffXfermode; 36 import android.graphics.Rect; 37 import android.graphics.RectF; 38 import android.graphics.Region; 39 import android.graphics.Shader; 40 import android.graphics.drawable.ColorDrawable; 41 import android.graphics.drawable.Drawable; 42 import android.hardware.display.DisplayManagerGlobal; 43 import android.os.Bundle; 44 import android.os.Handler; 45 import android.os.IBinder; 46 import android.os.Parcel; 47 import android.os.Parcelable; 48 import android.os.RemoteException; 49 import android.os.SystemClock; 50 import android.os.SystemProperties; 51 import android.text.TextUtils; 52 import android.util.AttributeSet; 53 import android.util.FloatProperty; 54 import android.util.Log; 55 import android.util.Pool; 56 import android.util.Poolable; 57 import android.util.PoolableManager; 58 import android.util.Pools; 59 import android.util.Property; 60 import android.util.SparseArray; 61 import android.util.TypedValue; 62 import android.view.ContextMenu.ContextMenuInfo; 63 import android.view.AccessibilityIterators.TextSegmentIterator; 64 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 65 import android.view.AccessibilityIterators.WordTextSegmentIterator; 66 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 67 import android.view.accessibility.AccessibilityEvent; 68 import android.view.accessibility.AccessibilityEventSource; 69 import android.view.accessibility.AccessibilityManager; 70 import android.view.accessibility.AccessibilityNodeInfo; 71 import android.view.accessibility.AccessibilityNodeProvider; 72 import android.view.animation.Animation; 73 import android.view.animation.AnimationUtils; 74 import android.view.animation.Transformation; 75 import android.view.inputmethod.EditorInfo; 76 import android.view.inputmethod.InputConnection; 77 import android.view.inputmethod.InputMethodManager; 78 import android.widget.ScrollBarDrawable; 79 80 import static android.os.Build.VERSION_CODES.*; 81 import static java.lang.Math.max; 82 83 import com.android.internal.R; 84 import com.android.internal.util.Predicate; 85 import com.android.internal.view.menu.MenuBuilder; 86 import com.google.android.collect.Lists; 87 import com.google.android.collect.Maps; 88 89 import java.lang.ref.WeakReference; 90 import java.lang.reflect.Field; 91 import java.lang.reflect.InvocationTargetException; 92 import java.lang.reflect.Method; 93 import java.lang.reflect.Modifier; 94 import java.util.ArrayList; 95 import java.util.Arrays; 96 import java.util.Collections; 97 import java.util.HashMap; 98 import java.util.Locale; 99 import java.util.concurrent.CopyOnWriteArrayList; 100 import java.util.concurrent.atomic.AtomicInteger; 101 102 /** 103 * <p> 104 * This class represents the basic building block for user interface components. A View 105 * occupies a rectangular area on the screen and is responsible for drawing and 106 * event handling. View is the base class for <em>widgets</em>, which are 107 * used to create interactive UI components (buttons, text fields, etc.). The 108 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 109 * are invisible containers that hold other Views (or other ViewGroups) and define 110 * their layout properties. 111 * </p> 112 * 113 * <div class="special reference"> 114 * <h3>Developer Guides</h3> 115 * <p>For information about using this class to develop your application's user interface, 116 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 117 * </div> 118 * 119 * <a name="Using"></a> 120 * <h3>Using Views</h3> 121 * <p> 122 * All of the views in a window are arranged in a single tree. You can add views 123 * either from code or by specifying a tree of views in one or more XML layout 124 * files. There are many specialized subclasses of views that act as controls or 125 * are capable of displaying text, images, or other content. 126 * </p> 127 * <p> 128 * Once you have created a tree of views, there are typically a few types of 129 * common operations you may wish to perform: 130 * <ul> 131 * <li><strong>Set properties:</strong> for example setting the text of a 132 * {@link android.widget.TextView}. The available properties and the methods 133 * that set them will vary among the different subclasses of views. Note that 134 * properties that are known at build time can be set in the XML layout 135 * files.</li> 136 * <li><strong>Set focus:</strong> The framework will handled moving focus in 137 * response to user input. To force focus to a specific view, call 138 * {@link #requestFocus}.</li> 139 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 140 * that will be notified when something interesting happens to the view. For 141 * example, all views will let you set a listener to be notified when the view 142 * gains or loses focus. You can register such a listener using 143 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 144 * Other view subclasses offer more specialized listeners. For example, a Button 145 * exposes a listener to notify clients when the button is clicked.</li> 146 * <li><strong>Set visibility:</strong> You can hide or show views using 147 * {@link #setVisibility(int)}.</li> 148 * </ul> 149 * </p> 150 * <p><em> 151 * Note: The Android framework is responsible for measuring, laying out and 152 * drawing views. You should not call methods that perform these actions on 153 * views yourself unless you are actually implementing a 154 * {@link android.view.ViewGroup}. 155 * </em></p> 156 * 157 * <a name="Lifecycle"></a> 158 * <h3>Implementing a Custom View</h3> 159 * 160 * <p> 161 * To implement a custom view, you will usually begin by providing overrides for 162 * some of the standard methods that the framework calls on all views. You do 163 * not need to override all of these methods. In fact, you can start by just 164 * overriding {@link #onDraw(android.graphics.Canvas)}. 165 * <table border="2" width="85%" align="center" cellpadding="5"> 166 * <thead> 167 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 168 * </thead> 169 * 170 * <tbody> 171 * <tr> 172 * <td rowspan="2">Creation</td> 173 * <td>Constructors</td> 174 * <td>There is a form of the constructor that are called when the view 175 * is created from code and a form that is called when the view is 176 * inflated from a layout file. The second form should parse and apply 177 * any attributes defined in the layout file. 178 * </td> 179 * </tr> 180 * <tr> 181 * <td><code>{@link #onFinishInflate()}</code></td> 182 * <td>Called after a view and all of its children has been inflated 183 * from XML.</td> 184 * </tr> 185 * 186 * <tr> 187 * <td rowspan="3">Layout</td> 188 * <td><code>{@link #onMeasure(int, int)}</code></td> 189 * <td>Called to determine the size requirements for this view and all 190 * of its children. 191 * </td> 192 * </tr> 193 * <tr> 194 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 195 * <td>Called when this view should assign a size and position to all 196 * of its children. 197 * </td> 198 * </tr> 199 * <tr> 200 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 201 * <td>Called when the size of this view has changed. 202 * </td> 203 * </tr> 204 * 205 * <tr> 206 * <td>Drawing</td> 207 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 208 * <td>Called when the view should render its content. 209 * </td> 210 * </tr> 211 * 212 * <tr> 213 * <td rowspan="4">Event processing</td> 214 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 215 * <td>Called when a new hardware key event occurs. 216 * </td> 217 * </tr> 218 * <tr> 219 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 220 * <td>Called when a hardware key up event occurs. 221 * </td> 222 * </tr> 223 * <tr> 224 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 225 * <td>Called when a trackball motion event occurs. 226 * </td> 227 * </tr> 228 * <tr> 229 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 230 * <td>Called when a touch screen motion event occurs. 231 * </td> 232 * </tr> 233 * 234 * <tr> 235 * <td rowspan="2">Focus</td> 236 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 237 * <td>Called when the view gains or loses focus. 238 * </td> 239 * </tr> 240 * 241 * <tr> 242 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 243 * <td>Called when the window containing the view gains or loses focus. 244 * </td> 245 * </tr> 246 * 247 * <tr> 248 * <td rowspan="3">Attaching</td> 249 * <td><code>{@link #onAttachedToWindow()}</code></td> 250 * <td>Called when the view is attached to a window. 251 * </td> 252 * </tr> 253 * 254 * <tr> 255 * <td><code>{@link #onDetachedFromWindow}</code></td> 256 * <td>Called when the view is detached from its window. 257 * </td> 258 * </tr> 259 * 260 * <tr> 261 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 262 * <td>Called when the visibility of the window containing the view 263 * has changed. 264 * </td> 265 * </tr> 266 * </tbody> 267 * 268 * </table> 269 * </p> 270 * 271 * <a name="IDs"></a> 272 * <h3>IDs</h3> 273 * Views may have an integer id associated with them. These ids are typically 274 * assigned in the layout XML files, and are used to find specific views within 275 * the view tree. A common pattern is to: 276 * <ul> 277 * <li>Define a Button in the layout file and assign it a unique ID. 278 * <pre> 279 * <Button 280 * android:id="@+id/my_button" 281 * android:layout_width="wrap_content" 282 * android:layout_height="wrap_content" 283 * android:text="@string/my_button_text"/> 284 * </pre></li> 285 * <li>From the onCreate method of an Activity, find the Button 286 * <pre class="prettyprint"> 287 * Button myButton = (Button) findViewById(R.id.my_button); 288 * </pre></li> 289 * </ul> 290 * <p> 291 * View IDs need not be unique throughout the tree, but it is good practice to 292 * ensure that they are at least unique within the part of the tree you are 293 * searching. 294 * </p> 295 * 296 * <a name="Position"></a> 297 * <h3>Position</h3> 298 * <p> 299 * The geometry of a view is that of a rectangle. A view has a location, 300 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 301 * two dimensions, expressed as a width and a height. The unit for location 302 * and dimensions is the pixel. 303 * </p> 304 * 305 * <p> 306 * It is possible to retrieve the location of a view by invoking the methods 307 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 308 * coordinate of the rectangle representing the view. The latter returns the 309 * top, or Y, coordinate of the rectangle representing the view. These methods 310 * both return the location of the view relative to its parent. For instance, 311 * when getLeft() returns 20, that means the view is located 20 pixels to the 312 * right of the left edge of its direct parent. 313 * </p> 314 * 315 * <p> 316 * In addition, several convenience methods are offered to avoid unnecessary 317 * computations, namely {@link #getRight()} and {@link #getBottom()}. 318 * These methods return the coordinates of the right and bottom edges of the 319 * rectangle representing the view. For instance, calling {@link #getRight()} 320 * is similar to the following computation: <code>getLeft() + getWidth()</code> 321 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 322 * </p> 323 * 324 * <a name="SizePaddingMargins"></a> 325 * <h3>Size, padding and margins</h3> 326 * <p> 327 * The size of a view is expressed with a width and a height. A view actually 328 * possess two pairs of width and height values. 329 * </p> 330 * 331 * <p> 332 * The first pair is known as <em>measured width</em> and 333 * <em>measured height</em>. These dimensions define how big a view wants to be 334 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 335 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 336 * and {@link #getMeasuredHeight()}. 337 * </p> 338 * 339 * <p> 340 * The second pair is simply known as <em>width</em> and <em>height</em>, or 341 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 342 * dimensions define the actual size of the view on screen, at drawing time and 343 * after layout. These values may, but do not have to, be different from the 344 * measured width and height. The width and height can be obtained by calling 345 * {@link #getWidth()} and {@link #getHeight()}. 346 * </p> 347 * 348 * <p> 349 * To measure its dimensions, a view takes into account its padding. The padding 350 * is expressed in pixels for the left, top, right and bottom parts of the view. 351 * Padding can be used to offset the content of the view by a specific amount of 352 * pixels. For instance, a left padding of 2 will push the view's content by 353 * 2 pixels to the right of the left edge. Padding can be set using the 354 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 355 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 356 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 357 * {@link #getPaddingEnd()}. 358 * </p> 359 * 360 * <p> 361 * Even though a view can define a padding, it does not provide any support for 362 * margins. However, view groups provide such a support. Refer to 363 * {@link android.view.ViewGroup} and 364 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 365 * </p> 366 * 367 * <a name="Layout"></a> 368 * <h3>Layout</h3> 369 * <p> 370 * Layout is a two pass process: a measure pass and a layout pass. The measuring 371 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 372 * of the view tree. Each view pushes dimension specifications down the tree 373 * during the recursion. At the end of the measure pass, every view has stored 374 * its measurements. The second pass happens in 375 * {@link #layout(int,int,int,int)} and is also top-down. During 376 * this pass each parent is responsible for positioning all of its children 377 * using the sizes computed in the measure pass. 378 * </p> 379 * 380 * <p> 381 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 382 * {@link #getMeasuredHeight()} values must be set, along with those for all of 383 * that view's descendants. A view's measured width and measured height values 384 * must respect the constraints imposed by the view's parents. This guarantees 385 * that at the end of the measure pass, all parents accept all of their 386 * children's measurements. A parent view may call measure() more than once on 387 * its children. For example, the parent may measure each child once with 388 * unspecified dimensions to find out how big they want to be, then call 389 * measure() on them again with actual numbers if the sum of all the children's 390 * unconstrained sizes is too big or too small. 391 * </p> 392 * 393 * <p> 394 * The measure pass uses two classes to communicate dimensions. The 395 * {@link MeasureSpec} class is used by views to tell their parents how they 396 * want to be measured and positioned. The base LayoutParams class just 397 * describes how big the view wants to be for both width and height. For each 398 * dimension, it can specify one of: 399 * <ul> 400 * <li> an exact number 401 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 402 * (minus padding) 403 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 404 * enclose its content (plus padding). 405 * </ul> 406 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 407 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 408 * an X and Y value. 409 * </p> 410 * 411 * <p> 412 * MeasureSpecs are used to push requirements down the tree from parent to 413 * child. A MeasureSpec can be in one of three modes: 414 * <ul> 415 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 416 * of a child view. For example, a LinearLayout may call measure() on its child 417 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 418 * tall the child view wants to be given a width of 240 pixels. 419 * <li>EXACTLY: This is used by the parent to impose an exact size on the 420 * child. The child must use this size, and guarantee that all of its 421 * descendants will fit within this size. 422 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 423 * child. The child must gurantee that it and all of its descendants will fit 424 * within this size. 425 * </ul> 426 * </p> 427 * 428 * <p> 429 * To intiate a layout, call {@link #requestLayout}. This method is typically 430 * called by a view on itself when it believes that is can no longer fit within 431 * its current bounds. 432 * </p> 433 * 434 * <a name="Drawing"></a> 435 * <h3>Drawing</h3> 436 * <p> 437 * Drawing is handled by walking the tree and rendering each view that 438 * intersects the invalid region. Because the tree is traversed in-order, 439 * this means that parents will draw before (i.e., behind) their children, with 440 * siblings drawn in the order they appear in the tree. 441 * If you set a background drawable for a View, then the View will draw it for you 442 * before calling back to its <code>onDraw()</code> method. 443 * </p> 444 * 445 * <p> 446 * Note that the framework will not draw views that are not in the invalid region. 447 * </p> 448 * 449 * <p> 450 * To force a view to draw, call {@link #invalidate()}. 451 * </p> 452 * 453 * <a name="EventHandlingThreading"></a> 454 * <h3>Event Handling and Threading</h3> 455 * <p> 456 * The basic cycle of a view is as follows: 457 * <ol> 458 * <li>An event comes in and is dispatched to the appropriate view. The view 459 * handles the event and notifies any listeners.</li> 460 * <li>If in the course of processing the event, the view's bounds may need 461 * to be changed, the view will call {@link #requestLayout()}.</li> 462 * <li>Similarly, if in the course of processing the event the view's appearance 463 * may need to be changed, the view will call {@link #invalidate()}.</li> 464 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 465 * the framework will take care of measuring, laying out, and drawing the tree 466 * as appropriate.</li> 467 * </ol> 468 * </p> 469 * 470 * <p><em>Note: The entire view tree is single threaded. You must always be on 471 * the UI thread when calling any method on any view.</em> 472 * If you are doing work on other threads and want to update the state of a view 473 * from that thread, you should use a {@link Handler}. 474 * </p> 475 * 476 * <a name="FocusHandling"></a> 477 * <h3>Focus Handling</h3> 478 * <p> 479 * The framework will handle routine focus movement in response to user input. 480 * This includes changing the focus as views are removed or hidden, or as new 481 * views become available. Views indicate their willingness to take focus 482 * through the {@link #isFocusable} method. To change whether a view can take 483 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 484 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 485 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 486 * </p> 487 * <p> 488 * Focus movement is based on an algorithm which finds the nearest neighbor in a 489 * given direction. In rare cases, the default algorithm may not match the 490 * intended behavior of the developer. In these situations, you can provide 491 * explicit overrides by using these XML attributes in the layout file: 492 * <pre> 493 * nextFocusDown 494 * nextFocusLeft 495 * nextFocusRight 496 * nextFocusUp 497 * </pre> 498 * </p> 499 * 500 * 501 * <p> 502 * To get a particular view to take focus, call {@link #requestFocus()}. 503 * </p> 504 * 505 * <a name="TouchMode"></a> 506 * <h3>Touch Mode</h3> 507 * <p> 508 * When a user is navigating a user interface via directional keys such as a D-pad, it is 509 * necessary to give focus to actionable items such as buttons so the user can see 510 * what will take input. If the device has touch capabilities, however, and the user 511 * begins interacting with the interface by touching it, it is no longer necessary to 512 * always highlight, or give focus to, a particular view. This motivates a mode 513 * for interaction named 'touch mode'. 514 * </p> 515 * <p> 516 * For a touch capable device, once the user touches the screen, the device 517 * will enter touch mode. From this point onward, only views for which 518 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 519 * Other views that are touchable, like buttons, will not take focus when touched; they will 520 * only fire the on click listeners. 521 * </p> 522 * <p> 523 * Any time a user hits a directional key, such as a D-pad direction, the view device will 524 * exit touch mode, and find a view to take focus, so that the user may resume interacting 525 * with the user interface without touching the screen again. 526 * </p> 527 * <p> 528 * The touch mode state is maintained across {@link android.app.Activity}s. Call 529 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 530 * </p> 531 * 532 * <a name="Scrolling"></a> 533 * <h3>Scrolling</h3> 534 * <p> 535 * The framework provides basic support for views that wish to internally 536 * scroll their content. This includes keeping track of the X and Y scroll 537 * offset as well as mechanisms for drawing scrollbars. See 538 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 539 * {@link #awakenScrollBars()} for more details. 540 * </p> 541 * 542 * <a name="Tags"></a> 543 * <h3>Tags</h3> 544 * <p> 545 * Unlike IDs, tags are not used to identify views. Tags are essentially an 546 * extra piece of information that can be associated with a view. They are most 547 * often used as a convenience to store data related to views in the views 548 * themselves rather than by putting them in a separate structure. 549 * </p> 550 * 551 * <a name="Properties"></a> 552 * <h3>Properties</h3> 553 * <p> 554 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 555 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 556 * available both in the {@link Property} form as well as in similarly-named setter/getter 557 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 558 * be used to set persistent state associated with these rendering-related properties on the view. 559 * The properties and methods can also be used in conjunction with 560 * {@link android.animation.Animator Animator}-based animations, described more in the 561 * <a href="#Animation">Animation</a> section. 562 * </p> 563 * 564 * <a name="Animation"></a> 565 * <h3>Animation</h3> 566 * <p> 567 * Starting with Android 3.0, the preferred way of animating views is to use the 568 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 569 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 570 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 571 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 572 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 573 * makes animating these View properties particularly easy and efficient. 574 * </p> 575 * <p> 576 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 577 * You can attach an {@link Animation} object to a view using 578 * {@link #setAnimation(Animation)} or 579 * {@link #startAnimation(Animation)}. The animation can alter the scale, 580 * rotation, translation and alpha of a view over time. If the animation is 581 * attached to a view that has children, the animation will affect the entire 582 * subtree rooted by that node. When an animation is started, the framework will 583 * take care of redrawing the appropriate views until the animation completes. 584 * </p> 585 * 586 * <a name="Security"></a> 587 * <h3>Security</h3> 588 * <p> 589 * Sometimes it is essential that an application be able to verify that an action 590 * is being performed with the full knowledge and consent of the user, such as 591 * granting a permission request, making a purchase or clicking on an advertisement. 592 * Unfortunately, a malicious application could try to spoof the user into 593 * performing these actions, unaware, by concealing the intended purpose of the view. 594 * As a remedy, the framework offers a touch filtering mechanism that can be used to 595 * improve the security of views that provide access to sensitive functionality. 596 * </p><p> 597 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 598 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 599 * will discard touches that are received whenever the view's window is obscured by 600 * another visible window. As a result, the view will not receive touches whenever a 601 * toast, dialog or other window appears above the view's window. 602 * </p><p> 603 * For more fine-grained control over security, consider overriding the 604 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 605 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 606 * </p> 607 * 608 * @attr ref android.R.styleable#View_alpha 609 * @attr ref android.R.styleable#View_background 610 * @attr ref android.R.styleable#View_clickable 611 * @attr ref android.R.styleable#View_contentDescription 612 * @attr ref android.R.styleable#View_drawingCacheQuality 613 * @attr ref android.R.styleable#View_duplicateParentState 614 * @attr ref android.R.styleable#View_id 615 * @attr ref android.R.styleable#View_requiresFadingEdge 616 * @attr ref android.R.styleable#View_fadeScrollbars 617 * @attr ref android.R.styleable#View_fadingEdgeLength 618 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 619 * @attr ref android.R.styleable#View_fitsSystemWindows 620 * @attr ref android.R.styleable#View_isScrollContainer 621 * @attr ref android.R.styleable#View_focusable 622 * @attr ref android.R.styleable#View_focusableInTouchMode 623 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 624 * @attr ref android.R.styleable#View_keepScreenOn 625 * @attr ref android.R.styleable#View_layerType 626 * @attr ref android.R.styleable#View_layoutDirection 627 * @attr ref android.R.styleable#View_longClickable 628 * @attr ref android.R.styleable#View_minHeight 629 * @attr ref android.R.styleable#View_minWidth 630 * @attr ref android.R.styleable#View_nextFocusDown 631 * @attr ref android.R.styleable#View_nextFocusLeft 632 * @attr ref android.R.styleable#View_nextFocusRight 633 * @attr ref android.R.styleable#View_nextFocusUp 634 * @attr ref android.R.styleable#View_onClick 635 * @attr ref android.R.styleable#View_padding 636 * @attr ref android.R.styleable#View_paddingBottom 637 * @attr ref android.R.styleable#View_paddingLeft 638 * @attr ref android.R.styleable#View_paddingRight 639 * @attr ref android.R.styleable#View_paddingTop 640 * @attr ref android.R.styleable#View_paddingStart 641 * @attr ref android.R.styleable#View_paddingEnd 642 * @attr ref android.R.styleable#View_saveEnabled 643 * @attr ref android.R.styleable#View_rotation 644 * @attr ref android.R.styleable#View_rotationX 645 * @attr ref android.R.styleable#View_rotationY 646 * @attr ref android.R.styleable#View_scaleX 647 * @attr ref android.R.styleable#View_scaleY 648 * @attr ref android.R.styleable#View_scrollX 649 * @attr ref android.R.styleable#View_scrollY 650 * @attr ref android.R.styleable#View_scrollbarSize 651 * @attr ref android.R.styleable#View_scrollbarStyle 652 * @attr ref android.R.styleable#View_scrollbars 653 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 654 * @attr ref android.R.styleable#View_scrollbarFadeDuration 655 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 656 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 657 * @attr ref android.R.styleable#View_scrollbarThumbVertical 658 * @attr ref android.R.styleable#View_scrollbarTrackVertical 659 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 660 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 661 * @attr ref android.R.styleable#View_soundEffectsEnabled 662 * @attr ref android.R.styleable#View_tag 663 * @attr ref android.R.styleable#View_textAlignment 664 * @attr ref android.R.styleable#View_textDirection 665 * @attr ref android.R.styleable#View_transformPivotX 666 * @attr ref android.R.styleable#View_transformPivotY 667 * @attr ref android.R.styleable#View_translationX 668 * @attr ref android.R.styleable#View_translationY 669 * @attr ref android.R.styleable#View_visibility 670 * 671 * @see android.view.ViewGroup 672 */ 673 public class View implements Drawable.Callback, KeyEvent.Callback, 674 AccessibilityEventSource { 675 private static final boolean DBG = false; 676 677 /** 678 * The logging tag used by this class with android.util.Log. 679 */ 680 protected static final String VIEW_LOG_TAG = "View"; 681 682 /** 683 * When set to true, apps will draw debugging information about their layouts. 684 * 685 * @hide 686 */ 687 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 688 689 /** 690 * Used to mark a View that has no ID. 691 */ 692 public static final int NO_ID = -1; 693 694 /** 695 * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when 696 * calling setFlags. 697 */ 698 private static final int NOT_FOCUSABLE = 0x00000000; 699 700 /** 701 * This view wants keystrokes. Use with TAKES_FOCUS_MASK when calling 702 * setFlags. 703 */ 704 private static final int FOCUSABLE = 0x00000001; 705 706 /** 707 * Mask for use with setFlags indicating bits used for focus. 708 */ 709 private static final int FOCUSABLE_MASK = 0x00000001; 710 711 /** 712 * This view will adjust its padding to fit sytem windows (e.g. status bar) 713 */ 714 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 715 716 /** 717 * This view is visible. 718 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 719 * android:visibility}. 720 */ 721 public static final int VISIBLE = 0x00000000; 722 723 /** 724 * This view is invisible, but it still takes up space for layout purposes. 725 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 726 * android:visibility}. 727 */ 728 public static final int INVISIBLE = 0x00000004; 729 730 /** 731 * This view is invisible, and it doesn't take any space for layout 732 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 733 * android:visibility}. 734 */ 735 public static final int GONE = 0x00000008; 736 737 /** 738 * Mask for use with setFlags indicating bits used for visibility. 739 * {@hide} 740 */ 741 static final int VISIBILITY_MASK = 0x0000000C; 742 743 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 744 745 /** 746 * This view is enabled. Interpretation varies by subclass. 747 * Use with ENABLED_MASK when calling setFlags. 748 * {@hide} 749 */ 750 static final int ENABLED = 0x00000000; 751 752 /** 753 * This view is disabled. Interpretation varies by subclass. 754 * Use with ENABLED_MASK when calling setFlags. 755 * {@hide} 756 */ 757 static final int DISABLED = 0x00000020; 758 759 /** 760 * Mask for use with setFlags indicating bits used for indicating whether 761 * this view is enabled 762 * {@hide} 763 */ 764 static final int ENABLED_MASK = 0x00000020; 765 766 /** 767 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 768 * called and further optimizations will be performed. It is okay to have 769 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 770 * {@hide} 771 */ 772 static final int WILL_NOT_DRAW = 0x00000080; 773 774 /** 775 * Mask for use with setFlags indicating bits used for indicating whether 776 * this view is will draw 777 * {@hide} 778 */ 779 static final int DRAW_MASK = 0x00000080; 780 781 /** 782 * <p>This view doesn't show scrollbars.</p> 783 * {@hide} 784 */ 785 static final int SCROLLBARS_NONE = 0x00000000; 786 787 /** 788 * <p>This view shows horizontal scrollbars.</p> 789 * {@hide} 790 */ 791 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 792 793 /** 794 * <p>This view shows vertical scrollbars.</p> 795 * {@hide} 796 */ 797 static final int SCROLLBARS_VERTICAL = 0x00000200; 798 799 /** 800 * <p>Mask for use with setFlags indicating bits used for indicating which 801 * scrollbars are enabled.</p> 802 * {@hide} 803 */ 804 static final int SCROLLBARS_MASK = 0x00000300; 805 806 /** 807 * Indicates that the view should filter touches when its window is obscured. 808 * Refer to the class comments for more information about this security feature. 809 * {@hide} 810 */ 811 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 812 813 /** 814 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 815 * that they are optional and should be skipped if the window has 816 * requested system UI flags that ignore those insets for layout. 817 */ 818 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 819 820 /** 821 * <p>This view doesn't show fading edges.</p> 822 * {@hide} 823 */ 824 static final int FADING_EDGE_NONE = 0x00000000; 825 826 /** 827 * <p>This view shows horizontal fading edges.</p> 828 * {@hide} 829 */ 830 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 831 832 /** 833 * <p>This view shows vertical fading edges.</p> 834 * {@hide} 835 */ 836 static final int FADING_EDGE_VERTICAL = 0x00002000; 837 838 /** 839 * <p>Mask for use with setFlags indicating bits used for indicating which 840 * fading edges are enabled.</p> 841 * {@hide} 842 */ 843 static final int FADING_EDGE_MASK = 0x00003000; 844 845 /** 846 * <p>Indicates this view can be clicked. When clickable, a View reacts 847 * to clicks by notifying the OnClickListener.<p> 848 * {@hide} 849 */ 850 static final int CLICKABLE = 0x00004000; 851 852 /** 853 * <p>Indicates this view is caching its drawing into a bitmap.</p> 854 * {@hide} 855 */ 856 static final int DRAWING_CACHE_ENABLED = 0x00008000; 857 858 /** 859 * <p>Indicates that no icicle should be saved for this view.<p> 860 * {@hide} 861 */ 862 static final int SAVE_DISABLED = 0x000010000; 863 864 /** 865 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 866 * property.</p> 867 * {@hide} 868 */ 869 static final int SAVE_DISABLED_MASK = 0x000010000; 870 871 /** 872 * <p>Indicates that no drawing cache should ever be created for this view.<p> 873 * {@hide} 874 */ 875 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 876 877 /** 878 * <p>Indicates this view can take / keep focus when int touch mode.</p> 879 * {@hide} 880 */ 881 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 882 883 /** 884 * <p>Enables low quality mode for the drawing cache.</p> 885 */ 886 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 887 888 /** 889 * <p>Enables high quality mode for the drawing cache.</p> 890 */ 891 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 892 893 /** 894 * <p>Enables automatic quality mode for the drawing cache.</p> 895 */ 896 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 897 898 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 899 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 900 }; 901 902 /** 903 * <p>Mask for use with setFlags indicating bits used for the cache 904 * quality property.</p> 905 * {@hide} 906 */ 907 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 908 909 /** 910 * <p> 911 * Indicates this view can be long clicked. When long clickable, a View 912 * reacts to long clicks by notifying the OnLongClickListener or showing a 913 * context menu. 914 * </p> 915 * {@hide} 916 */ 917 static final int LONG_CLICKABLE = 0x00200000; 918 919 /** 920 * <p>Indicates that this view gets its drawable states from its direct parent 921 * and ignores its original internal states.</p> 922 * 923 * @hide 924 */ 925 static final int DUPLICATE_PARENT_STATE = 0x00400000; 926 927 /** 928 * The scrollbar style to display the scrollbars inside the content area, 929 * without increasing the padding. The scrollbars will be overlaid with 930 * translucency on the view's content. 931 */ 932 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 933 934 /** 935 * The scrollbar style to display the scrollbars inside the padded area, 936 * increasing the padding of the view. The scrollbars will not overlap the 937 * content area of the view. 938 */ 939 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 940 941 /** 942 * The scrollbar style to display the scrollbars at the edge of the view, 943 * without increasing the padding. The scrollbars will be overlaid with 944 * translucency. 945 */ 946 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 947 948 /** 949 * The scrollbar style to display the scrollbars at the edge of the view, 950 * increasing the padding of the view. The scrollbars will only overlap the 951 * background, if any. 952 */ 953 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 954 955 /** 956 * Mask to check if the scrollbar style is overlay or inset. 957 * {@hide} 958 */ 959 static final int SCROLLBARS_INSET_MASK = 0x01000000; 960 961 /** 962 * Mask to check if the scrollbar style is inside or outside. 963 * {@hide} 964 */ 965 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 966 967 /** 968 * Mask for scrollbar style. 969 * {@hide} 970 */ 971 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 972 973 /** 974 * View flag indicating that the screen should remain on while the 975 * window containing this view is visible to the user. This effectively 976 * takes care of automatically setting the WindowManager's 977 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 978 */ 979 public static final int KEEP_SCREEN_ON = 0x04000000; 980 981 /** 982 * View flag indicating whether this view should have sound effects enabled 983 * for events such as clicking and touching. 984 */ 985 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 986 987 /** 988 * View flag indicating whether this view should have haptic feedback 989 * enabled for events such as long presses. 990 */ 991 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 992 993 /** 994 * <p>Indicates that the view hierarchy should stop saving state when 995 * it reaches this view. If state saving is initiated immediately at 996 * the view, it will be allowed. 997 * {@hide} 998 */ 999 static final int PARENT_SAVE_DISABLED = 0x20000000; 1000 1001 /** 1002 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1003 * {@hide} 1004 */ 1005 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1006 1007 /** 1008 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1009 * should add all focusable Views regardless if they are focusable in touch mode. 1010 */ 1011 public static final int FOCUSABLES_ALL = 0x00000000; 1012 1013 /** 1014 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1015 * should add only Views focusable in touch mode. 1016 */ 1017 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1018 1019 /** 1020 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1021 * item. 1022 */ 1023 public static final int FOCUS_BACKWARD = 0x00000001; 1024 1025 /** 1026 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1027 * item. 1028 */ 1029 public static final int FOCUS_FORWARD = 0x00000002; 1030 1031 /** 1032 * Use with {@link #focusSearch(int)}. Move focus to the left. 1033 */ 1034 public static final int FOCUS_LEFT = 0x00000011; 1035 1036 /** 1037 * Use with {@link #focusSearch(int)}. Move focus up. 1038 */ 1039 public static final int FOCUS_UP = 0x00000021; 1040 1041 /** 1042 * Use with {@link #focusSearch(int)}. Move focus to the right. 1043 */ 1044 public static final int FOCUS_RIGHT = 0x00000042; 1045 1046 /** 1047 * Use with {@link #focusSearch(int)}. Move focus down. 1048 */ 1049 public static final int FOCUS_DOWN = 0x00000082; 1050 1051 /** 1052 * Bits of {@link #getMeasuredWidthAndState()} and 1053 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1054 */ 1055 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1056 1057 /** 1058 * Bits of {@link #getMeasuredWidthAndState()} and 1059 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1060 */ 1061 public static final int MEASURED_STATE_MASK = 0xff000000; 1062 1063 /** 1064 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1065 * for functions that combine both width and height into a single int, 1066 * such as {@link #getMeasuredState()} and the childState argument of 1067 * {@link #resolveSizeAndState(int, int, int)}. 1068 */ 1069 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1070 1071 /** 1072 * Bit of {@link #getMeasuredWidthAndState()} and 1073 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1074 * is smaller that the space the view would like to have. 1075 */ 1076 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1077 1078 /** 1079 * Base View state sets 1080 */ 1081 // Singles 1082 /** 1083 * Indicates the view has no states set. States are used with 1084 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1085 * view depending on its state. 1086 * 1087 * @see android.graphics.drawable.Drawable 1088 * @see #getDrawableState() 1089 */ 1090 protected static final int[] EMPTY_STATE_SET; 1091 /** 1092 * Indicates the view is enabled. States are used with 1093 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1094 * view depending on its state. 1095 * 1096 * @see android.graphics.drawable.Drawable 1097 * @see #getDrawableState() 1098 */ 1099 protected static final int[] ENABLED_STATE_SET; 1100 /** 1101 * Indicates the view is focused. States are used with 1102 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1103 * view depending on its state. 1104 * 1105 * @see android.graphics.drawable.Drawable 1106 * @see #getDrawableState() 1107 */ 1108 protected static final int[] FOCUSED_STATE_SET; 1109 /** 1110 * Indicates the view is selected. States are used with 1111 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1112 * view depending on its state. 1113 * 1114 * @see android.graphics.drawable.Drawable 1115 * @see #getDrawableState() 1116 */ 1117 protected static final int[] SELECTED_STATE_SET; 1118 /** 1119 * Indicates the view is pressed. States are used with 1120 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1121 * view depending on its state. 1122 * 1123 * @see android.graphics.drawable.Drawable 1124 * @see #getDrawableState() 1125 * @hide 1126 */ 1127 protected static final int[] PRESSED_STATE_SET; 1128 /** 1129 * Indicates the view's window has focus. States are used with 1130 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1131 * view depending on its state. 1132 * 1133 * @see android.graphics.drawable.Drawable 1134 * @see #getDrawableState() 1135 */ 1136 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1137 // Doubles 1138 /** 1139 * Indicates the view is enabled and has the focus. 1140 * 1141 * @see #ENABLED_STATE_SET 1142 * @see #FOCUSED_STATE_SET 1143 */ 1144 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1145 /** 1146 * Indicates the view is enabled and selected. 1147 * 1148 * @see #ENABLED_STATE_SET 1149 * @see #SELECTED_STATE_SET 1150 */ 1151 protected static final int[] ENABLED_SELECTED_STATE_SET; 1152 /** 1153 * Indicates the view is enabled and that its window has focus. 1154 * 1155 * @see #ENABLED_STATE_SET 1156 * @see #WINDOW_FOCUSED_STATE_SET 1157 */ 1158 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1159 /** 1160 * Indicates the view is focused and selected. 1161 * 1162 * @see #FOCUSED_STATE_SET 1163 * @see #SELECTED_STATE_SET 1164 */ 1165 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1166 /** 1167 * Indicates the view has the focus and that its window has the focus. 1168 * 1169 * @see #FOCUSED_STATE_SET 1170 * @see #WINDOW_FOCUSED_STATE_SET 1171 */ 1172 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1173 /** 1174 * Indicates the view is selected and that its window has the focus. 1175 * 1176 * @see #SELECTED_STATE_SET 1177 * @see #WINDOW_FOCUSED_STATE_SET 1178 */ 1179 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1180 // Triples 1181 /** 1182 * Indicates the view is enabled, focused and selected. 1183 * 1184 * @see #ENABLED_STATE_SET 1185 * @see #FOCUSED_STATE_SET 1186 * @see #SELECTED_STATE_SET 1187 */ 1188 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1189 /** 1190 * Indicates the view is enabled, focused and its window has the focus. 1191 * 1192 * @see #ENABLED_STATE_SET 1193 * @see #FOCUSED_STATE_SET 1194 * @see #WINDOW_FOCUSED_STATE_SET 1195 */ 1196 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1197 /** 1198 * Indicates the view is enabled, selected and its window has the focus. 1199 * 1200 * @see #ENABLED_STATE_SET 1201 * @see #SELECTED_STATE_SET 1202 * @see #WINDOW_FOCUSED_STATE_SET 1203 */ 1204 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1205 /** 1206 * Indicates the view is focused, selected and its window has the focus. 1207 * 1208 * @see #FOCUSED_STATE_SET 1209 * @see #SELECTED_STATE_SET 1210 * @see #WINDOW_FOCUSED_STATE_SET 1211 */ 1212 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1213 /** 1214 * Indicates the view is enabled, focused, selected and its window 1215 * has the focus. 1216 * 1217 * @see #ENABLED_STATE_SET 1218 * @see #FOCUSED_STATE_SET 1219 * @see #SELECTED_STATE_SET 1220 * @see #WINDOW_FOCUSED_STATE_SET 1221 */ 1222 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1223 /** 1224 * Indicates the view is pressed and its window has the focus. 1225 * 1226 * @see #PRESSED_STATE_SET 1227 * @see #WINDOW_FOCUSED_STATE_SET 1228 */ 1229 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1230 /** 1231 * Indicates the view is pressed and selected. 1232 * 1233 * @see #PRESSED_STATE_SET 1234 * @see #SELECTED_STATE_SET 1235 */ 1236 protected static final int[] PRESSED_SELECTED_STATE_SET; 1237 /** 1238 * Indicates the view is pressed, selected and its window has the focus. 1239 * 1240 * @see #PRESSED_STATE_SET 1241 * @see #SELECTED_STATE_SET 1242 * @see #WINDOW_FOCUSED_STATE_SET 1243 */ 1244 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1245 /** 1246 * Indicates the view is pressed and focused. 1247 * 1248 * @see #PRESSED_STATE_SET 1249 * @see #FOCUSED_STATE_SET 1250 */ 1251 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1252 /** 1253 * Indicates the view is pressed, focused and its window has the focus. 1254 * 1255 * @see #PRESSED_STATE_SET 1256 * @see #FOCUSED_STATE_SET 1257 * @see #WINDOW_FOCUSED_STATE_SET 1258 */ 1259 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1260 /** 1261 * Indicates the view is pressed, focused and selected. 1262 * 1263 * @see #PRESSED_STATE_SET 1264 * @see #SELECTED_STATE_SET 1265 * @see #FOCUSED_STATE_SET 1266 */ 1267 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1268 /** 1269 * Indicates the view is pressed, focused, selected and its window has the focus. 1270 * 1271 * @see #PRESSED_STATE_SET 1272 * @see #FOCUSED_STATE_SET 1273 * @see #SELECTED_STATE_SET 1274 * @see #WINDOW_FOCUSED_STATE_SET 1275 */ 1276 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1277 /** 1278 * Indicates the view is pressed and enabled. 1279 * 1280 * @see #PRESSED_STATE_SET 1281 * @see #ENABLED_STATE_SET 1282 */ 1283 protected static final int[] PRESSED_ENABLED_STATE_SET; 1284 /** 1285 * Indicates the view is pressed, enabled and its window has the focus. 1286 * 1287 * @see #PRESSED_STATE_SET 1288 * @see #ENABLED_STATE_SET 1289 * @see #WINDOW_FOCUSED_STATE_SET 1290 */ 1291 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1292 /** 1293 * Indicates the view is pressed, enabled and selected. 1294 * 1295 * @see #PRESSED_STATE_SET 1296 * @see #ENABLED_STATE_SET 1297 * @see #SELECTED_STATE_SET 1298 */ 1299 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1300 /** 1301 * Indicates the view is pressed, enabled, selected and its window has the 1302 * focus. 1303 * 1304 * @see #PRESSED_STATE_SET 1305 * @see #ENABLED_STATE_SET 1306 * @see #SELECTED_STATE_SET 1307 * @see #WINDOW_FOCUSED_STATE_SET 1308 */ 1309 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1310 /** 1311 * Indicates the view is pressed, enabled and focused. 1312 * 1313 * @see #PRESSED_STATE_SET 1314 * @see #ENABLED_STATE_SET 1315 * @see #FOCUSED_STATE_SET 1316 */ 1317 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1318 /** 1319 * Indicates the view is pressed, enabled, focused and its window has the 1320 * focus. 1321 * 1322 * @see #PRESSED_STATE_SET 1323 * @see #ENABLED_STATE_SET 1324 * @see #FOCUSED_STATE_SET 1325 * @see #WINDOW_FOCUSED_STATE_SET 1326 */ 1327 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1328 /** 1329 * Indicates the view is pressed, enabled, focused and selected. 1330 * 1331 * @see #PRESSED_STATE_SET 1332 * @see #ENABLED_STATE_SET 1333 * @see #SELECTED_STATE_SET 1334 * @see #FOCUSED_STATE_SET 1335 */ 1336 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1337 /** 1338 * Indicates the view is pressed, enabled, focused, selected and its window 1339 * has the focus. 1340 * 1341 * @see #PRESSED_STATE_SET 1342 * @see #ENABLED_STATE_SET 1343 * @see #SELECTED_STATE_SET 1344 * @see #FOCUSED_STATE_SET 1345 * @see #WINDOW_FOCUSED_STATE_SET 1346 */ 1347 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1348 1349 /** 1350 * The order here is very important to {@link #getDrawableState()} 1351 */ 1352 private static final int[][] VIEW_STATE_SETS; 1353 1354 static final int VIEW_STATE_WINDOW_FOCUSED = 1; 1355 static final int VIEW_STATE_SELECTED = 1 << 1; 1356 static final int VIEW_STATE_FOCUSED = 1 << 2; 1357 static final int VIEW_STATE_ENABLED = 1 << 3; 1358 static final int VIEW_STATE_PRESSED = 1 << 4; 1359 static final int VIEW_STATE_ACTIVATED = 1 << 5; 1360 static final int VIEW_STATE_ACCELERATED = 1 << 6; 1361 static final int VIEW_STATE_HOVERED = 1 << 7; 1362 static final int VIEW_STATE_DRAG_CAN_ACCEPT = 1 << 8; 1363 static final int VIEW_STATE_DRAG_HOVERED = 1 << 9; 1364 1365 static final int[] VIEW_STATE_IDS = new int[] { 1366 R.attr.state_window_focused, VIEW_STATE_WINDOW_FOCUSED, 1367 R.attr.state_selected, VIEW_STATE_SELECTED, 1368 R.attr.state_focused, VIEW_STATE_FOCUSED, 1369 R.attr.state_enabled, VIEW_STATE_ENABLED, 1370 R.attr.state_pressed, VIEW_STATE_PRESSED, 1371 R.attr.state_activated, VIEW_STATE_ACTIVATED, 1372 R.attr.state_accelerated, VIEW_STATE_ACCELERATED, 1373 R.attr.state_hovered, VIEW_STATE_HOVERED, 1374 R.attr.state_drag_can_accept, VIEW_STATE_DRAG_CAN_ACCEPT, 1375 R.attr.state_drag_hovered, VIEW_STATE_DRAG_HOVERED 1376 }; 1377 1378 static { 1379 if ((VIEW_STATE_IDS.length/2) != R.styleable.ViewDrawableStates.length) { 1380 throw new IllegalStateException( 1381 "VIEW_STATE_IDs array length does not match ViewDrawableStates style array"); 1382 } 1383 int[] orderedIds = new int[VIEW_STATE_IDS.length]; 1384 for (int i = 0; i < R.styleable.ViewDrawableStates.length; i++) { 1385 int viewState = R.styleable.ViewDrawableStates[i]; 1386 for (int j = 0; j<VIEW_STATE_IDS.length; j += 2) { 1387 if (VIEW_STATE_IDS[j] == viewState) { 1388 orderedIds[i * 2] = viewState; 1389 orderedIds[i * 2 + 1] = VIEW_STATE_IDS[j + 1]; 1390 } 1391 } 1392 } 1393 final int NUM_BITS = VIEW_STATE_IDS.length / 2; 1394 VIEW_STATE_SETS = new int[1 << NUM_BITS][]; 1395 for (int i = 0; i < VIEW_STATE_SETS.length; i++) { 1396 int numBits = Integer.bitCount(i); 1397 int[] set = new int[numBits]; 1398 int pos = 0; 1399 for (int j = 0; j < orderedIds.length; j += 2) { 1400 if ((i & orderedIds[j+1]) != 0) { 1401 set[pos++] = orderedIds[j]; 1402 } 1403 } 1404 VIEW_STATE_SETS[i] = set; 1405 } 1406 1407 EMPTY_STATE_SET = VIEW_STATE_SETS[0]; 1408 WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[VIEW_STATE_WINDOW_FOCUSED]; 1409 SELECTED_STATE_SET = VIEW_STATE_SETS[VIEW_STATE_SELECTED]; 1410 SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1411 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED]; 1412 FOCUSED_STATE_SET = VIEW_STATE_SETS[VIEW_STATE_FOCUSED]; 1413 FOCUSED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1414 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_FOCUSED]; 1415 FOCUSED_SELECTED_STATE_SET = VIEW_STATE_SETS[ 1416 VIEW_STATE_SELECTED | VIEW_STATE_FOCUSED]; 1417 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1418 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED 1419 | VIEW_STATE_FOCUSED]; 1420 ENABLED_STATE_SET = VIEW_STATE_SETS[VIEW_STATE_ENABLED]; 1421 ENABLED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1422 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_ENABLED]; 1423 ENABLED_SELECTED_STATE_SET = VIEW_STATE_SETS[ 1424 VIEW_STATE_SELECTED | VIEW_STATE_ENABLED]; 1425 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1426 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED 1427 | VIEW_STATE_ENABLED]; 1428 ENABLED_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1429 VIEW_STATE_FOCUSED | VIEW_STATE_ENABLED]; 1430 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1431 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_FOCUSED 1432 | VIEW_STATE_ENABLED]; 1433 ENABLED_FOCUSED_SELECTED_STATE_SET = VIEW_STATE_SETS[ 1434 VIEW_STATE_SELECTED | VIEW_STATE_FOCUSED 1435 | VIEW_STATE_ENABLED]; 1436 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1437 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED 1438 | VIEW_STATE_FOCUSED| VIEW_STATE_ENABLED]; 1439 1440 PRESSED_STATE_SET = VIEW_STATE_SETS[VIEW_STATE_PRESSED]; 1441 PRESSED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1442 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_PRESSED]; 1443 PRESSED_SELECTED_STATE_SET = VIEW_STATE_SETS[ 1444 VIEW_STATE_SELECTED | VIEW_STATE_PRESSED]; 1445 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1446 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED 1447 | VIEW_STATE_PRESSED]; 1448 PRESSED_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1449 VIEW_STATE_FOCUSED | VIEW_STATE_PRESSED]; 1450 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1451 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_FOCUSED 1452 | VIEW_STATE_PRESSED]; 1453 PRESSED_FOCUSED_SELECTED_STATE_SET = VIEW_STATE_SETS[ 1454 VIEW_STATE_SELECTED | VIEW_STATE_FOCUSED 1455 | VIEW_STATE_PRESSED]; 1456 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1457 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED 1458 | VIEW_STATE_FOCUSED | VIEW_STATE_PRESSED]; 1459 PRESSED_ENABLED_STATE_SET = VIEW_STATE_SETS[ 1460 VIEW_STATE_ENABLED | VIEW_STATE_PRESSED]; 1461 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1462 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_ENABLED 1463 | VIEW_STATE_PRESSED]; 1464 PRESSED_ENABLED_SELECTED_STATE_SET = VIEW_STATE_SETS[ 1465 VIEW_STATE_SELECTED | VIEW_STATE_ENABLED 1466 | VIEW_STATE_PRESSED]; 1467 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1468 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED 1469 | VIEW_STATE_ENABLED | VIEW_STATE_PRESSED]; 1470 PRESSED_ENABLED_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1471 VIEW_STATE_FOCUSED | VIEW_STATE_ENABLED 1472 | VIEW_STATE_PRESSED]; 1473 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1474 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_FOCUSED 1475 | VIEW_STATE_ENABLED | VIEW_STATE_PRESSED]; 1476 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = VIEW_STATE_SETS[ 1477 VIEW_STATE_SELECTED | VIEW_STATE_FOCUSED 1478 | VIEW_STATE_ENABLED | VIEW_STATE_PRESSED]; 1479 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[ 1480 VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED 1481 | VIEW_STATE_FOCUSED| VIEW_STATE_ENABLED 1482 | VIEW_STATE_PRESSED]; 1483 } 1484 1485 /** 1486 * Accessibility event types that are dispatched for text population. 1487 */ 1488 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 1489 AccessibilityEvent.TYPE_VIEW_CLICKED 1490 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 1491 | AccessibilityEvent.TYPE_VIEW_SELECTED 1492 | AccessibilityEvent.TYPE_VIEW_FOCUSED 1493 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 1494 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 1495 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 1496 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 1497 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 1498 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 1499 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 1500 1501 /** 1502 * Temporary Rect currently for use in setBackground(). This will probably 1503 * be extended in the future to hold our own class with more than just 1504 * a Rect. :) 1505 */ 1506 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 1507 1508 /** 1509 * Map used to store views' tags. 1510 */ 1511 private SparseArray<Object> mKeyedTags; 1512 1513 /** 1514 * The next available accessibility id. 1515 */ 1516 private static int sNextAccessibilityViewId; 1517 1518 /** 1519 * The animation currently associated with this view. 1520 * @hide 1521 */ 1522 protected Animation mCurrentAnimation = null; 1523 1524 /** 1525 * Width as measured during measure pass. 1526 * {@hide} 1527 */ 1528 @ViewDebug.ExportedProperty(category = "measurement") 1529 int mMeasuredWidth; 1530 1531 /** 1532 * Height as measured during measure pass. 1533 * {@hide} 1534 */ 1535 @ViewDebug.ExportedProperty(category = "measurement") 1536 int mMeasuredHeight; 1537 1538 /** 1539 * Flag to indicate that this view was marked INVALIDATED, or had its display list 1540 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 1541 * its display list. This flag, used only when hw accelerated, allows us to clear the 1542 * flag while retaining this information until it's needed (at getDisplayList() time and 1543 * in drawChild(), when we decide to draw a view's children's display lists into our own). 1544 * 1545 * {@hide} 1546 */ 1547 boolean mRecreateDisplayList = false; 1548 1549 /** 1550 * The view's identifier. 1551 * {@hide} 1552 * 1553 * @see #setId(int) 1554 * @see #getId() 1555 */ 1556 @ViewDebug.ExportedProperty(resolveId = true) 1557 int mID = NO_ID; 1558 1559 /** 1560 * The stable ID of this view for accessibility purposes. 1561 */ 1562 int mAccessibilityViewId = NO_ID; 1563 1564 /** 1565 * @hide 1566 */ 1567 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 1568 1569 /** 1570 * The view's tag. 1571 * {@hide} 1572 * 1573 * @see #setTag(Object) 1574 * @see #getTag() 1575 */ 1576 protected Object mTag; 1577 1578 // for mPrivateFlags: 1579 /** {@hide} */ 1580 static final int PFLAG_WANTS_FOCUS = 0x00000001; 1581 /** {@hide} */ 1582 static final int PFLAG_FOCUSED = 0x00000002; 1583 /** {@hide} */ 1584 static final int PFLAG_SELECTED = 0x00000004; 1585 /** {@hide} */ 1586 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 1587 /** {@hide} */ 1588 static final int PFLAG_HAS_BOUNDS = 0x00000010; 1589 /** {@hide} */ 1590 static final int PFLAG_DRAWN = 0x00000020; 1591 /** 1592 * When this flag is set, this view is running an animation on behalf of its 1593 * children and should therefore not cancel invalidate requests, even if they 1594 * lie outside of this view's bounds. 1595 * 1596 * {@hide} 1597 */ 1598 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 1599 /** {@hide} */ 1600 static final int PFLAG_SKIP_DRAW = 0x00000080; 1601 /** {@hide} */ 1602 static final int PFLAG_ONLY_DRAWS_BACKGROUND = 0x00000100; 1603 /** {@hide} */ 1604 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 1605 /** {@hide} */ 1606 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 1607 /** {@hide} */ 1608 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 1609 /** {@hide} */ 1610 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 1611 /** {@hide} */ 1612 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 1613 1614 private static final int PFLAG_PRESSED = 0x00004000; 1615 1616 /** {@hide} */ 1617 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 1618 /** 1619 * Flag used to indicate that this view should be drawn once more (and only once 1620 * more) after its animation has completed. 1621 * {@hide} 1622 */ 1623 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 1624 1625 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 1626 1627 /** 1628 * Indicates that the View returned true when onSetAlpha() was called and that 1629 * the alpha must be restored. 1630 * {@hide} 1631 */ 1632 static final int PFLAG_ALPHA_SET = 0x00040000; 1633 1634 /** 1635 * Set by {@link #setScrollContainer(boolean)}. 1636 */ 1637 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 1638 1639 /** 1640 * Set by {@link #setScrollContainer(boolean)}. 1641 */ 1642 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 1643 1644 /** 1645 * View flag indicating whether this view was invalidated (fully or partially.) 1646 * 1647 * @hide 1648 */ 1649 static final int PFLAG_DIRTY = 0x00200000; 1650 1651 /** 1652 * View flag indicating whether this view was invalidated by an opaque 1653 * invalidate request. 1654 * 1655 * @hide 1656 */ 1657 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 1658 1659 /** 1660 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 1661 * 1662 * @hide 1663 */ 1664 static final int PFLAG_DIRTY_MASK = 0x00600000; 1665 1666 /** 1667 * Indicates whether the background is opaque. 1668 * 1669 * @hide 1670 */ 1671 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 1672 1673 /** 1674 * Indicates whether the scrollbars are opaque. 1675 * 1676 * @hide 1677 */ 1678 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 1679 1680 /** 1681 * Indicates whether the view is opaque. 1682 * 1683 * @hide 1684 */ 1685 static final int PFLAG_OPAQUE_MASK = 0x01800000; 1686 1687 /** 1688 * Indicates a prepressed state; 1689 * the short time between ACTION_DOWN and recognizing 1690 * a 'real' press. Prepressed is used to recognize quick taps 1691 * even when they are shorter than ViewConfiguration.getTapTimeout(). 1692 * 1693 * @hide 1694 */ 1695 private static final int PFLAG_PREPRESSED = 0x02000000; 1696 1697 /** 1698 * Indicates whether the view is temporarily detached. 1699 * 1700 * @hide 1701 */ 1702 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 1703 1704 /** 1705 * Indicates that we should awaken scroll bars once attached 1706 * 1707 * @hide 1708 */ 1709 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 1710 1711 /** 1712 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 1713 * @hide 1714 */ 1715 private static final int PFLAG_HOVERED = 0x10000000; 1716 1717 /** 1718 * Indicates that pivotX or pivotY were explicitly set and we should not assume the center 1719 * for transform operations 1720 * 1721 * @hide 1722 */ 1723 private static final int PFLAG_PIVOT_EXPLICITLY_SET = 0x20000000; 1724 1725 /** {@hide} */ 1726 static final int PFLAG_ACTIVATED = 0x40000000; 1727 1728 /** 1729 * Indicates that this view was specifically invalidated, not just dirtied because some 1730 * child view was invalidated. The flag is used to determine when we need to recreate 1731 * a view's display list (as opposed to just returning a reference to its existing 1732 * display list). 1733 * 1734 * @hide 1735 */ 1736 static final int PFLAG_INVALIDATED = 0x80000000; 1737 1738 /** 1739 * Masks for mPrivateFlags2, as generated by dumpFlags(): 1740 * 1741 * -------|-------|-------|-------| 1742 * PFLAG2_TEXT_ALIGNMENT_FLAGS[0] 1743 * PFLAG2_TEXT_DIRECTION_FLAGS[0] 1744 * 1 PFLAG2_DRAG_CAN_ACCEPT 1745 * 1 PFLAG2_DRAG_HOVERED 1746 * 1 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT 1747 * 11 PFLAG2_TEXT_DIRECTION_MASK_SHIFT 1748 * 1 1 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT 1749 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 1750 * 11 1 PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 1751 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 1752 * 1 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT 1753 * 1 1 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT 1754 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 1755 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 1756 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 1757 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 1758 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 1759 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 1760 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 1761 * 111 PFLAG2_TEXT_DIRECTION_MASK 1762 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 1763 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 1764 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 1765 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 1766 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 1767 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 1768 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 1769 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 1770 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 1771 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 1772 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 1773 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 1774 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 1775 * 11 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 1776 * 1 PFLAG2_HAS_TRANSIENT_STATE 1777 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 1778 * 1 PFLAG2_ACCESSIBILITY_STATE_CHANGED 1779 * 1 PFLAG2_VIEW_QUICK_REJECTED 1780 * 1 PFLAG2_PADDING_RESOLVED 1781 * -------|-------|-------|-------| 1782 */ 1783 1784 /** 1785 * Indicates that this view has reported that it can accept the current drag's content. 1786 * Cleared when the drag operation concludes. 1787 * @hide 1788 */ 1789 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 1790 1791 /** 1792 * Indicates that this view is currently directly under the drag location in a 1793 * drag-and-drop operation involving content that it can accept. Cleared when 1794 * the drag exits the view, or when the drag operation concludes. 1795 * @hide 1796 */ 1797 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 1798 1799 /** 1800 * Horizontal layout direction of this view is from Left to Right. 1801 * Use with {@link #setLayoutDirection}. 1802 */ 1803 public static final int LAYOUT_DIRECTION_LTR = 0; 1804 1805 /** 1806 * Horizontal layout direction of this view is from Right to Left. 1807 * Use with {@link #setLayoutDirection}. 1808 */ 1809 public static final int LAYOUT_DIRECTION_RTL = 1; 1810 1811 /** 1812 * Horizontal layout direction of this view is inherited from its parent. 1813 * Use with {@link #setLayoutDirection}. 1814 */ 1815 public static final int LAYOUT_DIRECTION_INHERIT = 2; 1816 1817 /** 1818 * Horizontal layout direction of this view is from deduced from the default language 1819 * script for the locale. Use with {@link #setLayoutDirection}. 1820 */ 1821 public static final int LAYOUT_DIRECTION_LOCALE = 3; 1822 1823 /** 1824 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 1825 * @hide 1826 */ 1827 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 1828 1829 /** 1830 * Mask for use with private flags indicating bits used for horizontal layout direction. 1831 * @hide 1832 */ 1833 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 1834 1835 /** 1836 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 1837 * right-to-left direction. 1838 * @hide 1839 */ 1840 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 1841 1842 /** 1843 * Indicates whether the view horizontal layout direction has been resolved. 1844 * @hide 1845 */ 1846 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 1847 1848 /** 1849 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 1850 * @hide 1851 */ 1852 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 1853 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 1854 1855 /* 1856 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 1857 * flag value. 1858 * @hide 1859 */ 1860 private static final int[] LAYOUT_DIRECTION_FLAGS = { 1861 LAYOUT_DIRECTION_LTR, 1862 LAYOUT_DIRECTION_RTL, 1863 LAYOUT_DIRECTION_INHERIT, 1864 LAYOUT_DIRECTION_LOCALE 1865 }; 1866 1867 /** 1868 * Default horizontal layout direction. 1869 */ 1870 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 1871 1872 /** 1873 * Indicates that the view is tracking some sort of transient state 1874 * that the app should not need to be aware of, but that the framework 1875 * should take special care to preserve. 1876 * 1877 * @hide 1878 */ 1879 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x1 << 22; 1880 1881 /** 1882 * Text direction is inherited thru {@link ViewGroup} 1883 */ 1884 public static final int TEXT_DIRECTION_INHERIT = 0; 1885 1886 /** 1887 * Text direction is using "first strong algorithm". The first strong directional character 1888 * determines the paragraph direction. If there is no strong directional character, the 1889 * paragraph direction is the view's resolved layout direction. 1890 */ 1891 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 1892 1893 /** 1894 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 1895 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 1896 * If there are neither, the paragraph direction is the view's resolved layout direction. 1897 */ 1898 public static final int TEXT_DIRECTION_ANY_RTL = 2; 1899 1900 /** 1901 * Text direction is forced to LTR. 1902 */ 1903 public static final int TEXT_DIRECTION_LTR = 3; 1904 1905 /** 1906 * Text direction is forced to RTL. 1907 */ 1908 public static final int TEXT_DIRECTION_RTL = 4; 1909 1910 /** 1911 * Text direction is coming from the system Locale. 1912 */ 1913 public static final int TEXT_DIRECTION_LOCALE = 5; 1914 1915 /** 1916 * Default text direction is inherited 1917 */ 1918 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 1919 1920 /** 1921 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 1922 * @hide 1923 */ 1924 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 1925 1926 /** 1927 * Mask for use with private flags indicating bits used for text direction. 1928 * @hide 1929 */ 1930 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 1931 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 1932 1933 /** 1934 * Array of text direction flags for mapping attribute "textDirection" to correct 1935 * flag value. 1936 * @hide 1937 */ 1938 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 1939 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 1940 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 1941 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 1942 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 1943 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 1944 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 1945 }; 1946 1947 /** 1948 * Indicates whether the view text direction has been resolved. 1949 * @hide 1950 */ 1951 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 1952 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 1953 1954 /** 1955 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 1956 * @hide 1957 */ 1958 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 1959 1960 /** 1961 * Mask for use with private flags indicating bits used for resolved text direction. 1962 * @hide 1963 */ 1964 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 1965 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 1966 1967 /** 1968 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 1969 * @hide 1970 */ 1971 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 1972 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 1973 1974 /* 1975 * Default text alignment. The text alignment of this View is inherited from its parent. 1976 * Use with {@link #setTextAlignment(int)} 1977 */ 1978 public static final int TEXT_ALIGNMENT_INHERIT = 0; 1979 1980 /** 1981 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 1982 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 1983 * 1984 * Use with {@link #setTextAlignment(int)} 1985 */ 1986 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 1987 1988 /** 1989 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 1990 * 1991 * Use with {@link #setTextAlignment(int)} 1992 */ 1993 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 1994 1995 /** 1996 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 1997 * 1998 * Use with {@link #setTextAlignment(int)} 1999 */ 2000 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2001 2002 /** 2003 * Center the paragraph, e.g. ALIGN_CENTER. 2004 * 2005 * Use with {@link #setTextAlignment(int)} 2006 */ 2007 public static final int TEXT_ALIGNMENT_CENTER = 4; 2008 2009 /** 2010 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2011 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2012 * 2013 * Use with {@link #setTextAlignment(int)} 2014 */ 2015 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2016 2017 /** 2018 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2019 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2020 * 2021 * Use with {@link #setTextAlignment(int)} 2022 */ 2023 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2024 2025 /** 2026 * Default text alignment is inherited 2027 */ 2028 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2029 2030 /** 2031 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2032 * @hide 2033 */ 2034 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2035 2036 /** 2037 * Mask for use with private flags indicating bits used for text alignment. 2038 * @hide 2039 */ 2040 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2041 2042 /** 2043 * Array of text direction flags for mapping attribute "textAlignment" to correct 2044 * flag value. 2045 * @hide 2046 */ 2047 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2048 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2049 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2050 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2051 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2052 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2053 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2054 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2055 }; 2056 2057 /** 2058 * Indicates whether the view text alignment has been resolved. 2059 * @hide 2060 */ 2061 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2062 2063 /** 2064 * Bit shift to get the resolved text alignment. 2065 * @hide 2066 */ 2067 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2068 2069 /** 2070 * Mask for use with private flags indicating bits used for text alignment. 2071 * @hide 2072 */ 2073 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2074 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2075 2076 /** 2077 * Indicates whether if the view text alignment has been resolved to gravity 2078 */ 2079 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2080 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2081 2082 // Accessiblity constants for mPrivateFlags2 2083 2084 /** 2085 * Shift for the bits in {@link #mPrivateFlags2} related to the 2086 * "importantForAccessibility" attribute. 2087 */ 2088 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2089 2090 /** 2091 * Automatically determine whether a view is important for accessibility. 2092 */ 2093 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2094 2095 /** 2096 * The view is important for accessibility. 2097 */ 2098 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2099 2100 /** 2101 * The view is not important for accessibility. 2102 */ 2103 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2104 2105 /** 2106 * The default whether the view is important for accessibility. 2107 */ 2108 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2109 2110 /** 2111 * Mask for obtainig the bits which specify how to determine 2112 * whether a view is important for accessibility. 2113 */ 2114 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2115 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO) 2116 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2117 2118 /** 2119 * Flag indicating whether a view has accessibility focus. 2120 */ 2121 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x00000040 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2122 2123 /** 2124 * Flag indicating whether a view state for accessibility has changed. 2125 */ 2126 static final int PFLAG2_ACCESSIBILITY_STATE_CHANGED = 0x00000080 2127 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2128 2129 /** 2130 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2131 * is used to check whether later changes to the view's transform should invalidate the 2132 * view to force the quickReject test to run again. 2133 */ 2134 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2135 2136 /** 2137 * Flag indicating that start/end padding has been resolved into left/right padding 2138 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2139 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2140 * during measurement. In some special cases this is required such as when an adapter-based 2141 * view measures prospective children without attaching them to a window. 2142 */ 2143 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2144 2145 /** 2146 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2147 */ 2148 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2149 2150 /** 2151 * Group of bits indicating that RTL properties resolution is done. 2152 */ 2153 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2154 PFLAG2_TEXT_DIRECTION_RESOLVED | 2155 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2156 PFLAG2_PADDING_RESOLVED | 2157 PFLAG2_DRAWABLE_RESOLVED; 2158 2159 // There are a couple of flags left in mPrivateFlags2 2160 2161 /* End of masks for mPrivateFlags2 */ 2162 2163 /* Masks for mPrivateFlags3 */ 2164 2165 /** 2166 * Flag indicating that view has a transform animation set on it. This is used to track whether 2167 * an animation is cleared between successive frames, in order to tell the associated 2168 * DisplayList to clear its animation matrix. 2169 */ 2170 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2171 2172 /** 2173 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2174 * animation is cleared between successive frames, in order to tell the associated 2175 * DisplayList to restore its alpha value. 2176 */ 2177 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2178 2179 2180 /* End of masks for mPrivateFlags3 */ 2181 2182 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2183 2184 /** 2185 * Always allow a user to over-scroll this view, provided it is a 2186 * view that can scroll. 2187 * 2188 * @see #getOverScrollMode() 2189 * @see #setOverScrollMode(int) 2190 */ 2191 public static final int OVER_SCROLL_ALWAYS = 0; 2192 2193 /** 2194 * Allow a user to over-scroll this view only if the content is large 2195 * enough to meaningfully scroll, provided it is a view that can scroll. 2196 * 2197 * @see #getOverScrollMode() 2198 * @see #setOverScrollMode(int) 2199 */ 2200 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 2201 2202 /** 2203 * Never allow a user to over-scroll this view. 2204 * 2205 * @see #getOverScrollMode() 2206 * @see #setOverScrollMode(int) 2207 */ 2208 public static final int OVER_SCROLL_NEVER = 2; 2209 2210 /** 2211 * Special constant for {@link #setSystemUiVisibility(int)}: View has 2212 * requested the system UI (status bar) to be visible (the default). 2213 * 2214 * @see #setSystemUiVisibility(int) 2215 */ 2216 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 2217 2218 /** 2219 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 2220 * system UI to enter an unobtrusive "low profile" mode. 2221 * 2222 * <p>This is for use in games, book readers, video players, or any other 2223 * "immersive" application where the usual system chrome is deemed too distracting. 2224 * 2225 * <p>In low profile mode, the status bar and/or navigation icons may dim. 2226 * 2227 * @see #setSystemUiVisibility(int) 2228 */ 2229 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 2230 2231 /** 2232 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 2233 * system navigation be temporarily hidden. 2234 * 2235 * <p>This is an even less obtrusive state than that called for by 2236 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 2237 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 2238 * those to disappear. This is useful (in conjunction with the 2239 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 2240 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 2241 * window flags) for displaying content using every last pixel on the display. 2242 * 2243 * <p>There is a limitation: because navigation controls are so important, the least user 2244 * interaction will cause them to reappear immediately. When this happens, both 2245 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 2246 * so that both elements reappear at the same time. 2247 * 2248 * @see #setSystemUiVisibility(int) 2249 */ 2250 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 2251 2252 /** 2253 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 2254 * into the normal fullscreen mode so that its content can take over the screen 2255 * while still allowing the user to interact with the application. 2256 * 2257 * <p>This has the same visual effect as 2258 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 2259 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 2260 * meaning that non-critical screen decorations (such as the status bar) will be 2261 * hidden while the user is in the View's window, focusing the experience on 2262 * that content. Unlike the window flag, if you are using ActionBar in 2263 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2264 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 2265 * hide the action bar. 2266 * 2267 * <p>This approach to going fullscreen is best used over the window flag when 2268 * it is a transient state -- that is, the application does this at certain 2269 * points in its user interaction where it wants to allow the user to focus 2270 * on content, but not as a continuous state. For situations where the application 2271 * would like to simply stay full screen the entire time (such as a game that 2272 * wants to take over the screen), the 2273 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 2274 * is usually a better approach. The state set here will be removed by the system 2275 * in various situations (such as the user moving to another application) like 2276 * the other system UI states. 2277 * 2278 * <p>When using this flag, the application should provide some easy facility 2279 * for the user to go out of it. A common example would be in an e-book 2280 * reader, where tapping on the screen brings back whatever screen and UI 2281 * decorations that had been hidden while the user was immersed in reading 2282 * the book. 2283 * 2284 * @see #setSystemUiVisibility(int) 2285 */ 2286 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 2287 2288 /** 2289 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 2290 * flags, we would like a stable view of the content insets given to 2291 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 2292 * will always represent the worst case that the application can expect 2293 * as a continuous state. In the stock Android UI this is the space for 2294 * the system bar, nav bar, and status bar, but not more transient elements 2295 * such as an input method. 2296 * 2297 * The stable layout your UI sees is based on the system UI modes you can 2298 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 2299 * then you will get a stable layout for changes of the 2300 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 2301 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 2302 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 2303 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 2304 * with a stable layout. (Note that you should avoid using 2305 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 2306 * 2307 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 2308 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 2309 * then a hidden status bar will be considered a "stable" state for purposes 2310 * here. This allows your UI to continually hide the status bar, while still 2311 * using the system UI flags to hide the action bar while still retaining 2312 * a stable layout. Note that changing the window fullscreen flag will never 2313 * provide a stable layout for a clean transition. 2314 * 2315 * <p>If you are using ActionBar in 2316 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2317 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 2318 * insets it adds to those given to the application. 2319 */ 2320 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 2321 2322 /** 2323 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2324 * to be layed out as if it has requested 2325 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 2326 * allows it to avoid artifacts when switching in and out of that mode, at 2327 * the expense that some of its user interface may be covered by screen 2328 * decorations when they are shown. You can perform layout of your inner 2329 * UI elements to account for the navagation system UI through the 2330 * {@link #fitSystemWindows(Rect)} method. 2331 */ 2332 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 2333 2334 /** 2335 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2336 * to be layed out as if it has requested 2337 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 2338 * allows it to avoid artifacts when switching in and out of that mode, at 2339 * the expense that some of its user interface may be covered by screen 2340 * decorations when they are shown. You can perform layout of your inner 2341 * UI elements to account for non-fullscreen system UI through the 2342 * {@link #fitSystemWindows(Rect)} method. 2343 */ 2344 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 2345 2346 /** 2347 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 2348 */ 2349 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 2350 2351 /** 2352 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 2353 */ 2354 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 2355 2356 /** 2357 * @hide 2358 * 2359 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2360 * out of the public fields to keep the undefined bits out of the developer's way. 2361 * 2362 * Flag to make the status bar not expandable. Unless you also 2363 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 2364 */ 2365 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 2366 2367 /** 2368 * @hide 2369 * 2370 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2371 * out of the public fields to keep the undefined bits out of the developer's way. 2372 * 2373 * Flag to hide notification icons and scrolling ticker text. 2374 */ 2375 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 2376 2377 /** 2378 * @hide 2379 * 2380 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2381 * out of the public fields to keep the undefined bits out of the developer's way. 2382 * 2383 * Flag to disable incoming notification alerts. This will not block 2384 * icons, but it will block sound, vibrating and other visual or aural notifications. 2385 */ 2386 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 2387 2388 /** 2389 * @hide 2390 * 2391 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2392 * out of the public fields to keep the undefined bits out of the developer's way. 2393 * 2394 * Flag to hide only the scrolling ticker. Note that 2395 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 2396 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 2397 */ 2398 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 2399 2400 /** 2401 * @hide 2402 * 2403 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2404 * out of the public fields to keep the undefined bits out of the developer's way. 2405 * 2406 * Flag to hide the center system info area. 2407 */ 2408 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 2409 2410 /** 2411 * @hide 2412 * 2413 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2414 * out of the public fields to keep the undefined bits out of the developer's way. 2415 * 2416 * Flag to hide only the home button. Don't use this 2417 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 2418 */ 2419 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 2420 2421 /** 2422 * @hide 2423 * 2424 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2425 * out of the public fields to keep the undefined bits out of the developer's way. 2426 * 2427 * Flag to hide only the back button. Don't use this 2428 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 2429 */ 2430 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 2431 2432 /** 2433 * @hide 2434 * 2435 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2436 * out of the public fields to keep the undefined bits out of the developer's way. 2437 * 2438 * Flag to hide only the clock. You might use this if your activity has 2439 * its own clock making the status bar's clock redundant. 2440 */ 2441 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 2442 2443 /** 2444 * @hide 2445 * 2446 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2447 * out of the public fields to keep the undefined bits out of the developer's way. 2448 * 2449 * Flag to hide only the recent apps button. Don't use this 2450 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 2451 */ 2452 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 2453 2454 /** 2455 * @hide 2456 * 2457 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2458 * out of the public fields to keep the undefined bits out of the developer's way. 2459 * 2460 * Flag to disable the global search gesture. Don't use this 2461 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 2462 */ 2463 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 2464 2465 /** 2466 * @hide 2467 */ 2468 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF; 2469 2470 /** 2471 * These are the system UI flags that can be cleared by events outside 2472 * of an application. Currently this is just the ability to tap on the 2473 * screen while hiding the navigation bar to have it return. 2474 * @hide 2475 */ 2476 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 2477 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 2478 | SYSTEM_UI_FLAG_FULLSCREEN; 2479 2480 /** 2481 * Flags that can impact the layout in relation to system UI. 2482 */ 2483 public static final int SYSTEM_UI_LAYOUT_FLAGS = 2484 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 2485 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 2486 2487 /** 2488 * Find views that render the specified text. 2489 * 2490 * @see #findViewsWithText(ArrayList, CharSequence, int) 2491 */ 2492 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 2493 2494 /** 2495 * Find find views that contain the specified content description. 2496 * 2497 * @see #findViewsWithText(ArrayList, CharSequence, int) 2498 */ 2499 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 2500 2501 /** 2502 * Find views that contain {@link AccessibilityNodeProvider}. Such 2503 * a View is a root of virtual view hierarchy and may contain the searched 2504 * text. If this flag is set Views with providers are automatically 2505 * added and it is a responsibility of the client to call the APIs of 2506 * the provider to determine whether the virtual tree rooted at this View 2507 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 2508 * represeting the virtual views with this text. 2509 * 2510 * @see #findViewsWithText(ArrayList, CharSequence, int) 2511 * 2512 * @hide 2513 */ 2514 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 2515 2516 /** 2517 * The undefined cursor position. 2518 */ 2519 private static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 2520 2521 /** 2522 * Indicates that the screen has changed state and is now off. 2523 * 2524 * @see #onScreenStateChanged(int) 2525 */ 2526 public static final int SCREEN_STATE_OFF = 0x0; 2527 2528 /** 2529 * Indicates that the screen has changed state and is now on. 2530 * 2531 * @see #onScreenStateChanged(int) 2532 */ 2533 public static final int SCREEN_STATE_ON = 0x1; 2534 2535 /** 2536 * Controls the over-scroll mode for this view. 2537 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 2538 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 2539 * and {@link #OVER_SCROLL_NEVER}. 2540 */ 2541 private int mOverScrollMode; 2542 2543 /** 2544 * The parent this view is attached to. 2545 * {@hide} 2546 * 2547 * @see #getParent() 2548 */ 2549 protected ViewParent mParent; 2550 2551 /** 2552 * {@hide} 2553 */ 2554 AttachInfo mAttachInfo; 2555 2556 /** 2557 * {@hide} 2558 */ 2559 @ViewDebug.ExportedProperty(flagMapping = { 2560 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 2561 name = "FORCE_LAYOUT"), 2562 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 2563 name = "LAYOUT_REQUIRED"), 2564 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 2565 name = "DRAWING_CACHE_INVALID", outputIf = false), 2566 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 2567 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 2568 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 2569 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 2570 }) 2571 int mPrivateFlags; 2572 int mPrivateFlags2; 2573 int mPrivateFlags3; 2574 2575 /** 2576 * This view's request for the visibility of the status bar. 2577 * @hide 2578 */ 2579 @ViewDebug.ExportedProperty(flagMapping = { 2580 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 2581 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 2582 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 2583 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 2584 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 2585 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 2586 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 2587 equals = SYSTEM_UI_FLAG_VISIBLE, 2588 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 2589 }) 2590 int mSystemUiVisibility; 2591 2592 /** 2593 * Reference count for transient state. 2594 * @see #setHasTransientState(boolean) 2595 */ 2596 int mTransientStateCount = 0; 2597 2598 /** 2599 * Count of how many windows this view has been attached to. 2600 */ 2601 int mWindowAttachCount; 2602 2603 /** 2604 * The layout parameters associated with this view and used by the parent 2605 * {@link android.view.ViewGroup} to determine how this view should be 2606 * laid out. 2607 * {@hide} 2608 */ 2609 protected ViewGroup.LayoutParams mLayoutParams; 2610 2611 /** 2612 * The view flags hold various views states. 2613 * {@hide} 2614 */ 2615 @ViewDebug.ExportedProperty 2616 int mViewFlags; 2617 2618 static class TransformationInfo { 2619 /** 2620 * The transform matrix for the View. This transform is calculated internally 2621 * based on the rotation, scaleX, and scaleY properties. The identity matrix 2622 * is used by default. Do *not* use this variable directly; instead call 2623 * getMatrix(), which will automatically recalculate the matrix if necessary 2624 * to get the correct matrix based on the latest rotation and scale properties. 2625 */ 2626 private final Matrix mMatrix = new Matrix(); 2627 2628 /** 2629 * The transform matrix for the View. This transform is calculated internally 2630 * based on the rotation, scaleX, and scaleY properties. The identity matrix 2631 * is used by default. Do *not* use this variable directly; instead call 2632 * getInverseMatrix(), which will automatically recalculate the matrix if necessary 2633 * to get the correct matrix based on the latest rotation and scale properties. 2634 */ 2635 private Matrix mInverseMatrix; 2636 2637 /** 2638 * An internal variable that tracks whether we need to recalculate the 2639 * transform matrix, based on whether the rotation or scaleX/Y properties 2640 * have changed since the matrix was last calculated. 2641 */ 2642 boolean mMatrixDirty = false; 2643 2644 /** 2645 * An internal variable that tracks whether we need to recalculate the 2646 * transform matrix, based on whether the rotation or scaleX/Y properties 2647 * have changed since the matrix was last calculated. 2648 */ 2649 private boolean mInverseMatrixDirty = true; 2650 2651 /** 2652 * A variable that tracks whether we need to recalculate the 2653 * transform matrix, based on whether the rotation or scaleX/Y properties 2654 * have changed since the matrix was last calculated. This variable 2655 * is only valid after a call to updateMatrix() or to a function that 2656 * calls it such as getMatrix(), hasIdentityMatrix() and getInverseMatrix(). 2657 */ 2658 private boolean mMatrixIsIdentity = true; 2659 2660 /** 2661 * The Camera object is used to compute a 3D matrix when rotationX or rotationY are set. 2662 */ 2663 private Camera mCamera = null; 2664 2665 /** 2666 * This matrix is used when computing the matrix for 3D rotations. 2667 */ 2668 private Matrix matrix3D = null; 2669 2670 /** 2671 * These prev values are used to recalculate a centered pivot point when necessary. The 2672 * pivot point is only used in matrix operations (when rotation, scale, or translation are 2673 * set), so thes values are only used then as well. 2674 */ 2675 private int mPrevWidth = -1; 2676 private int mPrevHeight = -1; 2677 2678 /** 2679 * The degrees rotation around the vertical axis through the pivot point. 2680 */ 2681 @ViewDebug.ExportedProperty 2682 float mRotationY = 0f; 2683 2684 /** 2685 * The degrees rotation around the horizontal axis through the pivot point. 2686 */ 2687 @ViewDebug.ExportedProperty 2688 float mRotationX = 0f; 2689 2690 /** 2691 * The degrees rotation around the pivot point. 2692 */ 2693 @ViewDebug.ExportedProperty 2694 float mRotation = 0f; 2695 2696 /** 2697 * The amount of translation of the object away from its left property (post-layout). 2698 */ 2699 @ViewDebug.ExportedProperty 2700 float mTranslationX = 0f; 2701 2702 /** 2703 * The amount of translation of the object away from its top property (post-layout). 2704 */ 2705 @ViewDebug.ExportedProperty 2706 float mTranslationY = 0f; 2707 2708 /** 2709 * The amount of scale in the x direction around the pivot point. A 2710 * value of 1 means no scaling is applied. 2711 */ 2712 @ViewDebug.ExportedProperty 2713 float mScaleX = 1f; 2714 2715 /** 2716 * The amount of scale in the y direction around the pivot point. A 2717 * value of 1 means no scaling is applied. 2718 */ 2719 @ViewDebug.ExportedProperty 2720 float mScaleY = 1f; 2721 2722 /** 2723 * The x location of the point around which the view is rotated and scaled. 2724 */ 2725 @ViewDebug.ExportedProperty 2726 float mPivotX = 0f; 2727 2728 /** 2729 * The y location of the point around which the view is rotated and scaled. 2730 */ 2731 @ViewDebug.ExportedProperty 2732 float mPivotY = 0f; 2733 2734 /** 2735 * The opacity of the View. This is a value from 0 to 1, where 0 means 2736 * completely transparent and 1 means completely opaque. 2737 */ 2738 @ViewDebug.ExportedProperty 2739 float mAlpha = 1f; 2740 } 2741 2742 TransformationInfo mTransformationInfo; 2743 2744 private boolean mLastIsOpaque; 2745 2746 /** 2747 * Convenience value to check for float values that are close enough to zero to be considered 2748 * zero. 2749 */ 2750 private static final float NONZERO_EPSILON = .001f; 2751 2752 /** 2753 * The distance in pixels from the left edge of this view's parent 2754 * to the left edge of this view. 2755 * {@hide} 2756 */ 2757 @ViewDebug.ExportedProperty(category = "layout") 2758 protected int mLeft; 2759 /** 2760 * The distance in pixels from the left edge of this view's parent 2761 * to the right edge of this view. 2762 * {@hide} 2763 */ 2764 @ViewDebug.ExportedProperty(category = "layout") 2765 protected int mRight; 2766 /** 2767 * The distance in pixels from the top edge of this view's parent 2768 * to the top edge of this view. 2769 * {@hide} 2770 */ 2771 @ViewDebug.ExportedProperty(category = "layout") 2772 protected int mTop; 2773 /** 2774 * The distance in pixels from the top edge of this view's parent 2775 * to the bottom edge of this view. 2776 * {@hide} 2777 */ 2778 @ViewDebug.ExportedProperty(category = "layout") 2779 protected int mBottom; 2780 2781 /** 2782 * The offset, in pixels, by which the content of this view is scrolled 2783 * horizontally. 2784 * {@hide} 2785 */ 2786 @ViewDebug.ExportedProperty(category = "scrolling") 2787 protected int mScrollX; 2788 /** 2789 * The offset, in pixels, by which the content of this view is scrolled 2790 * vertically. 2791 * {@hide} 2792 */ 2793 @ViewDebug.ExportedProperty(category = "scrolling") 2794 protected int mScrollY; 2795 2796 /** 2797 * The left padding in pixels, that is the distance in pixels between the 2798 * left edge of this view and the left edge of its content. 2799 * {@hide} 2800 */ 2801 @ViewDebug.ExportedProperty(category = "padding") 2802 protected int mPaddingLeft = 0; 2803 /** 2804 * The right padding in pixels, that is the distance in pixels between the 2805 * right edge of this view and the right edge of its content. 2806 * {@hide} 2807 */ 2808 @ViewDebug.ExportedProperty(category = "padding") 2809 protected int mPaddingRight = 0; 2810 /** 2811 * The top padding in pixels, that is the distance in pixels between the 2812 * top edge of this view and the top edge of its content. 2813 * {@hide} 2814 */ 2815 @ViewDebug.ExportedProperty(category = "padding") 2816 protected int mPaddingTop; 2817 /** 2818 * The bottom padding in pixels, that is the distance in pixels between the 2819 * bottom edge of this view and the bottom edge of its content. 2820 * {@hide} 2821 */ 2822 @ViewDebug.ExportedProperty(category = "padding") 2823 protected int mPaddingBottom; 2824 2825 /** 2826 * The layout insets in pixels, that is the distance in pixels between the 2827 * visible edges of this view its bounds. 2828 */ 2829 private Insets mLayoutInsets; 2830 2831 /** 2832 * Briefly describes the view and is primarily used for accessibility support. 2833 */ 2834 private CharSequence mContentDescription; 2835 2836 /** 2837 * Specifies the id of a view for which this view serves as a label for 2838 * accessibility purposes. 2839 */ 2840 private int mLabelForId = View.NO_ID; 2841 2842 /** 2843 * Predicate for matching labeled view id with its label for 2844 * accessibility purposes. 2845 */ 2846 private MatchLabelForPredicate mMatchLabelForPredicate; 2847 2848 /** 2849 * Predicate for matching a view by its id. 2850 */ 2851 private MatchIdPredicate mMatchIdPredicate; 2852 2853 /** 2854 * Cache the paddingRight set by the user to append to the scrollbar's size. 2855 * 2856 * @hide 2857 */ 2858 @ViewDebug.ExportedProperty(category = "padding") 2859 protected int mUserPaddingRight; 2860 2861 /** 2862 * Cache the paddingBottom set by the user to append to the scrollbar's size. 2863 * 2864 * @hide 2865 */ 2866 @ViewDebug.ExportedProperty(category = "padding") 2867 protected int mUserPaddingBottom; 2868 2869 /** 2870 * Cache the paddingLeft set by the user to append to the scrollbar's size. 2871 * 2872 * @hide 2873 */ 2874 @ViewDebug.ExportedProperty(category = "padding") 2875 protected int mUserPaddingLeft; 2876 2877 /** 2878 * Cache the paddingStart set by the user to append to the scrollbar's size. 2879 * 2880 */ 2881 @ViewDebug.ExportedProperty(category = "padding") 2882 int mUserPaddingStart; 2883 2884 /** 2885 * Cache the paddingEnd set by the user to append to the scrollbar's size. 2886 * 2887 */ 2888 @ViewDebug.ExportedProperty(category = "padding") 2889 int mUserPaddingEnd; 2890 2891 /** 2892 * Cache initial left padding. 2893 * 2894 * @hide 2895 */ 2896 int mUserPaddingLeftInitial = 0; 2897 2898 /** 2899 * Cache initial right padding. 2900 * 2901 * @hide 2902 */ 2903 int mUserPaddingRightInitial = 0; 2904 2905 /** 2906 * Default undefined padding 2907 */ 2908 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 2909 2910 /** 2911 * @hide 2912 */ 2913 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 2914 /** 2915 * @hide 2916 */ 2917 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 2918 2919 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 2920 private Drawable mBackground; 2921 2922 private int mBackgroundResource; 2923 private boolean mBackgroundSizeChanged; 2924 2925 static class ListenerInfo { 2926 /** 2927 * Listener used to dispatch focus change events. 2928 * This field should be made private, so it is hidden from the SDK. 2929 * {@hide} 2930 */ 2931 protected OnFocusChangeListener mOnFocusChangeListener; 2932 2933 /** 2934 * Listeners for layout change events. 2935 */ 2936 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 2937 2938 /** 2939 * Listeners for attach events. 2940 */ 2941 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 2942 2943 /** 2944 * Listener used to dispatch click events. 2945 * This field should be made private, so it is hidden from the SDK. 2946 * {@hide} 2947 */ 2948 public OnClickListener mOnClickListener; 2949 2950 /** 2951 * Listener used to dispatch long click events. 2952 * This field should be made private, so it is hidden from the SDK. 2953 * {@hide} 2954 */ 2955 protected OnLongClickListener mOnLongClickListener; 2956 2957 /** 2958 * Listener used to build the context menu. 2959 * This field should be made private, so it is hidden from the SDK. 2960 * {@hide} 2961 */ 2962 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 2963 2964 private OnKeyListener mOnKeyListener; 2965 2966 private OnTouchListener mOnTouchListener; 2967 2968 private OnHoverListener mOnHoverListener; 2969 2970 private OnGenericMotionListener mOnGenericMotionListener; 2971 2972 private OnDragListener mOnDragListener; 2973 2974 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 2975 } 2976 2977 ListenerInfo mListenerInfo; 2978 2979 /** 2980 * The application environment this view lives in. 2981 * This field should be made private, so it is hidden from the SDK. 2982 * {@hide} 2983 */ 2984 protected Context mContext; 2985 2986 private final Resources mResources; 2987 2988 private ScrollabilityCache mScrollCache; 2989 2990 private int[] mDrawableState = null; 2991 2992 /** 2993 * Set to true when drawing cache is enabled and cannot be created. 2994 * 2995 * @hide 2996 */ 2997 public boolean mCachingFailed; 2998 2999 private Bitmap mDrawingCache; 3000 private Bitmap mUnscaledDrawingCache; 3001 private HardwareLayer mHardwareLayer; 3002 DisplayList mDisplayList; 3003 3004 /** 3005 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 3006 * the user may specify which view to go to next. 3007 */ 3008 private int mNextFocusLeftId = View.NO_ID; 3009 3010 /** 3011 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 3012 * the user may specify which view to go to next. 3013 */ 3014 private int mNextFocusRightId = View.NO_ID; 3015 3016 /** 3017 * When this view has focus and the next focus is {@link #FOCUS_UP}, 3018 * the user may specify which view to go to next. 3019 */ 3020 private int mNextFocusUpId = View.NO_ID; 3021 3022 /** 3023 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 3024 * the user may specify which view to go to next. 3025 */ 3026 private int mNextFocusDownId = View.NO_ID; 3027 3028 /** 3029 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 3030 * the user may specify which view to go to next. 3031 */ 3032 int mNextFocusForwardId = View.NO_ID; 3033 3034 private CheckForLongPress mPendingCheckForLongPress; 3035 private CheckForTap mPendingCheckForTap = null; 3036 private PerformClick mPerformClick; 3037 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 3038 3039 private UnsetPressedState mUnsetPressedState; 3040 3041 /** 3042 * Whether the long press's action has been invoked. The tap's action is invoked on the 3043 * up event while a long press is invoked as soon as the long press duration is reached, so 3044 * a long press could be performed before the tap is checked, in which case the tap's action 3045 * should not be invoked. 3046 */ 3047 private boolean mHasPerformedLongPress; 3048 3049 /** 3050 * The minimum height of the view. We'll try our best to have the height 3051 * of this view to at least this amount. 3052 */ 3053 @ViewDebug.ExportedProperty(category = "measurement") 3054 private int mMinHeight; 3055 3056 /** 3057 * The minimum width of the view. We'll try our best to have the width 3058 * of this view to at least this amount. 3059 */ 3060 @ViewDebug.ExportedProperty(category = "measurement") 3061 private int mMinWidth; 3062 3063 /** 3064 * The delegate to handle touch events that are physically in this view 3065 * but should be handled by another view. 3066 */ 3067 private TouchDelegate mTouchDelegate = null; 3068 3069 /** 3070 * Solid color to use as a background when creating the drawing cache. Enables 3071 * the cache to use 16 bit bitmaps instead of 32 bit. 3072 */ 3073 private int mDrawingCacheBackgroundColor = 0; 3074 3075 /** 3076 * Special tree observer used when mAttachInfo is null. 3077 */ 3078 private ViewTreeObserver mFloatingTreeObserver; 3079 3080 /** 3081 * Cache the touch slop from the context that created the view. 3082 */ 3083 private int mTouchSlop; 3084 3085 /** 3086 * Object that handles automatic animation of view properties. 3087 */ 3088 private ViewPropertyAnimator mAnimator = null; 3089 3090 /** 3091 * Flag indicating that a drag can cross window boundaries. When 3092 * {@link #startDrag(ClipData, DragShadowBuilder, Object, int)} is called 3093 * with this flag set, all visible applications will be able to participate 3094 * in the drag operation and receive the dragged content. 3095 * 3096 * @hide 3097 */ 3098 public static final int DRAG_FLAG_GLOBAL = 1; 3099 3100 /** 3101 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 3102 */ 3103 private float mVerticalScrollFactor; 3104 3105 /** 3106 * Position of the vertical scroll bar. 3107 */ 3108 private int mVerticalScrollbarPosition; 3109 3110 /** 3111 * Position the scroll bar at the default position as determined by the system. 3112 */ 3113 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 3114 3115 /** 3116 * Position the scroll bar along the left edge. 3117 */ 3118 public static final int SCROLLBAR_POSITION_LEFT = 1; 3119 3120 /** 3121 * Position the scroll bar along the right edge. 3122 */ 3123 public static final int SCROLLBAR_POSITION_RIGHT = 2; 3124 3125 /** 3126 * Indicates that the view does not have a layer. 3127 * 3128 * @see #getLayerType() 3129 * @see #setLayerType(int, android.graphics.Paint) 3130 * @see #LAYER_TYPE_SOFTWARE 3131 * @see #LAYER_TYPE_HARDWARE 3132 */ 3133 public static final int LAYER_TYPE_NONE = 0; 3134 3135 /** 3136 * <p>Indicates that the view has a software layer. A software layer is backed 3137 * by a bitmap and causes the view to be rendered using Android's software 3138 * rendering pipeline, even if hardware acceleration is enabled.</p> 3139 * 3140 * <p>Software layers have various usages:</p> 3141 * <p>When the application is not using hardware acceleration, a software layer 3142 * is useful to apply a specific color filter and/or blending mode and/or 3143 * translucency to a view and all its children.</p> 3144 * <p>When the application is using hardware acceleration, a software layer 3145 * is useful to render drawing primitives not supported by the hardware 3146 * accelerated pipeline. It can also be used to cache a complex view tree 3147 * into a texture and reduce the complexity of drawing operations. For instance, 3148 * when animating a complex view tree with a translation, a software layer can 3149 * be used to render the view tree only once.</p> 3150 * <p>Software layers should be avoided when the affected view tree updates 3151 * often. Every update will require to re-render the software layer, which can 3152 * potentially be slow (particularly when hardware acceleration is turned on 3153 * since the layer will have to be uploaded into a hardware texture after every 3154 * update.)</p> 3155 * 3156 * @see #getLayerType() 3157 * @see #setLayerType(int, android.graphics.Paint) 3158 * @see #LAYER_TYPE_NONE 3159 * @see #LAYER_TYPE_HARDWARE 3160 */ 3161 public static final int LAYER_TYPE_SOFTWARE = 1; 3162 3163 /** 3164 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 3165 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 3166 * OpenGL hardware) and causes the view to be rendered using Android's hardware 3167 * rendering pipeline, but only if hardware acceleration is turned on for the 3168 * view hierarchy. When hardware acceleration is turned off, hardware layers 3169 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 3170 * 3171 * <p>A hardware layer is useful to apply a specific color filter and/or 3172 * blending mode and/or translucency to a view and all its children.</p> 3173 * <p>A hardware layer can be used to cache a complex view tree into a 3174 * texture and reduce the complexity of drawing operations. For instance, 3175 * when animating a complex view tree with a translation, a hardware layer can 3176 * be used to render the view tree only once.</p> 3177 * <p>A hardware layer can also be used to increase the rendering quality when 3178 * rotation transformations are applied on a view. It can also be used to 3179 * prevent potential clipping issues when applying 3D transforms on a view.</p> 3180 * 3181 * @see #getLayerType() 3182 * @see #setLayerType(int, android.graphics.Paint) 3183 * @see #LAYER_TYPE_NONE 3184 * @see #LAYER_TYPE_SOFTWARE 3185 */ 3186 public static final int LAYER_TYPE_HARDWARE = 2; 3187 3188 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 3189 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 3190 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 3191 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 3192 }) 3193 int mLayerType = LAYER_TYPE_NONE; 3194 Paint mLayerPaint; 3195 Rect mLocalDirtyRect; 3196 3197 /** 3198 * Set to true when the view is sending hover accessibility events because it 3199 * is the innermost hovered view. 3200 */ 3201 private boolean mSendingHoverAccessibilityEvents; 3202 3203 /** 3204 * Delegate for injecting accessibility functionality. 3205 */ 3206 AccessibilityDelegate mAccessibilityDelegate; 3207 3208 /** 3209 * Consistency verifier for debugging purposes. 3210 * @hide 3211 */ 3212 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 3213 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 3214 new InputEventConsistencyVerifier(this, 0) : null; 3215 3216 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 3217 3218 /** 3219 * Simple constructor to use when creating a view from code. 3220 * 3221 * @param context The Context the view is running in, through which it can 3222 * access the current theme, resources, etc. 3223 */ View(Context context)3224 public View(Context context) { 3225 mContext = context; 3226 mResources = context != null ? context.getResources() : null; 3227 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED; 3228 // Set some flags defaults 3229 mPrivateFlags2 = 3230 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 3231 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 3232 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 3233 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 3234 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 3235 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 3236 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 3237 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 3238 mUserPaddingStart = UNDEFINED_PADDING; 3239 mUserPaddingEnd = UNDEFINED_PADDING; 3240 } 3241 3242 /** 3243 * Constructor that is called when inflating a view from XML. This is called 3244 * when a view is being constructed from an XML file, supplying attributes 3245 * that were specified in the XML file. This version uses a default style of 3246 * 0, so the only attribute values applied are those in the Context's Theme 3247 * and the given AttributeSet. 3248 * 3249 * <p> 3250 * The method onFinishInflate() will be called after all children have been 3251 * added. 3252 * 3253 * @param context The Context the view is running in, through which it can 3254 * access the current theme, resources, etc. 3255 * @param attrs The attributes of the XML tag that is inflating the view. 3256 * @see #View(Context, AttributeSet, int) 3257 */ View(Context context, AttributeSet attrs)3258 public View(Context context, AttributeSet attrs) { 3259 this(context, attrs, 0); 3260 } 3261 3262 /** 3263 * Perform inflation from XML and apply a class-specific base style. This 3264 * constructor of View allows subclasses to use their own base style when 3265 * they are inflating. For example, a Button class's constructor would call 3266 * this version of the super class constructor and supply 3267 * <code>R.attr.buttonStyle</code> for <var>defStyle</var>; this allows 3268 * the theme's button style to modify all of the base view attributes (in 3269 * particular its background) as well as the Button class's attributes. 3270 * 3271 * @param context The Context the view is running in, through which it can 3272 * access the current theme, resources, etc. 3273 * @param attrs The attributes of the XML tag that is inflating the view. 3274 * @param defStyle The default style to apply to this view. If 0, no style 3275 * will be applied (beyond what is included in the theme). This may 3276 * either be an attribute resource, whose value will be retrieved 3277 * from the current theme, or an explicit style resource. 3278 * @see #View(Context, AttributeSet) 3279 */ View(Context context, AttributeSet attrs, int defStyle)3280 public View(Context context, AttributeSet attrs, int defStyle) { 3281 this(context); 3282 3283 TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View, 3284 defStyle, 0); 3285 3286 Drawable background = null; 3287 3288 int leftPadding = -1; 3289 int topPadding = -1; 3290 int rightPadding = -1; 3291 int bottomPadding = -1; 3292 int startPadding = UNDEFINED_PADDING; 3293 int endPadding = UNDEFINED_PADDING; 3294 3295 int padding = -1; 3296 3297 int viewFlagValues = 0; 3298 int viewFlagMasks = 0; 3299 3300 boolean setScrollContainer = false; 3301 3302 int x = 0; 3303 int y = 0; 3304 3305 float tx = 0; 3306 float ty = 0; 3307 float rotation = 0; 3308 float rotationX = 0; 3309 float rotationY = 0; 3310 float sx = 1f; 3311 float sy = 1f; 3312 boolean transformSet = false; 3313 3314 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 3315 int overScrollMode = mOverScrollMode; 3316 boolean initializeScrollbars = false; 3317 3318 boolean leftPaddingDefined = false; 3319 boolean rightPaddingDefined = false; 3320 boolean startPaddingDefined = false; 3321 boolean endPaddingDefined = false; 3322 3323 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 3324 3325 final int N = a.getIndexCount(); 3326 for (int i = 0; i < N; i++) { 3327 int attr = a.getIndex(i); 3328 switch (attr) { 3329 case com.android.internal.R.styleable.View_background: 3330 background = a.getDrawable(attr); 3331 break; 3332 case com.android.internal.R.styleable.View_padding: 3333 padding = a.getDimensionPixelSize(attr, -1); 3334 mUserPaddingLeftInitial = padding; 3335 mUserPaddingRightInitial = padding; 3336 leftPaddingDefined = true; 3337 rightPaddingDefined = true; 3338 break; 3339 case com.android.internal.R.styleable.View_paddingLeft: 3340 leftPadding = a.getDimensionPixelSize(attr, -1); 3341 mUserPaddingLeftInitial = leftPadding; 3342 leftPaddingDefined = true; 3343 break; 3344 case com.android.internal.R.styleable.View_paddingTop: 3345 topPadding = a.getDimensionPixelSize(attr, -1); 3346 break; 3347 case com.android.internal.R.styleable.View_paddingRight: 3348 rightPadding = a.getDimensionPixelSize(attr, -1); 3349 mUserPaddingRightInitial = rightPadding; 3350 rightPaddingDefined = true; 3351 break; 3352 case com.android.internal.R.styleable.View_paddingBottom: 3353 bottomPadding = a.getDimensionPixelSize(attr, -1); 3354 break; 3355 case com.android.internal.R.styleable.View_paddingStart: 3356 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 3357 startPaddingDefined = true; 3358 break; 3359 case com.android.internal.R.styleable.View_paddingEnd: 3360 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 3361 endPaddingDefined = true; 3362 break; 3363 case com.android.internal.R.styleable.View_scrollX: 3364 x = a.getDimensionPixelOffset(attr, 0); 3365 break; 3366 case com.android.internal.R.styleable.View_scrollY: 3367 y = a.getDimensionPixelOffset(attr, 0); 3368 break; 3369 case com.android.internal.R.styleable.View_alpha: 3370 setAlpha(a.getFloat(attr, 1f)); 3371 break; 3372 case com.android.internal.R.styleable.View_transformPivotX: 3373 setPivotX(a.getDimensionPixelOffset(attr, 0)); 3374 break; 3375 case com.android.internal.R.styleable.View_transformPivotY: 3376 setPivotY(a.getDimensionPixelOffset(attr, 0)); 3377 break; 3378 case com.android.internal.R.styleable.View_translationX: 3379 tx = a.getDimensionPixelOffset(attr, 0); 3380 transformSet = true; 3381 break; 3382 case com.android.internal.R.styleable.View_translationY: 3383 ty = a.getDimensionPixelOffset(attr, 0); 3384 transformSet = true; 3385 break; 3386 case com.android.internal.R.styleable.View_rotation: 3387 rotation = a.getFloat(attr, 0); 3388 transformSet = true; 3389 break; 3390 case com.android.internal.R.styleable.View_rotationX: 3391 rotationX = a.getFloat(attr, 0); 3392 transformSet = true; 3393 break; 3394 case com.android.internal.R.styleable.View_rotationY: 3395 rotationY = a.getFloat(attr, 0); 3396 transformSet = true; 3397 break; 3398 case com.android.internal.R.styleable.View_scaleX: 3399 sx = a.getFloat(attr, 1f); 3400 transformSet = true; 3401 break; 3402 case com.android.internal.R.styleable.View_scaleY: 3403 sy = a.getFloat(attr, 1f); 3404 transformSet = true; 3405 break; 3406 case com.android.internal.R.styleable.View_id: 3407 mID = a.getResourceId(attr, NO_ID); 3408 break; 3409 case com.android.internal.R.styleable.View_tag: 3410 mTag = a.getText(attr); 3411 break; 3412 case com.android.internal.R.styleable.View_fitsSystemWindows: 3413 if (a.getBoolean(attr, false)) { 3414 viewFlagValues |= FITS_SYSTEM_WINDOWS; 3415 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 3416 } 3417 break; 3418 case com.android.internal.R.styleable.View_focusable: 3419 if (a.getBoolean(attr, false)) { 3420 viewFlagValues |= FOCUSABLE; 3421 viewFlagMasks |= FOCUSABLE_MASK; 3422 } 3423 break; 3424 case com.android.internal.R.styleable.View_focusableInTouchMode: 3425 if (a.getBoolean(attr, false)) { 3426 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 3427 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 3428 } 3429 break; 3430 case com.android.internal.R.styleable.View_clickable: 3431 if (a.getBoolean(attr, false)) { 3432 viewFlagValues |= CLICKABLE; 3433 viewFlagMasks |= CLICKABLE; 3434 } 3435 break; 3436 case com.android.internal.R.styleable.View_longClickable: 3437 if (a.getBoolean(attr, false)) { 3438 viewFlagValues |= LONG_CLICKABLE; 3439 viewFlagMasks |= LONG_CLICKABLE; 3440 } 3441 break; 3442 case com.android.internal.R.styleable.View_saveEnabled: 3443 if (!a.getBoolean(attr, true)) { 3444 viewFlagValues |= SAVE_DISABLED; 3445 viewFlagMasks |= SAVE_DISABLED_MASK; 3446 } 3447 break; 3448 case com.android.internal.R.styleable.View_duplicateParentState: 3449 if (a.getBoolean(attr, false)) { 3450 viewFlagValues |= DUPLICATE_PARENT_STATE; 3451 viewFlagMasks |= DUPLICATE_PARENT_STATE; 3452 } 3453 break; 3454 case com.android.internal.R.styleable.View_visibility: 3455 final int visibility = a.getInt(attr, 0); 3456 if (visibility != 0) { 3457 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 3458 viewFlagMasks |= VISIBILITY_MASK; 3459 } 3460 break; 3461 case com.android.internal.R.styleable.View_layoutDirection: 3462 // Clear any layout direction flags (included resolved bits) already set 3463 mPrivateFlags2 &= 3464 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 3465 // Set the layout direction flags depending on the value of the attribute 3466 final int layoutDirection = a.getInt(attr, -1); 3467 final int value = (layoutDirection != -1) ? 3468 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 3469 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 3470 break; 3471 case com.android.internal.R.styleable.View_drawingCacheQuality: 3472 final int cacheQuality = a.getInt(attr, 0); 3473 if (cacheQuality != 0) { 3474 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 3475 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 3476 } 3477 break; 3478 case com.android.internal.R.styleable.View_contentDescription: 3479 setContentDescription(a.getString(attr)); 3480 break; 3481 case com.android.internal.R.styleable.View_labelFor: 3482 setLabelFor(a.getResourceId(attr, NO_ID)); 3483 break; 3484 case com.android.internal.R.styleable.View_soundEffectsEnabled: 3485 if (!a.getBoolean(attr, true)) { 3486 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 3487 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 3488 } 3489 break; 3490 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 3491 if (!a.getBoolean(attr, true)) { 3492 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 3493 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 3494 } 3495 break; 3496 case R.styleable.View_scrollbars: 3497 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 3498 if (scrollbars != SCROLLBARS_NONE) { 3499 viewFlagValues |= scrollbars; 3500 viewFlagMasks |= SCROLLBARS_MASK; 3501 initializeScrollbars = true; 3502 } 3503 break; 3504 //noinspection deprecation 3505 case R.styleable.View_fadingEdge: 3506 if (targetSdkVersion >= ICE_CREAM_SANDWICH) { 3507 // Ignore the attribute starting with ICS 3508 break; 3509 } 3510 // With builds < ICS, fall through and apply fading edges 3511 case R.styleable.View_requiresFadingEdge: 3512 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 3513 if (fadingEdge != FADING_EDGE_NONE) { 3514 viewFlagValues |= fadingEdge; 3515 viewFlagMasks |= FADING_EDGE_MASK; 3516 initializeFadingEdge(a); 3517 } 3518 break; 3519 case R.styleable.View_scrollbarStyle: 3520 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 3521 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 3522 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 3523 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 3524 } 3525 break; 3526 case R.styleable.View_isScrollContainer: 3527 setScrollContainer = true; 3528 if (a.getBoolean(attr, false)) { 3529 setScrollContainer(true); 3530 } 3531 break; 3532 case com.android.internal.R.styleable.View_keepScreenOn: 3533 if (a.getBoolean(attr, false)) { 3534 viewFlagValues |= KEEP_SCREEN_ON; 3535 viewFlagMasks |= KEEP_SCREEN_ON; 3536 } 3537 break; 3538 case R.styleable.View_filterTouchesWhenObscured: 3539 if (a.getBoolean(attr, false)) { 3540 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 3541 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 3542 } 3543 break; 3544 case R.styleable.View_nextFocusLeft: 3545 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 3546 break; 3547 case R.styleable.View_nextFocusRight: 3548 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 3549 break; 3550 case R.styleable.View_nextFocusUp: 3551 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 3552 break; 3553 case R.styleable.View_nextFocusDown: 3554 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 3555 break; 3556 case R.styleable.View_nextFocusForward: 3557 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 3558 break; 3559 case R.styleable.View_minWidth: 3560 mMinWidth = a.getDimensionPixelSize(attr, 0); 3561 break; 3562 case R.styleable.View_minHeight: 3563 mMinHeight = a.getDimensionPixelSize(attr, 0); 3564 break; 3565 case R.styleable.View_onClick: 3566 if (context.isRestricted()) { 3567 throw new IllegalStateException("The android:onClick attribute cannot " 3568 + "be used within a restricted context"); 3569 } 3570 3571 final String handlerName = a.getString(attr); 3572 if (handlerName != null) { 3573 setOnClickListener(new OnClickListener() { 3574 private Method mHandler; 3575 3576 public void onClick(View v) { 3577 if (mHandler == null) { 3578 try { 3579 mHandler = getContext().getClass().getMethod(handlerName, 3580 View.class); 3581 } catch (NoSuchMethodException e) { 3582 int id = getId(); 3583 String idText = id == NO_ID ? "" : " with id '" 3584 + getContext().getResources().getResourceEntryName( 3585 id) + "'"; 3586 throw new IllegalStateException("Could not find a method " + 3587 handlerName + "(View) in the activity " 3588 + getContext().getClass() + " for onClick handler" 3589 + " on view " + View.this.getClass() + idText, e); 3590 } 3591 } 3592 3593 try { 3594 mHandler.invoke(getContext(), View.this); 3595 } catch (IllegalAccessException e) { 3596 throw new IllegalStateException("Could not execute non " 3597 + "public method of the activity", e); 3598 } catch (InvocationTargetException e) { 3599 throw new IllegalStateException("Could not execute " 3600 + "method of the activity", e); 3601 } 3602 } 3603 }); 3604 } 3605 break; 3606 case R.styleable.View_overScrollMode: 3607 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 3608 break; 3609 case R.styleable.View_verticalScrollbarPosition: 3610 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 3611 break; 3612 case R.styleable.View_layerType: 3613 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 3614 break; 3615 case R.styleable.View_textDirection: 3616 // Clear any text direction flag already set 3617 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 3618 // Set the text direction flags depending on the value of the attribute 3619 final int textDirection = a.getInt(attr, -1); 3620 if (textDirection != -1) { 3621 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 3622 } 3623 break; 3624 case R.styleable.View_textAlignment: 3625 // Clear any text alignment flag already set 3626 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 3627 // Set the text alignment flag depending on the value of the attribute 3628 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 3629 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 3630 break; 3631 case R.styleable.View_importantForAccessibility: 3632 setImportantForAccessibility(a.getInt(attr, 3633 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 3634 break; 3635 } 3636 } 3637 3638 setOverScrollMode(overScrollMode); 3639 3640 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 3641 // the resolved layout direction). Those cached values will be used later during padding 3642 // resolution. 3643 mUserPaddingStart = startPadding; 3644 mUserPaddingEnd = endPadding; 3645 3646 if (background != null) { 3647 setBackground(background); 3648 } 3649 3650 if (padding >= 0) { 3651 leftPadding = padding; 3652 topPadding = padding; 3653 rightPadding = padding; 3654 bottomPadding = padding; 3655 mUserPaddingLeftInitial = padding; 3656 mUserPaddingRightInitial = padding; 3657 } 3658 3659 if (isRtlCompatibilityMode()) { 3660 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 3661 // left / right padding are used if defined (meaning here nothing to do). If they are not 3662 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 3663 // start / end and resolve them as left / right (layout direction is not taken into account). 3664 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 3665 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 3666 // defined. 3667 if (!leftPaddingDefined && startPaddingDefined) { 3668 leftPadding = startPadding; 3669 } 3670 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 3671 if (!rightPaddingDefined && endPaddingDefined) { 3672 rightPadding = endPadding; 3673 } 3674 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 3675 } else { 3676 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 3677 // values defined. Otherwise, left /right values are used. 3678 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 3679 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 3680 // defined. 3681 if (leftPaddingDefined) { 3682 mUserPaddingLeftInitial = leftPadding; 3683 } 3684 if (rightPaddingDefined) { 3685 mUserPaddingRightInitial = rightPadding; 3686 } 3687 } 3688 3689 internalSetPadding( 3690 mUserPaddingLeftInitial, 3691 topPadding >= 0 ? topPadding : mPaddingTop, 3692 mUserPaddingRightInitial, 3693 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 3694 3695 if (viewFlagMasks != 0) { 3696 setFlags(viewFlagValues, viewFlagMasks); 3697 } 3698 3699 if (initializeScrollbars) { 3700 initializeScrollbars(a); 3701 } 3702 3703 a.recycle(); 3704 3705 // Needs to be called after mViewFlags is set 3706 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 3707 recomputePadding(); 3708 } 3709 3710 if (x != 0 || y != 0) { 3711 scrollTo(x, y); 3712 } 3713 3714 if (transformSet) { 3715 setTranslationX(tx); 3716 setTranslationY(ty); 3717 setRotation(rotation); 3718 setRotationX(rotationX); 3719 setRotationY(rotationY); 3720 setScaleX(sx); 3721 setScaleY(sy); 3722 } 3723 3724 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 3725 setScrollContainer(true); 3726 } 3727 3728 computeOpaqueFlags(); 3729 } 3730 3731 /** 3732 * Non-public constructor for use in testing 3733 */ View()3734 View() { 3735 mResources = null; 3736 } 3737 toString()3738 public String toString() { 3739 StringBuilder out = new StringBuilder(128); 3740 out.append(getClass().getName()); 3741 out.append('{'); 3742 out.append(Integer.toHexString(System.identityHashCode(this))); 3743 out.append(' '); 3744 switch (mViewFlags&VISIBILITY_MASK) { 3745 case VISIBLE: out.append('V'); break; 3746 case INVISIBLE: out.append('I'); break; 3747 case GONE: out.append('G'); break; 3748 default: out.append('.'); break; 3749 } 3750 out.append((mViewFlags&FOCUSABLE_MASK) == FOCUSABLE ? 'F' : '.'); 3751 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 3752 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 3753 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 3754 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 3755 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 3756 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 3757 out.append(' '); 3758 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 3759 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 3760 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 3761 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 3762 out.append('p'); 3763 } else { 3764 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 3765 } 3766 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 3767 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 3768 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 3769 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 3770 out.append(' '); 3771 out.append(mLeft); 3772 out.append(','); 3773 out.append(mTop); 3774 out.append('-'); 3775 out.append(mRight); 3776 out.append(','); 3777 out.append(mBottom); 3778 final int id = getId(); 3779 if (id != NO_ID) { 3780 out.append(" #"); 3781 out.append(Integer.toHexString(id)); 3782 final Resources r = mResources; 3783 if (id != 0 && r != null) { 3784 try { 3785 String pkgname; 3786 switch (id&0xff000000) { 3787 case 0x7f000000: 3788 pkgname="app"; 3789 break; 3790 case 0x01000000: 3791 pkgname="android"; 3792 break; 3793 default: 3794 pkgname = r.getResourcePackageName(id); 3795 break; 3796 } 3797 String typename = r.getResourceTypeName(id); 3798 String entryname = r.getResourceEntryName(id); 3799 out.append(" "); 3800 out.append(pkgname); 3801 out.append(":"); 3802 out.append(typename); 3803 out.append("/"); 3804 out.append(entryname); 3805 } catch (Resources.NotFoundException e) { 3806 } 3807 } 3808 } 3809 out.append("}"); 3810 return out.toString(); 3811 } 3812 3813 /** 3814 * <p> 3815 * Initializes the fading edges from a given set of styled attributes. This 3816 * method should be called by subclasses that need fading edges and when an 3817 * instance of these subclasses is created programmatically rather than 3818 * being inflated from XML. This method is automatically called when the XML 3819 * is inflated. 3820 * </p> 3821 * 3822 * @param a the styled attributes set to initialize the fading edges from 3823 */ initializeFadingEdge(TypedArray a)3824 protected void initializeFadingEdge(TypedArray a) { 3825 initScrollCache(); 3826 3827 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 3828 R.styleable.View_fadingEdgeLength, 3829 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 3830 } 3831 3832 /** 3833 * Returns the size of the vertical faded edges used to indicate that more 3834 * content in this view is visible. 3835 * 3836 * @return The size in pixels of the vertical faded edge or 0 if vertical 3837 * faded edges are not enabled for this view. 3838 * @attr ref android.R.styleable#View_fadingEdgeLength 3839 */ getVerticalFadingEdgeLength()3840 public int getVerticalFadingEdgeLength() { 3841 if (isVerticalFadingEdgeEnabled()) { 3842 ScrollabilityCache cache = mScrollCache; 3843 if (cache != null) { 3844 return cache.fadingEdgeLength; 3845 } 3846 } 3847 return 0; 3848 } 3849 3850 /** 3851 * Set the size of the faded edge used to indicate that more content in this 3852 * view is available. Will not change whether the fading edge is enabled; use 3853 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 3854 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 3855 * for the vertical or horizontal fading edges. 3856 * 3857 * @param length The size in pixels of the faded edge used to indicate that more 3858 * content in this view is visible. 3859 */ setFadingEdgeLength(int length)3860 public void setFadingEdgeLength(int length) { 3861 initScrollCache(); 3862 mScrollCache.fadingEdgeLength = length; 3863 } 3864 3865 /** 3866 * Returns the size of the horizontal faded edges used to indicate that more 3867 * content in this view is visible. 3868 * 3869 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 3870 * faded edges are not enabled for this view. 3871 * @attr ref android.R.styleable#View_fadingEdgeLength 3872 */ getHorizontalFadingEdgeLength()3873 public int getHorizontalFadingEdgeLength() { 3874 if (isHorizontalFadingEdgeEnabled()) { 3875 ScrollabilityCache cache = mScrollCache; 3876 if (cache != null) { 3877 return cache.fadingEdgeLength; 3878 } 3879 } 3880 return 0; 3881 } 3882 3883 /** 3884 * Returns the width of the vertical scrollbar. 3885 * 3886 * @return The width in pixels of the vertical scrollbar or 0 if there 3887 * is no vertical scrollbar. 3888 */ getVerticalScrollbarWidth()3889 public int getVerticalScrollbarWidth() { 3890 ScrollabilityCache cache = mScrollCache; 3891 if (cache != null) { 3892 ScrollBarDrawable scrollBar = cache.scrollBar; 3893 if (scrollBar != null) { 3894 int size = scrollBar.getSize(true); 3895 if (size <= 0) { 3896 size = cache.scrollBarSize; 3897 } 3898 return size; 3899 } 3900 return 0; 3901 } 3902 return 0; 3903 } 3904 3905 /** 3906 * Returns the height of the horizontal scrollbar. 3907 * 3908 * @return The height in pixels of the horizontal scrollbar or 0 if 3909 * there is no horizontal scrollbar. 3910 */ getHorizontalScrollbarHeight()3911 protected int getHorizontalScrollbarHeight() { 3912 ScrollabilityCache cache = mScrollCache; 3913 if (cache != null) { 3914 ScrollBarDrawable scrollBar = cache.scrollBar; 3915 if (scrollBar != null) { 3916 int size = scrollBar.getSize(false); 3917 if (size <= 0) { 3918 size = cache.scrollBarSize; 3919 } 3920 return size; 3921 } 3922 return 0; 3923 } 3924 return 0; 3925 } 3926 3927 /** 3928 * <p> 3929 * Initializes the scrollbars from a given set of styled attributes. This 3930 * method should be called by subclasses that need scrollbars and when an 3931 * instance of these subclasses is created programmatically rather than 3932 * being inflated from XML. This method is automatically called when the XML 3933 * is inflated. 3934 * </p> 3935 * 3936 * @param a the styled attributes set to initialize the scrollbars from 3937 */ initializeScrollbars(TypedArray a)3938 protected void initializeScrollbars(TypedArray a) { 3939 initScrollCache(); 3940 3941 final ScrollabilityCache scrollabilityCache = mScrollCache; 3942 3943 if (scrollabilityCache.scrollBar == null) { 3944 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 3945 } 3946 3947 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 3948 3949 if (!fadeScrollbars) { 3950 scrollabilityCache.state = ScrollabilityCache.ON; 3951 } 3952 scrollabilityCache.fadeScrollBars = fadeScrollbars; 3953 3954 3955 scrollabilityCache.scrollBarFadeDuration = a.getInt( 3956 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 3957 .getScrollBarFadeDuration()); 3958 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 3959 R.styleable.View_scrollbarDefaultDelayBeforeFade, 3960 ViewConfiguration.getScrollDefaultDelay()); 3961 3962 3963 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 3964 com.android.internal.R.styleable.View_scrollbarSize, 3965 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 3966 3967 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 3968 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 3969 3970 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 3971 if (thumb != null) { 3972 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 3973 } 3974 3975 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 3976 false); 3977 if (alwaysDraw) { 3978 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 3979 } 3980 3981 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 3982 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 3983 3984 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 3985 if (thumb != null) { 3986 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 3987 } 3988 3989 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 3990 false); 3991 if (alwaysDraw) { 3992 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 3993 } 3994 3995 // Apply layout direction to the new Drawables if needed 3996 final int layoutDirection = getLayoutDirection(); 3997 if (track != null) { 3998 track.setLayoutDirection(layoutDirection); 3999 } 4000 if (thumb != null) { 4001 thumb.setLayoutDirection(layoutDirection); 4002 } 4003 4004 // Re-apply user/background padding so that scrollbar(s) get added 4005 resolvePadding(); 4006 } 4007 4008 /** 4009 * <p> 4010 * Initalizes the scrollability cache if necessary. 4011 * </p> 4012 */ initScrollCache()4013 private void initScrollCache() { 4014 if (mScrollCache == null) { 4015 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 4016 } 4017 } 4018 getScrollCache()4019 private ScrollabilityCache getScrollCache() { 4020 initScrollCache(); 4021 return mScrollCache; 4022 } 4023 4024 /** 4025 * Set the position of the vertical scroll bar. Should be one of 4026 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 4027 * {@link #SCROLLBAR_POSITION_RIGHT}. 4028 * 4029 * @param position Where the vertical scroll bar should be positioned. 4030 */ setVerticalScrollbarPosition(int position)4031 public void setVerticalScrollbarPosition(int position) { 4032 if (mVerticalScrollbarPosition != position) { 4033 mVerticalScrollbarPosition = position; 4034 computeOpaqueFlags(); 4035 resolvePadding(); 4036 } 4037 } 4038 4039 /** 4040 * @return The position where the vertical scroll bar will show, if applicable. 4041 * @see #setVerticalScrollbarPosition(int) 4042 */ getVerticalScrollbarPosition()4043 public int getVerticalScrollbarPosition() { 4044 return mVerticalScrollbarPosition; 4045 } 4046 getListenerInfo()4047 ListenerInfo getListenerInfo() { 4048 if (mListenerInfo != null) { 4049 return mListenerInfo; 4050 } 4051 mListenerInfo = new ListenerInfo(); 4052 return mListenerInfo; 4053 } 4054 4055 /** 4056 * Register a callback to be invoked when focus of this view changed. 4057 * 4058 * @param l The callback that will run. 4059 */ setOnFocusChangeListener(OnFocusChangeListener l)4060 public void setOnFocusChangeListener(OnFocusChangeListener l) { 4061 getListenerInfo().mOnFocusChangeListener = l; 4062 } 4063 4064 /** 4065 * Add a listener that will be called when the bounds of the view change due to 4066 * layout processing. 4067 * 4068 * @param listener The listener that will be called when layout bounds change. 4069 */ addOnLayoutChangeListener(OnLayoutChangeListener listener)4070 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 4071 ListenerInfo li = getListenerInfo(); 4072 if (li.mOnLayoutChangeListeners == null) { 4073 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 4074 } 4075 if (!li.mOnLayoutChangeListeners.contains(listener)) { 4076 li.mOnLayoutChangeListeners.add(listener); 4077 } 4078 } 4079 4080 /** 4081 * Remove a listener for layout changes. 4082 * 4083 * @param listener The listener for layout bounds change. 4084 */ removeOnLayoutChangeListener(OnLayoutChangeListener listener)4085 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 4086 ListenerInfo li = mListenerInfo; 4087 if (li == null || li.mOnLayoutChangeListeners == null) { 4088 return; 4089 } 4090 li.mOnLayoutChangeListeners.remove(listener); 4091 } 4092 4093 /** 4094 * Add a listener for attach state changes. 4095 * 4096 * This listener will be called whenever this view is attached or detached 4097 * from a window. Remove the listener using 4098 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 4099 * 4100 * @param listener Listener to attach 4101 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 4102 */ addOnAttachStateChangeListener(OnAttachStateChangeListener listener)4103 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 4104 ListenerInfo li = getListenerInfo(); 4105 if (li.mOnAttachStateChangeListeners == null) { 4106 li.mOnAttachStateChangeListeners 4107 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 4108 } 4109 li.mOnAttachStateChangeListeners.add(listener); 4110 } 4111 4112 /** 4113 * Remove a listener for attach state changes. The listener will receive no further 4114 * notification of window attach/detach events. 4115 * 4116 * @param listener Listener to remove 4117 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 4118 */ removeOnAttachStateChangeListener(OnAttachStateChangeListener listener)4119 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 4120 ListenerInfo li = mListenerInfo; 4121 if (li == null || li.mOnAttachStateChangeListeners == null) { 4122 return; 4123 } 4124 li.mOnAttachStateChangeListeners.remove(listener); 4125 } 4126 4127 /** 4128 * Returns the focus-change callback registered for this view. 4129 * 4130 * @return The callback, or null if one is not registered. 4131 */ getOnFocusChangeListener()4132 public OnFocusChangeListener getOnFocusChangeListener() { 4133 ListenerInfo li = mListenerInfo; 4134 return li != null ? li.mOnFocusChangeListener : null; 4135 } 4136 4137 /** 4138 * Register a callback to be invoked when this view is clicked. If this view is not 4139 * clickable, it becomes clickable. 4140 * 4141 * @param l The callback that will run 4142 * 4143 * @see #setClickable(boolean) 4144 */ setOnClickListener(OnClickListener l)4145 public void setOnClickListener(OnClickListener l) { 4146 if (!isClickable()) { 4147 setClickable(true); 4148 } 4149 getListenerInfo().mOnClickListener = l; 4150 } 4151 4152 /** 4153 * Return whether this view has an attached OnClickListener. Returns 4154 * true if there is a listener, false if there is none. 4155 */ hasOnClickListeners()4156 public boolean hasOnClickListeners() { 4157 ListenerInfo li = mListenerInfo; 4158 return (li != null && li.mOnClickListener != null); 4159 } 4160 4161 /** 4162 * Register a callback to be invoked when this view is clicked and held. If this view is not 4163 * long clickable, it becomes long clickable. 4164 * 4165 * @param l The callback that will run 4166 * 4167 * @see #setLongClickable(boolean) 4168 */ setOnLongClickListener(OnLongClickListener l)4169 public void setOnLongClickListener(OnLongClickListener l) { 4170 if (!isLongClickable()) { 4171 setLongClickable(true); 4172 } 4173 getListenerInfo().mOnLongClickListener = l; 4174 } 4175 4176 /** 4177 * Register a callback to be invoked when the context menu for this view is 4178 * being built. If this view is not long clickable, it becomes long clickable. 4179 * 4180 * @param l The callback that will run 4181 * 4182 */ setOnCreateContextMenuListener(OnCreateContextMenuListener l)4183 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 4184 if (!isLongClickable()) { 4185 setLongClickable(true); 4186 } 4187 getListenerInfo().mOnCreateContextMenuListener = l; 4188 } 4189 4190 /** 4191 * Call this view's OnClickListener, if it is defined. Performs all normal 4192 * actions associated with clicking: reporting accessibility event, playing 4193 * a sound, etc. 4194 * 4195 * @return True there was an assigned OnClickListener that was called, false 4196 * otherwise is returned. 4197 */ performClick()4198 public boolean performClick() { 4199 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 4200 4201 ListenerInfo li = mListenerInfo; 4202 if (li != null && li.mOnClickListener != null) { 4203 playSoundEffect(SoundEffectConstants.CLICK); 4204 li.mOnClickListener.onClick(this); 4205 return true; 4206 } 4207 4208 return false; 4209 } 4210 4211 /** 4212 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 4213 * this only calls the listener, and does not do any associated clicking 4214 * actions like reporting an accessibility event. 4215 * 4216 * @return True there was an assigned OnClickListener that was called, false 4217 * otherwise is returned. 4218 */ callOnClick()4219 public boolean callOnClick() { 4220 ListenerInfo li = mListenerInfo; 4221 if (li != null && li.mOnClickListener != null) { 4222 li.mOnClickListener.onClick(this); 4223 return true; 4224 } 4225 return false; 4226 } 4227 4228 /** 4229 * Call this view's OnLongClickListener, if it is defined. Invokes the context menu if the 4230 * OnLongClickListener did not consume the event. 4231 * 4232 * @return True if one of the above receivers consumed the event, false otherwise. 4233 */ performLongClick()4234 public boolean performLongClick() { 4235 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 4236 4237 boolean handled = false; 4238 ListenerInfo li = mListenerInfo; 4239 if (li != null && li.mOnLongClickListener != null) { 4240 handled = li.mOnLongClickListener.onLongClick(View.this); 4241 } 4242 if (!handled) { 4243 handled = showContextMenu(); 4244 } 4245 if (handled) { 4246 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 4247 } 4248 return handled; 4249 } 4250 4251 /** 4252 * Performs button-related actions during a touch down event. 4253 * 4254 * @param event The event. 4255 * @return True if the down was consumed. 4256 * 4257 * @hide 4258 */ performButtonActionOnTouchDown(MotionEvent event)4259 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 4260 if ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 4261 if (showContextMenu(event.getX(), event.getY(), event.getMetaState())) { 4262 return true; 4263 } 4264 } 4265 return false; 4266 } 4267 4268 /** 4269 * Bring up the context menu for this view. 4270 * 4271 * @return Whether a context menu was displayed. 4272 */ showContextMenu()4273 public boolean showContextMenu() { 4274 return getParent().showContextMenuForChild(this); 4275 } 4276 4277 /** 4278 * Bring up the context menu for this view, referring to the item under the specified point. 4279 * 4280 * @param x The referenced x coordinate. 4281 * @param y The referenced y coordinate. 4282 * @param metaState The keyboard modifiers that were pressed. 4283 * @return Whether a context menu was displayed. 4284 * 4285 * @hide 4286 */ showContextMenu(float x, float y, int metaState)4287 public boolean showContextMenu(float x, float y, int metaState) { 4288 return showContextMenu(); 4289 } 4290 4291 /** 4292 * Start an action mode. 4293 * 4294 * @param callback Callback that will control the lifecycle of the action mode 4295 * @return The new action mode if it is started, null otherwise 4296 * 4297 * @see ActionMode 4298 */ startActionMode(ActionMode.Callback callback)4299 public ActionMode startActionMode(ActionMode.Callback callback) { 4300 ViewParent parent = getParent(); 4301 if (parent == null) return null; 4302 return parent.startActionModeForChild(this, callback); 4303 } 4304 4305 /** 4306 * Register a callback to be invoked when a hardware key is pressed in this view. 4307 * Key presses in software input methods will generally not trigger the methods of 4308 * this listener. 4309 * @param l the key listener to attach to this view 4310 */ setOnKeyListener(OnKeyListener l)4311 public void setOnKeyListener(OnKeyListener l) { 4312 getListenerInfo().mOnKeyListener = l; 4313 } 4314 4315 /** 4316 * Register a callback to be invoked when a touch event is sent to this view. 4317 * @param l the touch listener to attach to this view 4318 */ setOnTouchListener(OnTouchListener l)4319 public void setOnTouchListener(OnTouchListener l) { 4320 getListenerInfo().mOnTouchListener = l; 4321 } 4322 4323 /** 4324 * Register a callback to be invoked when a generic motion event is sent to this view. 4325 * @param l the generic motion listener to attach to this view 4326 */ setOnGenericMotionListener(OnGenericMotionListener l)4327 public void setOnGenericMotionListener(OnGenericMotionListener l) { 4328 getListenerInfo().mOnGenericMotionListener = l; 4329 } 4330 4331 /** 4332 * Register a callback to be invoked when a hover event is sent to this view. 4333 * @param l the hover listener to attach to this view 4334 */ setOnHoverListener(OnHoverListener l)4335 public void setOnHoverListener(OnHoverListener l) { 4336 getListenerInfo().mOnHoverListener = l; 4337 } 4338 4339 /** 4340 * Register a drag event listener callback object for this View. The parameter is 4341 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 4342 * View, the system calls the 4343 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 4344 * @param l An implementation of {@link android.view.View.OnDragListener}. 4345 */ setOnDragListener(OnDragListener l)4346 public void setOnDragListener(OnDragListener l) { 4347 getListenerInfo().mOnDragListener = l; 4348 } 4349 4350 /** 4351 * Give this view focus. This will cause 4352 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 4353 * 4354 * Note: this does not check whether this {@link View} should get focus, it just 4355 * gives it focus no matter what. It should only be called internally by framework 4356 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 4357 * 4358 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 4359 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 4360 * focus moved when requestFocus() is called. It may not always 4361 * apply, in which case use the default View.FOCUS_DOWN. 4362 * @param previouslyFocusedRect The rectangle of the view that had focus 4363 * prior in this View's coordinate system. 4364 */ handleFocusGainInternal(int direction, Rect previouslyFocusedRect)4365 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) { 4366 if (DBG) { 4367 System.out.println(this + " requestFocus()"); 4368 } 4369 4370 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 4371 mPrivateFlags |= PFLAG_FOCUSED; 4372 4373 if (mParent != null) { 4374 mParent.requestChildFocus(this, this); 4375 } 4376 4377 onFocusChanged(true, direction, previouslyFocusedRect); 4378 refreshDrawableState(); 4379 4380 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 4381 notifyAccessibilityStateChanged(); 4382 } 4383 } 4384 } 4385 4386 /** 4387 * Request that a rectangle of this view be visible on the screen, 4388 * scrolling if necessary just enough. 4389 * 4390 * <p>A View should call this if it maintains some notion of which part 4391 * of its content is interesting. For example, a text editing view 4392 * should call this when its cursor moves. 4393 * 4394 * @param rectangle The rectangle. 4395 * @return Whether any parent scrolled. 4396 */ requestRectangleOnScreen(Rect rectangle)4397 public boolean requestRectangleOnScreen(Rect rectangle) { 4398 return requestRectangleOnScreen(rectangle, false); 4399 } 4400 4401 /** 4402 * Request that a rectangle of this view be visible on the screen, 4403 * scrolling if necessary just enough. 4404 * 4405 * <p>A View should call this if it maintains some notion of which part 4406 * of its content is interesting. For example, a text editing view 4407 * should call this when its cursor moves. 4408 * 4409 * <p>When <code>immediate</code> is set to true, scrolling will not be 4410 * animated. 4411 * 4412 * @param rectangle The rectangle. 4413 * @param immediate True to forbid animated scrolling, false otherwise 4414 * @return Whether any parent scrolled. 4415 */ requestRectangleOnScreen(Rect rectangle, boolean immediate)4416 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 4417 if (mParent == null) { 4418 return false; 4419 } 4420 4421 View child = this; 4422 4423 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 4424 position.set(rectangle); 4425 4426 ViewParent parent = mParent; 4427 boolean scrolled = false; 4428 while (parent != null) { 4429 rectangle.set((int) position.left, (int) position.top, 4430 (int) position.right, (int) position.bottom); 4431 4432 scrolled |= parent.requestChildRectangleOnScreen(child, 4433 rectangle, immediate); 4434 4435 if (!child.hasIdentityMatrix()) { 4436 child.getMatrix().mapRect(position); 4437 } 4438 4439 position.offset(child.mLeft, child.mTop); 4440 4441 if (!(parent instanceof View)) { 4442 break; 4443 } 4444 4445 View parentView = (View) parent; 4446 4447 position.offset(-parentView.getScrollX(), -parentView.getScrollY()); 4448 4449 child = parentView; 4450 parent = child.getParent(); 4451 } 4452 4453 return scrolled; 4454 } 4455 4456 /** 4457 * Called when this view wants to give up focus. If focus is cleared 4458 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 4459 * <p> 4460 * <strong>Note:</strong> When a View clears focus the framework is trying 4461 * to give focus to the first focusable View from the top. Hence, if this 4462 * View is the first from the top that can take focus, then all callbacks 4463 * related to clearing focus will be invoked after wich the framework will 4464 * give focus to this view. 4465 * </p> 4466 */ clearFocus()4467 public void clearFocus() { 4468 if (DBG) { 4469 System.out.println(this + " clearFocus()"); 4470 } 4471 4472 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 4473 mPrivateFlags &= ~PFLAG_FOCUSED; 4474 4475 if (mParent != null) { 4476 mParent.clearChildFocus(this); 4477 } 4478 4479 onFocusChanged(false, 0, null); 4480 4481 refreshDrawableState(); 4482 4483 ensureInputFocusOnFirstFocusable(); 4484 4485 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 4486 notifyAccessibilityStateChanged(); 4487 } 4488 } 4489 } 4490 ensureInputFocusOnFirstFocusable()4491 void ensureInputFocusOnFirstFocusable() { 4492 View root = getRootView(); 4493 if (root != null) { 4494 root.requestFocus(); 4495 } 4496 } 4497 4498 /** 4499 * Called internally by the view system when a new view is getting focus. 4500 * This is what clears the old focus. 4501 */ unFocus()4502 void unFocus() { 4503 if (DBG) { 4504 System.out.println(this + " unFocus()"); 4505 } 4506 4507 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 4508 mPrivateFlags &= ~PFLAG_FOCUSED; 4509 4510 onFocusChanged(false, 0, null); 4511 refreshDrawableState(); 4512 4513 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 4514 notifyAccessibilityStateChanged(); 4515 } 4516 } 4517 } 4518 4519 /** 4520 * Returns true if this view has focus iteself, or is the ancestor of the 4521 * view that has focus. 4522 * 4523 * @return True if this view has or contains focus, false otherwise. 4524 */ 4525 @ViewDebug.ExportedProperty(category = "focus") hasFocus()4526 public boolean hasFocus() { 4527 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 4528 } 4529 4530 /** 4531 * Returns true if this view is focusable or if it contains a reachable View 4532 * for which {@link #hasFocusable()} returns true. A "reachable hasFocusable()" 4533 * is a View whose parents do not block descendants focus. 4534 * 4535 * Only {@link #VISIBLE} views are considered focusable. 4536 * 4537 * @return True if the view is focusable or if the view contains a focusable 4538 * View, false otherwise. 4539 * 4540 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 4541 */ hasFocusable()4542 public boolean hasFocusable() { 4543 return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable(); 4544 } 4545 4546 /** 4547 * Called by the view system when the focus state of this view changes. 4548 * When the focus change event is caused by directional navigation, direction 4549 * and previouslyFocusedRect provide insight into where the focus is coming from. 4550 * When overriding, be sure to call up through to the super class so that 4551 * the standard focus handling will occur. 4552 * 4553 * @param gainFocus True if the View has focus; false otherwise. 4554 * @param direction The direction focus has moved when requestFocus() 4555 * is called to give this view focus. Values are 4556 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 4557 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 4558 * It may not always apply, in which case use the default. 4559 * @param previouslyFocusedRect The rectangle, in this view's coordinate 4560 * system, of the previously focused view. If applicable, this will be 4561 * passed in as finer grained information about where the focus is coming 4562 * from (in addition to direction). Will be <code>null</code> otherwise. 4563 */ onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect)4564 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 4565 if (gainFocus) { 4566 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 4567 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 4568 } 4569 } 4570 4571 InputMethodManager imm = InputMethodManager.peekInstance(); 4572 if (!gainFocus) { 4573 if (isPressed()) { 4574 setPressed(false); 4575 } 4576 if (imm != null && mAttachInfo != null 4577 && mAttachInfo.mHasWindowFocus) { 4578 imm.focusOut(this); 4579 } 4580 onFocusLost(); 4581 } else if (imm != null && mAttachInfo != null 4582 && mAttachInfo.mHasWindowFocus) { 4583 imm.focusIn(this); 4584 } 4585 4586 invalidate(true); 4587 ListenerInfo li = mListenerInfo; 4588 if (li != null && li.mOnFocusChangeListener != null) { 4589 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 4590 } 4591 4592 if (mAttachInfo != null) { 4593 mAttachInfo.mKeyDispatchState.reset(this); 4594 } 4595 } 4596 4597 /** 4598 * Sends an accessibility event of the given type. If accessibility is 4599 * not enabled this method has no effect. The default implementation calls 4600 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 4601 * to populate information about the event source (this View), then calls 4602 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 4603 * populate the text content of the event source including its descendants, 4604 * and last calls 4605 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 4606 * on its parent to resuest sending of the event to interested parties. 4607 * <p> 4608 * If an {@link AccessibilityDelegate} has been specified via calling 4609 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 4610 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 4611 * responsible for handling this call. 4612 * </p> 4613 * 4614 * @param eventType The type of the event to send, as defined by several types from 4615 * {@link android.view.accessibility.AccessibilityEvent}, such as 4616 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 4617 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 4618 * 4619 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 4620 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 4621 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 4622 * @see AccessibilityDelegate 4623 */ sendAccessibilityEvent(int eventType)4624 public void sendAccessibilityEvent(int eventType) { 4625 if (mAccessibilityDelegate != null) { 4626 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 4627 } else { 4628 sendAccessibilityEventInternal(eventType); 4629 } 4630 } 4631 4632 /** 4633 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 4634 * {@link AccessibilityEvent} to make an announcement which is related to some 4635 * sort of a context change for which none of the events representing UI transitions 4636 * is a good fit. For example, announcing a new page in a book. If accessibility 4637 * is not enabled this method does nothing. 4638 * 4639 * @param text The announcement text. 4640 */ announceForAccessibility(CharSequence text)4641 public void announceForAccessibility(CharSequence text) { 4642 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 4643 AccessibilityEvent event = AccessibilityEvent.obtain( 4644 AccessibilityEvent.TYPE_ANNOUNCEMENT); 4645 onInitializeAccessibilityEvent(event); 4646 event.getText().add(text); 4647 event.setContentDescription(null); 4648 mParent.requestSendAccessibilityEvent(this, event); 4649 } 4650 } 4651 4652 /** 4653 * @see #sendAccessibilityEvent(int) 4654 * 4655 * Note: Called from the default {@link AccessibilityDelegate}. 4656 */ sendAccessibilityEventInternal(int eventType)4657 void sendAccessibilityEventInternal(int eventType) { 4658 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 4659 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 4660 } 4661 } 4662 4663 /** 4664 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 4665 * takes as an argument an empty {@link AccessibilityEvent} and does not 4666 * perform a check whether accessibility is enabled. 4667 * <p> 4668 * If an {@link AccessibilityDelegate} has been specified via calling 4669 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 4670 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 4671 * is responsible for handling this call. 4672 * </p> 4673 * 4674 * @param event The event to send. 4675 * 4676 * @see #sendAccessibilityEvent(int) 4677 */ sendAccessibilityEventUnchecked(AccessibilityEvent event)4678 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 4679 if (mAccessibilityDelegate != null) { 4680 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 4681 } else { 4682 sendAccessibilityEventUncheckedInternal(event); 4683 } 4684 } 4685 4686 /** 4687 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 4688 * 4689 * Note: Called from the default {@link AccessibilityDelegate}. 4690 */ sendAccessibilityEventUncheckedInternal(AccessibilityEvent event)4691 void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 4692 if (!isShown()) { 4693 return; 4694 } 4695 onInitializeAccessibilityEvent(event); 4696 // Only a subset of accessibility events populates text content. 4697 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 4698 dispatchPopulateAccessibilityEvent(event); 4699 } 4700 // In the beginning we called #isShown(), so we know that getParent() is not null. 4701 getParent().requestSendAccessibilityEvent(this, event); 4702 } 4703 4704 /** 4705 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 4706 * to its children for adding their text content to the event. Note that the 4707 * event text is populated in a separate dispatch path since we add to the 4708 * event not only the text of the source but also the text of all its descendants. 4709 * A typical implementation will call 4710 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 4711 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 4712 * on each child. Override this method if custom population of the event text 4713 * content is required. 4714 * <p> 4715 * If an {@link AccessibilityDelegate} has been specified via calling 4716 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 4717 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 4718 * is responsible for handling this call. 4719 * </p> 4720 * <p> 4721 * <em>Note:</em> Accessibility events of certain types are not dispatched for 4722 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 4723 * </p> 4724 * 4725 * @param event The event. 4726 * 4727 * @return True if the event population was completed. 4728 */ dispatchPopulateAccessibilityEvent(AccessibilityEvent event)4729 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 4730 if (mAccessibilityDelegate != null) { 4731 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 4732 } else { 4733 return dispatchPopulateAccessibilityEventInternal(event); 4734 } 4735 } 4736 4737 /** 4738 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 4739 * 4740 * Note: Called from the default {@link AccessibilityDelegate}. 4741 */ dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event)4742 boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 4743 onPopulateAccessibilityEvent(event); 4744 return false; 4745 } 4746 4747 /** 4748 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 4749 * giving a chance to this View to populate the accessibility event with its 4750 * text content. While this method is free to modify event 4751 * attributes other than text content, doing so should normally be performed in 4752 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 4753 * <p> 4754 * Example: Adding formatted date string to an accessibility event in addition 4755 * to the text added by the super implementation: 4756 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 4757 * super.onPopulateAccessibilityEvent(event); 4758 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 4759 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 4760 * mCurrentDate.getTimeInMillis(), flags); 4761 * event.getText().add(selectedDateUtterance); 4762 * }</pre> 4763 * <p> 4764 * If an {@link AccessibilityDelegate} has been specified via calling 4765 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 4766 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 4767 * is responsible for handling this call. 4768 * </p> 4769 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 4770 * information to the event, in case the default implementation has basic information to add. 4771 * </p> 4772 * 4773 * @param event The accessibility event which to populate. 4774 * 4775 * @see #sendAccessibilityEvent(int) 4776 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 4777 */ onPopulateAccessibilityEvent(AccessibilityEvent event)4778 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 4779 if (mAccessibilityDelegate != null) { 4780 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 4781 } else { 4782 onPopulateAccessibilityEventInternal(event); 4783 } 4784 } 4785 4786 /** 4787 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 4788 * 4789 * Note: Called from the default {@link AccessibilityDelegate}. 4790 */ onPopulateAccessibilityEventInternal(AccessibilityEvent event)4791 void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 4792 4793 } 4794 4795 /** 4796 * Initializes an {@link AccessibilityEvent} with information about 4797 * this View which is the event source. In other words, the source of 4798 * an accessibility event is the view whose state change triggered firing 4799 * the event. 4800 * <p> 4801 * Example: Setting the password property of an event in addition 4802 * to properties set by the super implementation: 4803 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 4804 * super.onInitializeAccessibilityEvent(event); 4805 * event.setPassword(true); 4806 * }</pre> 4807 * <p> 4808 * If an {@link AccessibilityDelegate} has been specified via calling 4809 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 4810 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 4811 * is responsible for handling this call. 4812 * </p> 4813 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 4814 * information to the event, in case the default implementation has basic information to add. 4815 * </p> 4816 * @param event The event to initialize. 4817 * 4818 * @see #sendAccessibilityEvent(int) 4819 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 4820 */ onInitializeAccessibilityEvent(AccessibilityEvent event)4821 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 4822 if (mAccessibilityDelegate != null) { 4823 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 4824 } else { 4825 onInitializeAccessibilityEventInternal(event); 4826 } 4827 } 4828 4829 /** 4830 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 4831 * 4832 * Note: Called from the default {@link AccessibilityDelegate}. 4833 */ onInitializeAccessibilityEventInternal(AccessibilityEvent event)4834 void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 4835 event.setSource(this); 4836 event.setClassName(View.class.getName()); 4837 event.setPackageName(getContext().getPackageName()); 4838 event.setEnabled(isEnabled()); 4839 event.setContentDescription(mContentDescription); 4840 4841 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && mAttachInfo != null) { 4842 ArrayList<View> focusablesTempList = mAttachInfo.mTempArrayList; 4843 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, 4844 FOCUSABLES_ALL); 4845 event.setItemCount(focusablesTempList.size()); 4846 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 4847 focusablesTempList.clear(); 4848 } 4849 } 4850 4851 /** 4852 * Returns an {@link AccessibilityNodeInfo} representing this view from the 4853 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 4854 * This method is responsible for obtaining an accessibility node info from a 4855 * pool of reusable instances and calling 4856 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 4857 * initialize the former. 4858 * <p> 4859 * Note: The client is responsible for recycling the obtained instance by calling 4860 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 4861 * </p> 4862 * 4863 * @return A populated {@link AccessibilityNodeInfo}. 4864 * 4865 * @see AccessibilityNodeInfo 4866 */ createAccessibilityNodeInfo()4867 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 4868 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 4869 if (provider != null) { 4870 return provider.createAccessibilityNodeInfo(View.NO_ID); 4871 } else { 4872 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 4873 onInitializeAccessibilityNodeInfo(info); 4874 return info; 4875 } 4876 } 4877 4878 /** 4879 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 4880 * The base implementation sets: 4881 * <ul> 4882 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 4883 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 4884 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 4885 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 4886 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 4887 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 4888 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 4889 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 4890 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 4891 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 4892 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 4893 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 4894 * </ul> 4895 * <p> 4896 * Subclasses should override this method, call the super implementation, 4897 * and set additional attributes. 4898 * </p> 4899 * <p> 4900 * If an {@link AccessibilityDelegate} has been specified via calling 4901 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 4902 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 4903 * is responsible for handling this call. 4904 * </p> 4905 * 4906 * @param info The instance to initialize. 4907 */ onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info)4908 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 4909 if (mAccessibilityDelegate != null) { 4910 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 4911 } else { 4912 onInitializeAccessibilityNodeInfoInternal(info); 4913 } 4914 } 4915 4916 /** 4917 * Gets the location of this view in screen coordintates. 4918 * 4919 * @param outRect The output location 4920 */ getBoundsOnScreen(Rect outRect)4921 void getBoundsOnScreen(Rect outRect) { 4922 if (mAttachInfo == null) { 4923 return; 4924 } 4925 4926 RectF position = mAttachInfo.mTmpTransformRect; 4927 position.set(0, 0, mRight - mLeft, mBottom - mTop); 4928 4929 if (!hasIdentityMatrix()) { 4930 getMatrix().mapRect(position); 4931 } 4932 4933 position.offset(mLeft, mTop); 4934 4935 ViewParent parent = mParent; 4936 while (parent instanceof View) { 4937 View parentView = (View) parent; 4938 4939 position.offset(-parentView.mScrollX, -parentView.mScrollY); 4940 4941 if (!parentView.hasIdentityMatrix()) { 4942 parentView.getMatrix().mapRect(position); 4943 } 4944 4945 position.offset(parentView.mLeft, parentView.mTop); 4946 4947 parent = parentView.mParent; 4948 } 4949 4950 if (parent instanceof ViewRootImpl) { 4951 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 4952 position.offset(0, -viewRootImpl.mCurScrollY); 4953 } 4954 4955 position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 4956 4957 outRect.set((int) (position.left + 0.5f), (int) (position.top + 0.5f), 4958 (int) (position.right + 0.5f), (int) (position.bottom + 0.5f)); 4959 } 4960 4961 /** 4962 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 4963 * 4964 * Note: Called from the default {@link AccessibilityDelegate}. 4965 */ onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info)4966 void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 4967 Rect bounds = mAttachInfo.mTmpInvalRect; 4968 4969 getDrawingRect(bounds); 4970 info.setBoundsInParent(bounds); 4971 4972 getBoundsOnScreen(bounds); 4973 info.setBoundsInScreen(bounds); 4974 4975 ViewParent parent = getParentForAccessibility(); 4976 if (parent instanceof View) { 4977 info.setParent((View) parent); 4978 } 4979 4980 if (mID != View.NO_ID) { 4981 View rootView = getRootView(); 4982 if (rootView == null) { 4983 rootView = this; 4984 } 4985 View label = rootView.findLabelForView(this, mID); 4986 if (label != null) { 4987 info.setLabeledBy(label); 4988 } 4989 } 4990 4991 if (mLabelForId != View.NO_ID) { 4992 View rootView = getRootView(); 4993 if (rootView == null) { 4994 rootView = this; 4995 } 4996 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 4997 if (labeled != null) { 4998 info.setLabelFor(labeled); 4999 } 5000 } 5001 5002 info.setVisibleToUser(isVisibleToUser()); 5003 5004 info.setPackageName(mContext.getPackageName()); 5005 info.setClassName(View.class.getName()); 5006 info.setContentDescription(getContentDescription()); 5007 5008 info.setEnabled(isEnabled()); 5009 info.setClickable(isClickable()); 5010 info.setFocusable(isFocusable()); 5011 info.setFocused(isFocused()); 5012 info.setAccessibilityFocused(isAccessibilityFocused()); 5013 info.setSelected(isSelected()); 5014 info.setLongClickable(isLongClickable()); 5015 5016 // TODO: These make sense only if we are in an AdapterView but all 5017 // views can be selected. Maybe from accessibility perspective 5018 // we should report as selectable view in an AdapterView. 5019 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 5020 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 5021 5022 if (isFocusable()) { 5023 if (isFocused()) { 5024 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 5025 } else { 5026 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 5027 } 5028 } 5029 5030 if (!isAccessibilityFocused()) { 5031 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 5032 } else { 5033 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 5034 } 5035 5036 if (isClickable() && isEnabled()) { 5037 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 5038 } 5039 5040 if (isLongClickable() && isEnabled()) { 5041 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 5042 } 5043 5044 if (mContentDescription != null && mContentDescription.length() > 0) { 5045 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 5046 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 5047 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 5048 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 5049 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 5050 } 5051 } 5052 findLabelForView(View view, int labeledId)5053 private View findLabelForView(View view, int labeledId) { 5054 if (mMatchLabelForPredicate == null) { 5055 mMatchLabelForPredicate = new MatchLabelForPredicate(); 5056 } 5057 mMatchLabelForPredicate.mLabeledId = labeledId; 5058 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 5059 } 5060 5061 /** 5062 * Computes whether this view is visible to the user. Such a view is 5063 * attached, visible, all its predecessors are visible, it is not clipped 5064 * entirely by its predecessors, and has an alpha greater than zero. 5065 * 5066 * @return Whether the view is visible on the screen. 5067 * 5068 * @hide 5069 */ isVisibleToUser()5070 protected boolean isVisibleToUser() { 5071 return isVisibleToUser(null); 5072 } 5073 5074 /** 5075 * Computes whether the given portion of this view is visible to the user. 5076 * Such a view is attached, visible, all its predecessors are visible, 5077 * has an alpha greater than zero, and the specified portion is not 5078 * clipped entirely by its predecessors. 5079 * 5080 * @param boundInView the portion of the view to test; coordinates should be relative; may be 5081 * <code>null</code>, and the entire view will be tested in this case. 5082 * When <code>true</code> is returned by the function, the actual visible 5083 * region will be stored in this parameter; that is, if boundInView is fully 5084 * contained within the view, no modification will be made, otherwise regions 5085 * outside of the visible area of the view will be clipped. 5086 * 5087 * @return Whether the specified portion of the view is visible on the screen. 5088 * 5089 * @hide 5090 */ isVisibleToUser(Rect boundInView)5091 protected boolean isVisibleToUser(Rect boundInView) { 5092 if (mAttachInfo != null) { 5093 // Attached to invisible window means this view is not visible. 5094 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 5095 return false; 5096 } 5097 // An invisible predecessor or one with alpha zero means 5098 // that this view is not visible to the user. 5099 Object current = this; 5100 while (current instanceof View) { 5101 View view = (View) current; 5102 // We have attach info so this view is attached and there is no 5103 // need to check whether we reach to ViewRootImpl on the way up. 5104 if (view.getAlpha() <= 0 || view.getVisibility() != VISIBLE) { 5105 return false; 5106 } 5107 current = view.mParent; 5108 } 5109 // Check if the view is entirely covered by its predecessors. 5110 Rect visibleRect = mAttachInfo.mTmpInvalRect; 5111 Point offset = mAttachInfo.mPoint; 5112 if (!getGlobalVisibleRect(visibleRect, offset)) { 5113 return false; 5114 } 5115 // Check if the visible portion intersects the rectangle of interest. 5116 if (boundInView != null) { 5117 visibleRect.offset(-offset.x, -offset.y); 5118 return boundInView.intersect(visibleRect); 5119 } 5120 return true; 5121 } 5122 return false; 5123 } 5124 5125 /** 5126 * Returns the delegate for implementing accessibility support via 5127 * composition. For more details see {@link AccessibilityDelegate}. 5128 * 5129 * @return The delegate, or null if none set. 5130 * 5131 * @hide 5132 */ getAccessibilityDelegate()5133 public AccessibilityDelegate getAccessibilityDelegate() { 5134 return mAccessibilityDelegate; 5135 } 5136 5137 /** 5138 * Sets a delegate for implementing accessibility support via composition as 5139 * opposed to inheritance. The delegate's primary use is for implementing 5140 * backwards compatible widgets. For more details see {@link AccessibilityDelegate}. 5141 * 5142 * @param delegate The delegate instance. 5143 * 5144 * @see AccessibilityDelegate 5145 */ setAccessibilityDelegate(AccessibilityDelegate delegate)5146 public void setAccessibilityDelegate(AccessibilityDelegate delegate) { 5147 mAccessibilityDelegate = delegate; 5148 } 5149 5150 /** 5151 * Gets the provider for managing a virtual view hierarchy rooted at this View 5152 * and reported to {@link android.accessibilityservice.AccessibilityService}s 5153 * that explore the window content. 5154 * <p> 5155 * If this method returns an instance, this instance is responsible for managing 5156 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 5157 * View including the one representing the View itself. Similarly the returned 5158 * instance is responsible for performing accessibility actions on any virtual 5159 * view or the root view itself. 5160 * </p> 5161 * <p> 5162 * If an {@link AccessibilityDelegate} has been specified via calling 5163 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 5164 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 5165 * is responsible for handling this call. 5166 * </p> 5167 * 5168 * @return The provider. 5169 * 5170 * @see AccessibilityNodeProvider 5171 */ getAccessibilityNodeProvider()5172 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 5173 if (mAccessibilityDelegate != null) { 5174 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 5175 } else { 5176 return null; 5177 } 5178 } 5179 5180 /** 5181 * Gets the unique identifier of this view on the screen for accessibility purposes. 5182 * If this {@link View} is not attached to any window, {@value #NO_ID} is returned. 5183 * 5184 * @return The view accessibility id. 5185 * 5186 * @hide 5187 */ getAccessibilityViewId()5188 public int getAccessibilityViewId() { 5189 if (mAccessibilityViewId == NO_ID) { 5190 mAccessibilityViewId = sNextAccessibilityViewId++; 5191 } 5192 return mAccessibilityViewId; 5193 } 5194 5195 /** 5196 * Gets the unique identifier of the window in which this View reseides. 5197 * 5198 * @return The window accessibility id. 5199 * 5200 * @hide 5201 */ getAccessibilityWindowId()5202 public int getAccessibilityWindowId() { 5203 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId : NO_ID; 5204 } 5205 5206 /** 5207 * Gets the {@link View} description. It briefly describes the view and is 5208 * primarily used for accessibility support. Set this property to enable 5209 * better accessibility support for your application. This is especially 5210 * true for views that do not have textual representation (For example, 5211 * ImageButton). 5212 * 5213 * @return The content description. 5214 * 5215 * @attr ref android.R.styleable#View_contentDescription 5216 */ 5217 @ViewDebug.ExportedProperty(category = "accessibility") getContentDescription()5218 public CharSequence getContentDescription() { 5219 return mContentDescription; 5220 } 5221 5222 /** 5223 * Sets the {@link View} description. It briefly describes the view and is 5224 * primarily used for accessibility support. Set this property to enable 5225 * better accessibility support for your application. This is especially 5226 * true for views that do not have textual representation (For example, 5227 * ImageButton). 5228 * 5229 * @param contentDescription The content description. 5230 * 5231 * @attr ref android.R.styleable#View_contentDescription 5232 */ 5233 @RemotableViewMethod setContentDescription(CharSequence contentDescription)5234 public void setContentDescription(CharSequence contentDescription) { 5235 if (mContentDescription == null) { 5236 if (contentDescription == null) { 5237 return; 5238 } 5239 } else if (mContentDescription.equals(contentDescription)) { 5240 return; 5241 } 5242 mContentDescription = contentDescription; 5243 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 5244 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 5245 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 5246 } 5247 notifyAccessibilityStateChanged(); 5248 } 5249 5250 /** 5251 * Gets the id of a view for which this view serves as a label for 5252 * accessibility purposes. 5253 * 5254 * @return The labeled view id. 5255 */ 5256 @ViewDebug.ExportedProperty(category = "accessibility") getLabelFor()5257 public int getLabelFor() { 5258 return mLabelForId; 5259 } 5260 5261 /** 5262 * Sets the id of a view for which this view serves as a label for 5263 * accessibility purposes. 5264 * 5265 * @param id The labeled view id. 5266 */ 5267 @RemotableViewMethod setLabelFor(int id)5268 public void setLabelFor(int id) { 5269 mLabelForId = id; 5270 if (mLabelForId != View.NO_ID 5271 && mID == View.NO_ID) { 5272 mID = generateViewId(); 5273 } 5274 } 5275 5276 /** 5277 * Invoked whenever this view loses focus, either by losing window focus or by losing 5278 * focus within its window. This method can be used to clear any state tied to the 5279 * focus. For instance, if a button is held pressed with the trackball and the window 5280 * loses focus, this method can be used to cancel the press. 5281 * 5282 * Subclasses of View overriding this method should always call super.onFocusLost(). 5283 * 5284 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 5285 * @see #onWindowFocusChanged(boolean) 5286 * 5287 * @hide pending API council approval 5288 */ onFocusLost()5289 protected void onFocusLost() { 5290 resetPressedState(); 5291 } 5292 resetPressedState()5293 private void resetPressedState() { 5294 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 5295 return; 5296 } 5297 5298 if (isPressed()) { 5299 setPressed(false); 5300 5301 if (!mHasPerformedLongPress) { 5302 removeLongPressCallback(); 5303 } 5304 } 5305 } 5306 5307 /** 5308 * Returns true if this view has focus 5309 * 5310 * @return True if this view has focus, false otherwise. 5311 */ 5312 @ViewDebug.ExportedProperty(category = "focus") isFocused()5313 public boolean isFocused() { 5314 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 5315 } 5316 5317 /** 5318 * Find the view in the hierarchy rooted at this view that currently has 5319 * focus. 5320 * 5321 * @return The view that currently has focus, or null if no focused view can 5322 * be found. 5323 */ findFocus()5324 public View findFocus() { 5325 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 5326 } 5327 5328 /** 5329 * Indicates whether this view is one of the set of scrollable containers in 5330 * its window. 5331 * 5332 * @return whether this view is one of the set of scrollable containers in 5333 * its window 5334 * 5335 * @attr ref android.R.styleable#View_isScrollContainer 5336 */ isScrollContainer()5337 public boolean isScrollContainer() { 5338 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 5339 } 5340 5341 /** 5342 * Change whether this view is one of the set of scrollable containers in 5343 * its window. This will be used to determine whether the window can 5344 * resize or must pan when a soft input area is open -- scrollable 5345 * containers allow the window to use resize mode since the container 5346 * will appropriately shrink. 5347 * 5348 * @attr ref android.R.styleable#View_isScrollContainer 5349 */ setScrollContainer(boolean isScrollContainer)5350 public void setScrollContainer(boolean isScrollContainer) { 5351 if (isScrollContainer) { 5352 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 5353 mAttachInfo.mScrollContainers.add(this); 5354 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 5355 } 5356 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 5357 } else { 5358 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 5359 mAttachInfo.mScrollContainers.remove(this); 5360 } 5361 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 5362 } 5363 } 5364 5365 /** 5366 * Returns the quality of the drawing cache. 5367 * 5368 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 5369 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 5370 * 5371 * @see #setDrawingCacheQuality(int) 5372 * @see #setDrawingCacheEnabled(boolean) 5373 * @see #isDrawingCacheEnabled() 5374 * 5375 * @attr ref android.R.styleable#View_drawingCacheQuality 5376 */ getDrawingCacheQuality()5377 public int getDrawingCacheQuality() { 5378 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 5379 } 5380 5381 /** 5382 * Set the drawing cache quality of this view. This value is used only when the 5383 * drawing cache is enabled 5384 * 5385 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 5386 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 5387 * 5388 * @see #getDrawingCacheQuality() 5389 * @see #setDrawingCacheEnabled(boolean) 5390 * @see #isDrawingCacheEnabled() 5391 * 5392 * @attr ref android.R.styleable#View_drawingCacheQuality 5393 */ setDrawingCacheQuality(int quality)5394 public void setDrawingCacheQuality(int quality) { 5395 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 5396 } 5397 5398 /** 5399 * Returns whether the screen should remain on, corresponding to the current 5400 * value of {@link #KEEP_SCREEN_ON}. 5401 * 5402 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 5403 * 5404 * @see #setKeepScreenOn(boolean) 5405 * 5406 * @attr ref android.R.styleable#View_keepScreenOn 5407 */ getKeepScreenOn()5408 public boolean getKeepScreenOn() { 5409 return (mViewFlags & KEEP_SCREEN_ON) != 0; 5410 } 5411 5412 /** 5413 * Controls whether the screen should remain on, modifying the 5414 * value of {@link #KEEP_SCREEN_ON}. 5415 * 5416 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 5417 * 5418 * @see #getKeepScreenOn() 5419 * 5420 * @attr ref android.R.styleable#View_keepScreenOn 5421 */ setKeepScreenOn(boolean keepScreenOn)5422 public void setKeepScreenOn(boolean keepScreenOn) { 5423 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 5424 } 5425 5426 /** 5427 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 5428 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 5429 * 5430 * @attr ref android.R.styleable#View_nextFocusLeft 5431 */ getNextFocusLeftId()5432 public int getNextFocusLeftId() { 5433 return mNextFocusLeftId; 5434 } 5435 5436 /** 5437 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 5438 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 5439 * decide automatically. 5440 * 5441 * @attr ref android.R.styleable#View_nextFocusLeft 5442 */ setNextFocusLeftId(int nextFocusLeftId)5443 public void setNextFocusLeftId(int nextFocusLeftId) { 5444 mNextFocusLeftId = nextFocusLeftId; 5445 } 5446 5447 /** 5448 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 5449 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 5450 * 5451 * @attr ref android.R.styleable#View_nextFocusRight 5452 */ getNextFocusRightId()5453 public int getNextFocusRightId() { 5454 return mNextFocusRightId; 5455 } 5456 5457 /** 5458 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 5459 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 5460 * decide automatically. 5461 * 5462 * @attr ref android.R.styleable#View_nextFocusRight 5463 */ setNextFocusRightId(int nextFocusRightId)5464 public void setNextFocusRightId(int nextFocusRightId) { 5465 mNextFocusRightId = nextFocusRightId; 5466 } 5467 5468 /** 5469 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 5470 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 5471 * 5472 * @attr ref android.R.styleable#View_nextFocusUp 5473 */ getNextFocusUpId()5474 public int getNextFocusUpId() { 5475 return mNextFocusUpId; 5476 } 5477 5478 /** 5479 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 5480 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 5481 * decide automatically. 5482 * 5483 * @attr ref android.R.styleable#View_nextFocusUp 5484 */ setNextFocusUpId(int nextFocusUpId)5485 public void setNextFocusUpId(int nextFocusUpId) { 5486 mNextFocusUpId = nextFocusUpId; 5487 } 5488 5489 /** 5490 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 5491 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 5492 * 5493 * @attr ref android.R.styleable#View_nextFocusDown 5494 */ getNextFocusDownId()5495 public int getNextFocusDownId() { 5496 return mNextFocusDownId; 5497 } 5498 5499 /** 5500 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 5501 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 5502 * decide automatically. 5503 * 5504 * @attr ref android.R.styleable#View_nextFocusDown 5505 */ setNextFocusDownId(int nextFocusDownId)5506 public void setNextFocusDownId(int nextFocusDownId) { 5507 mNextFocusDownId = nextFocusDownId; 5508 } 5509 5510 /** 5511 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 5512 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 5513 * 5514 * @attr ref android.R.styleable#View_nextFocusForward 5515 */ getNextFocusForwardId()5516 public int getNextFocusForwardId() { 5517 return mNextFocusForwardId; 5518 } 5519 5520 /** 5521 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 5522 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 5523 * decide automatically. 5524 * 5525 * @attr ref android.R.styleable#View_nextFocusForward 5526 */ setNextFocusForwardId(int nextFocusForwardId)5527 public void setNextFocusForwardId(int nextFocusForwardId) { 5528 mNextFocusForwardId = nextFocusForwardId; 5529 } 5530 5531 /** 5532 * Returns the visibility of this view and all of its ancestors 5533 * 5534 * @return True if this view and all of its ancestors are {@link #VISIBLE} 5535 */ isShown()5536 public boolean isShown() { 5537 View current = this; 5538 //noinspection ConstantConditions 5539 do { 5540 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 5541 return false; 5542 } 5543 ViewParent parent = current.mParent; 5544 if (parent == null) { 5545 return false; // We are not attached to the view root 5546 } 5547 if (!(parent instanceof View)) { 5548 return true; 5549 } 5550 current = (View) parent; 5551 } while (current != null); 5552 5553 return false; 5554 } 5555 5556 /** 5557 * Called by the view hierarchy when the content insets for a window have 5558 * changed, to allow it to adjust its content to fit within those windows. 5559 * The content insets tell you the space that the status bar, input method, 5560 * and other system windows infringe on the application's window. 5561 * 5562 * <p>You do not normally need to deal with this function, since the default 5563 * window decoration given to applications takes care of applying it to the 5564 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 5565 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 5566 * and your content can be placed under those system elements. You can then 5567 * use this method within your view hierarchy if you have parts of your UI 5568 * which you would like to ensure are not being covered. 5569 * 5570 * <p>The default implementation of this method simply applies the content 5571 * inset's to the view's padding, consuming that content (modifying the 5572 * insets to be 0), and returning true. This behavior is off by default, but can 5573 * be enabled through {@link #setFitsSystemWindows(boolean)}. 5574 * 5575 * <p>This function's traversal down the hierarchy is depth-first. The same content 5576 * insets object is propagated down the hierarchy, so any changes made to it will 5577 * be seen by all following views (including potentially ones above in 5578 * the hierarchy since this is a depth-first traversal). The first view 5579 * that returns true will abort the entire traversal. 5580 * 5581 * <p>The default implementation works well for a situation where it is 5582 * used with a container that covers the entire window, allowing it to 5583 * apply the appropriate insets to its content on all edges. If you need 5584 * a more complicated layout (such as two different views fitting system 5585 * windows, one on the top of the window, and one on the bottom), 5586 * you can override the method and handle the insets however you would like. 5587 * Note that the insets provided by the framework are always relative to the 5588 * far edges of the window, not accounting for the location of the called view 5589 * within that window. (In fact when this method is called you do not yet know 5590 * where the layout will place the view, as it is done before layout happens.) 5591 * 5592 * <p>Note: unlike many View methods, there is no dispatch phase to this 5593 * call. If you are overriding it in a ViewGroup and want to allow the 5594 * call to continue to your children, you must be sure to call the super 5595 * implementation. 5596 * 5597 * <p>Here is a sample layout that makes use of fitting system windows 5598 * to have controls for a video view placed inside of the window decorations 5599 * that it hides and shows. This can be used with code like the second 5600 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 5601 * 5602 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 5603 * 5604 * @param insets Current content insets of the window. Prior to 5605 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 5606 * the insets or else you and Android will be unhappy. 5607 * 5608 * @return Return true if this view applied the insets and it should not 5609 * continue propagating further down the hierarchy, false otherwise. 5610 * @see #getFitsSystemWindows() 5611 * @see #setFitsSystemWindows(boolean) 5612 * @see #setSystemUiVisibility(int) 5613 */ fitSystemWindows(Rect insets)5614 protected boolean fitSystemWindows(Rect insets) { 5615 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 5616 mUserPaddingStart = UNDEFINED_PADDING; 5617 mUserPaddingEnd = UNDEFINED_PADDING; 5618 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 5619 || mAttachInfo == null 5620 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 5621 internalSetPadding(insets.left, insets.top, insets.right, insets.bottom); 5622 return true; 5623 } else { 5624 internalSetPadding(0, 0, 0, 0); 5625 return false; 5626 } 5627 } 5628 return false; 5629 } 5630 5631 /** 5632 * Sets whether or not this view should account for system screen decorations 5633 * such as the status bar and inset its content; that is, controlling whether 5634 * the default implementation of {@link #fitSystemWindows(Rect)} will be 5635 * executed. See that method for more details. 5636 * 5637 * <p>Note that if you are providing your own implementation of 5638 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 5639 * flag to true -- your implementation will be overriding the default 5640 * implementation that checks this flag. 5641 * 5642 * @param fitSystemWindows If true, then the default implementation of 5643 * {@link #fitSystemWindows(Rect)} will be executed. 5644 * 5645 * @attr ref android.R.styleable#View_fitsSystemWindows 5646 * @see #getFitsSystemWindows() 5647 * @see #fitSystemWindows(Rect) 5648 * @see #setSystemUiVisibility(int) 5649 */ setFitsSystemWindows(boolean fitSystemWindows)5650 public void setFitsSystemWindows(boolean fitSystemWindows) { 5651 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 5652 } 5653 5654 /** 5655 * Check for state of {@link #setFitsSystemWindows(boolean). If this method 5656 * returns true, the default implementation of {@link #fitSystemWindows(Rect)} 5657 * will be executed. 5658 * 5659 * @return Returns true if the default implementation of 5660 * {@link #fitSystemWindows(Rect)} will be executed. 5661 * 5662 * @attr ref android.R.styleable#View_fitsSystemWindows 5663 * @see #setFitsSystemWindows() 5664 * @see #fitSystemWindows(Rect) 5665 * @see #setSystemUiVisibility(int) 5666 */ getFitsSystemWindows()5667 public boolean getFitsSystemWindows() { 5668 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 5669 } 5670 5671 /** @hide */ fitsSystemWindows()5672 public boolean fitsSystemWindows() { 5673 return getFitsSystemWindows(); 5674 } 5675 5676 /** 5677 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 5678 */ requestFitSystemWindows()5679 public void requestFitSystemWindows() { 5680 if (mParent != null) { 5681 mParent.requestFitSystemWindows(); 5682 } 5683 } 5684 5685 /** 5686 * For use by PhoneWindow to make its own system window fitting optional. 5687 * @hide 5688 */ makeOptionalFitsSystemWindows()5689 public void makeOptionalFitsSystemWindows() { 5690 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 5691 } 5692 5693 /** 5694 * Returns the visibility status for this view. 5695 * 5696 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 5697 * @attr ref android.R.styleable#View_visibility 5698 */ 5699 @ViewDebug.ExportedProperty(mapping = { 5700 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 5701 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 5702 @ViewDebug.IntToString(from = GONE, to = "GONE") 5703 }) getVisibility()5704 public int getVisibility() { 5705 return mViewFlags & VISIBILITY_MASK; 5706 } 5707 5708 /** 5709 * Set the enabled state of this view. 5710 * 5711 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 5712 * @attr ref android.R.styleable#View_visibility 5713 */ 5714 @RemotableViewMethod setVisibility(int visibility)5715 public void setVisibility(int visibility) { 5716 setFlags(visibility, VISIBILITY_MASK); 5717 if (mBackground != null) mBackground.setVisible(visibility == VISIBLE, false); 5718 } 5719 5720 /** 5721 * Returns the enabled status for this view. The interpretation of the 5722 * enabled state varies by subclass. 5723 * 5724 * @return True if this view is enabled, false otherwise. 5725 */ 5726 @ViewDebug.ExportedProperty isEnabled()5727 public boolean isEnabled() { 5728 return (mViewFlags & ENABLED_MASK) == ENABLED; 5729 } 5730 5731 /** 5732 * Set the enabled state of this view. The interpretation of the enabled 5733 * state varies by subclass. 5734 * 5735 * @param enabled True if this view is enabled, false otherwise. 5736 */ 5737 @RemotableViewMethod setEnabled(boolean enabled)5738 public void setEnabled(boolean enabled) { 5739 if (enabled == isEnabled()) return; 5740 5741 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 5742 5743 /* 5744 * The View most likely has to change its appearance, so refresh 5745 * the drawable state. 5746 */ 5747 refreshDrawableState(); 5748 5749 // Invalidate too, since the default behavior for views is to be 5750 // be drawn at 50% alpha rather than to change the drawable. 5751 invalidate(true); 5752 } 5753 5754 /** 5755 * Set whether this view can receive the focus. 5756 * 5757 * Setting this to false will also ensure that this view is not focusable 5758 * in touch mode. 5759 * 5760 * @param focusable If true, this view can receive the focus. 5761 * 5762 * @see #setFocusableInTouchMode(boolean) 5763 * @attr ref android.R.styleable#View_focusable 5764 */ setFocusable(boolean focusable)5765 public void setFocusable(boolean focusable) { 5766 if (!focusable) { 5767 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 5768 } 5769 setFlags(focusable ? FOCUSABLE : NOT_FOCUSABLE, FOCUSABLE_MASK); 5770 } 5771 5772 /** 5773 * Set whether this view can receive focus while in touch mode. 5774 * 5775 * Setting this to true will also ensure that this view is focusable. 5776 * 5777 * @param focusableInTouchMode If true, this view can receive the focus while 5778 * in touch mode. 5779 * 5780 * @see #setFocusable(boolean) 5781 * @attr ref android.R.styleable#View_focusableInTouchMode 5782 */ setFocusableInTouchMode(boolean focusableInTouchMode)5783 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 5784 // Focusable in touch mode should always be set before the focusable flag 5785 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 5786 // which, in touch mode, will not successfully request focus on this view 5787 // because the focusable in touch mode flag is not set 5788 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 5789 if (focusableInTouchMode) { 5790 setFlags(FOCUSABLE, FOCUSABLE_MASK); 5791 } 5792 } 5793 5794 /** 5795 * Set whether this view should have sound effects enabled for events such as 5796 * clicking and touching. 5797 * 5798 * <p>You may wish to disable sound effects for a view if you already play sounds, 5799 * for instance, a dial key that plays dtmf tones. 5800 * 5801 * @param soundEffectsEnabled whether sound effects are enabled for this view. 5802 * @see #isSoundEffectsEnabled() 5803 * @see #playSoundEffect(int) 5804 * @attr ref android.R.styleable#View_soundEffectsEnabled 5805 */ setSoundEffectsEnabled(boolean soundEffectsEnabled)5806 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 5807 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 5808 } 5809 5810 /** 5811 * @return whether this view should have sound effects enabled for events such as 5812 * clicking and touching. 5813 * 5814 * @see #setSoundEffectsEnabled(boolean) 5815 * @see #playSoundEffect(int) 5816 * @attr ref android.R.styleable#View_soundEffectsEnabled 5817 */ 5818 @ViewDebug.ExportedProperty isSoundEffectsEnabled()5819 public boolean isSoundEffectsEnabled() { 5820 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 5821 } 5822 5823 /** 5824 * Set whether this view should have haptic feedback for events such as 5825 * long presses. 5826 * 5827 * <p>You may wish to disable haptic feedback if your view already controls 5828 * its own haptic feedback. 5829 * 5830 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 5831 * @see #isHapticFeedbackEnabled() 5832 * @see #performHapticFeedback(int) 5833 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 5834 */ setHapticFeedbackEnabled(boolean hapticFeedbackEnabled)5835 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 5836 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 5837 } 5838 5839 /** 5840 * @return whether this view should have haptic feedback enabled for events 5841 * long presses. 5842 * 5843 * @see #setHapticFeedbackEnabled(boolean) 5844 * @see #performHapticFeedback(int) 5845 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 5846 */ 5847 @ViewDebug.ExportedProperty isHapticFeedbackEnabled()5848 public boolean isHapticFeedbackEnabled() { 5849 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 5850 } 5851 5852 /** 5853 * Returns the layout direction for this view. 5854 * 5855 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 5856 * {@link #LAYOUT_DIRECTION_RTL}, 5857 * {@link #LAYOUT_DIRECTION_INHERIT} or 5858 * {@link #LAYOUT_DIRECTION_LOCALE}. 5859 * 5860 * @attr ref android.R.styleable#View_layoutDirection 5861 * 5862 * @hide 5863 */ 5864 @ViewDebug.ExportedProperty(category = "layout", mapping = { 5865 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 5866 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 5867 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 5868 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 5869 }) getRawLayoutDirection()5870 public int getRawLayoutDirection() { 5871 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 5872 } 5873 5874 /** 5875 * Set the layout direction for this view. This will propagate a reset of layout direction 5876 * resolution to the view's children and resolve layout direction for this view. 5877 * 5878 * @param layoutDirection the layout direction to set. Should be one of: 5879 * 5880 * {@link #LAYOUT_DIRECTION_LTR}, 5881 * {@link #LAYOUT_DIRECTION_RTL}, 5882 * {@link #LAYOUT_DIRECTION_INHERIT}, 5883 * {@link #LAYOUT_DIRECTION_LOCALE}. 5884 * 5885 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 5886 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 5887 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 5888 * 5889 * @attr ref android.R.styleable#View_layoutDirection 5890 */ 5891 @RemotableViewMethod setLayoutDirection(int layoutDirection)5892 public void setLayoutDirection(int layoutDirection) { 5893 if (getRawLayoutDirection() != layoutDirection) { 5894 // Reset the current layout direction and the resolved one 5895 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 5896 resetRtlProperties(); 5897 // Set the new layout direction (filtered) 5898 mPrivateFlags2 |= 5899 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 5900 // We need to resolve all RTL properties as they all depend on layout direction 5901 resolveRtlPropertiesIfNeeded(); 5902 requestLayout(); 5903 invalidate(true); 5904 } 5905 } 5906 5907 /** 5908 * Returns the resolved layout direction for this view. 5909 * 5910 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 5911 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 5912 * 5913 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 5914 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 5915 * 5916 * @attr ref android.R.styleable#View_layoutDirection 5917 */ 5918 @ViewDebug.ExportedProperty(category = "layout", mapping = { 5919 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 5920 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 5921 }) getLayoutDirection()5922 public int getLayoutDirection() { 5923 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 5924 if (targetSdkVersion < JELLY_BEAN_MR1) { 5925 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 5926 return LAYOUT_DIRECTION_LTR; 5927 } 5928 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 5929 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 5930 } 5931 5932 /** 5933 * Indicates whether or not this view's layout is right-to-left. This is resolved from 5934 * layout attribute and/or the inherited value from the parent 5935 * 5936 * @return true if the layout is right-to-left. 5937 * 5938 * @hide 5939 */ 5940 @ViewDebug.ExportedProperty(category = "layout") isLayoutRtl()5941 public boolean isLayoutRtl() { 5942 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 5943 } 5944 5945 /** 5946 * Indicates whether the view is currently tracking transient state that the 5947 * app should not need to concern itself with saving and restoring, but that 5948 * the framework should take special note to preserve when possible. 5949 * 5950 * <p>A view with transient state cannot be trivially rebound from an external 5951 * data source, such as an adapter binding item views in a list. This may be 5952 * because the view is performing an animation, tracking user selection 5953 * of content, or similar.</p> 5954 * 5955 * @return true if the view has transient state 5956 */ 5957 @ViewDebug.ExportedProperty(category = "layout") hasTransientState()5958 public boolean hasTransientState() { 5959 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 5960 } 5961 5962 /** 5963 * Set whether this view is currently tracking transient state that the 5964 * framework should attempt to preserve when possible. This flag is reference counted, 5965 * so every call to setHasTransientState(true) should be paired with a later call 5966 * to setHasTransientState(false). 5967 * 5968 * <p>A view with transient state cannot be trivially rebound from an external 5969 * data source, such as an adapter binding item views in a list. This may be 5970 * because the view is performing an animation, tracking user selection 5971 * of content, or similar.</p> 5972 * 5973 * @param hasTransientState true if this view has transient state 5974 */ setHasTransientState(boolean hasTransientState)5975 public void setHasTransientState(boolean hasTransientState) { 5976 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 5977 mTransientStateCount - 1; 5978 if (mTransientStateCount < 0) { 5979 mTransientStateCount = 0; 5980 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 5981 "unmatched pair of setHasTransientState calls"); 5982 } 5983 if ((hasTransientState && mTransientStateCount == 1) || 5984 (!hasTransientState && mTransientStateCount == 0)) { 5985 // update flag if we've just incremented up from 0 or decremented down to 0 5986 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 5987 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 5988 if (mParent != null) { 5989 try { 5990 mParent.childHasTransientStateChanged(this, hasTransientState); 5991 } catch (AbstractMethodError e) { 5992 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 5993 " does not fully implement ViewParent", e); 5994 } 5995 } 5996 } 5997 } 5998 5999 /** 6000 * If this view doesn't do any drawing on its own, set this flag to 6001 * allow further optimizations. By default, this flag is not set on 6002 * View, but could be set on some View subclasses such as ViewGroup. 6003 * 6004 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 6005 * you should clear this flag. 6006 * 6007 * @param willNotDraw whether or not this View draw on its own 6008 */ setWillNotDraw(boolean willNotDraw)6009 public void setWillNotDraw(boolean willNotDraw) { 6010 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 6011 } 6012 6013 /** 6014 * Returns whether or not this View draws on its own. 6015 * 6016 * @return true if this view has nothing to draw, false otherwise 6017 */ 6018 @ViewDebug.ExportedProperty(category = "drawing") willNotDraw()6019 public boolean willNotDraw() { 6020 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 6021 } 6022 6023 /** 6024 * When a View's drawing cache is enabled, drawing is redirected to an 6025 * offscreen bitmap. Some views, like an ImageView, must be able to 6026 * bypass this mechanism if they already draw a single bitmap, to avoid 6027 * unnecessary usage of the memory. 6028 * 6029 * @param willNotCacheDrawing true if this view does not cache its 6030 * drawing, false otherwise 6031 */ setWillNotCacheDrawing(boolean willNotCacheDrawing)6032 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 6033 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 6034 } 6035 6036 /** 6037 * Returns whether or not this View can cache its drawing or not. 6038 * 6039 * @return true if this view does not cache its drawing, false otherwise 6040 */ 6041 @ViewDebug.ExportedProperty(category = "drawing") willNotCacheDrawing()6042 public boolean willNotCacheDrawing() { 6043 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 6044 } 6045 6046 /** 6047 * Indicates whether this view reacts to click events or not. 6048 * 6049 * @return true if the view is clickable, false otherwise 6050 * 6051 * @see #setClickable(boolean) 6052 * @attr ref android.R.styleable#View_clickable 6053 */ 6054 @ViewDebug.ExportedProperty isClickable()6055 public boolean isClickable() { 6056 return (mViewFlags & CLICKABLE) == CLICKABLE; 6057 } 6058 6059 /** 6060 * Enables or disables click events for this view. When a view 6061 * is clickable it will change its state to "pressed" on every click. 6062 * Subclasses should set the view clickable to visually react to 6063 * user's clicks. 6064 * 6065 * @param clickable true to make the view clickable, false otherwise 6066 * 6067 * @see #isClickable() 6068 * @attr ref android.R.styleable#View_clickable 6069 */ setClickable(boolean clickable)6070 public void setClickable(boolean clickable) { 6071 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 6072 } 6073 6074 /** 6075 * Indicates whether this view reacts to long click events or not. 6076 * 6077 * @return true if the view is long clickable, false otherwise 6078 * 6079 * @see #setLongClickable(boolean) 6080 * @attr ref android.R.styleable#View_longClickable 6081 */ isLongClickable()6082 public boolean isLongClickable() { 6083 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 6084 } 6085 6086 /** 6087 * Enables or disables long click events for this view. When a view is long 6088 * clickable it reacts to the user holding down the button for a longer 6089 * duration than a tap. This event can either launch the listener or a 6090 * context menu. 6091 * 6092 * @param longClickable true to make the view long clickable, false otherwise 6093 * @see #isLongClickable() 6094 * @attr ref android.R.styleable#View_longClickable 6095 */ setLongClickable(boolean longClickable)6096 public void setLongClickable(boolean longClickable) { 6097 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 6098 } 6099 6100 /** 6101 * Sets the pressed state for this view. 6102 * 6103 * @see #isClickable() 6104 * @see #setClickable(boolean) 6105 * 6106 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 6107 * the View's internal state from a previously set "pressed" state. 6108 */ setPressed(boolean pressed)6109 public void setPressed(boolean pressed) { 6110 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 6111 6112 if (pressed) { 6113 mPrivateFlags |= PFLAG_PRESSED; 6114 } else { 6115 mPrivateFlags &= ~PFLAG_PRESSED; 6116 } 6117 6118 if (needsRefresh) { 6119 refreshDrawableState(); 6120 } 6121 dispatchSetPressed(pressed); 6122 } 6123 6124 /** 6125 * Dispatch setPressed to all of this View's children. 6126 * 6127 * @see #setPressed(boolean) 6128 * 6129 * @param pressed The new pressed state 6130 */ dispatchSetPressed(boolean pressed)6131 protected void dispatchSetPressed(boolean pressed) { 6132 } 6133 6134 /** 6135 * Indicates whether the view is currently in pressed state. Unless 6136 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 6137 * the pressed state. 6138 * 6139 * @see #setPressed(boolean) 6140 * @see #isClickable() 6141 * @see #setClickable(boolean) 6142 * 6143 * @return true if the view is currently pressed, false otherwise 6144 */ isPressed()6145 public boolean isPressed() { 6146 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 6147 } 6148 6149 /** 6150 * Indicates whether this view will save its state (that is, 6151 * whether its {@link #onSaveInstanceState} method will be called). 6152 * 6153 * @return Returns true if the view state saving is enabled, else false. 6154 * 6155 * @see #setSaveEnabled(boolean) 6156 * @attr ref android.R.styleable#View_saveEnabled 6157 */ isSaveEnabled()6158 public boolean isSaveEnabled() { 6159 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 6160 } 6161 6162 /** 6163 * Controls whether the saving of this view's state is 6164 * enabled (that is, whether its {@link #onSaveInstanceState} method 6165 * will be called). Note that even if freezing is enabled, the 6166 * view still must have an id assigned to it (via {@link #setId(int)}) 6167 * for its state to be saved. This flag can only disable the 6168 * saving of this view; any child views may still have their state saved. 6169 * 6170 * @param enabled Set to false to <em>disable</em> state saving, or true 6171 * (the default) to allow it. 6172 * 6173 * @see #isSaveEnabled() 6174 * @see #setId(int) 6175 * @see #onSaveInstanceState() 6176 * @attr ref android.R.styleable#View_saveEnabled 6177 */ setSaveEnabled(boolean enabled)6178 public void setSaveEnabled(boolean enabled) { 6179 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 6180 } 6181 6182 /** 6183 * Gets whether the framework should discard touches when the view's 6184 * window is obscured by another visible window. 6185 * Refer to the {@link View} security documentation for more details. 6186 * 6187 * @return True if touch filtering is enabled. 6188 * 6189 * @see #setFilterTouchesWhenObscured(boolean) 6190 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 6191 */ 6192 @ViewDebug.ExportedProperty getFilterTouchesWhenObscured()6193 public boolean getFilterTouchesWhenObscured() { 6194 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 6195 } 6196 6197 /** 6198 * Sets whether the framework should discard touches when the view's 6199 * window is obscured by another visible window. 6200 * Refer to the {@link View} security documentation for more details. 6201 * 6202 * @param enabled True if touch filtering should be enabled. 6203 * 6204 * @see #getFilterTouchesWhenObscured 6205 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 6206 */ setFilterTouchesWhenObscured(boolean enabled)6207 public void setFilterTouchesWhenObscured(boolean enabled) { 6208 setFlags(enabled ? 0 : FILTER_TOUCHES_WHEN_OBSCURED, 6209 FILTER_TOUCHES_WHEN_OBSCURED); 6210 } 6211 6212 /** 6213 * Indicates whether the entire hierarchy under this view will save its 6214 * state when a state saving traversal occurs from its parent. The default 6215 * is true; if false, these views will not be saved unless 6216 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 6217 * 6218 * @return Returns true if the view state saving from parent is enabled, else false. 6219 * 6220 * @see #setSaveFromParentEnabled(boolean) 6221 */ isSaveFromParentEnabled()6222 public boolean isSaveFromParentEnabled() { 6223 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 6224 } 6225 6226 /** 6227 * Controls whether the entire hierarchy under this view will save its 6228 * state when a state saving traversal occurs from its parent. The default 6229 * is true; if false, these views will not be saved unless 6230 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 6231 * 6232 * @param enabled Set to false to <em>disable</em> state saving, or true 6233 * (the default) to allow it. 6234 * 6235 * @see #isSaveFromParentEnabled() 6236 * @see #setId(int) 6237 * @see #onSaveInstanceState() 6238 */ setSaveFromParentEnabled(boolean enabled)6239 public void setSaveFromParentEnabled(boolean enabled) { 6240 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 6241 } 6242 6243 6244 /** 6245 * Returns whether this View is able to take focus. 6246 * 6247 * @return True if this view can take focus, or false otherwise. 6248 * @attr ref android.R.styleable#View_focusable 6249 */ 6250 @ViewDebug.ExportedProperty(category = "focus") isFocusable()6251 public final boolean isFocusable() { 6252 return FOCUSABLE == (mViewFlags & FOCUSABLE_MASK); 6253 } 6254 6255 /** 6256 * When a view is focusable, it may not want to take focus when in touch mode. 6257 * For example, a button would like focus when the user is navigating via a D-pad 6258 * so that the user can click on it, but once the user starts touching the screen, 6259 * the button shouldn't take focus 6260 * @return Whether the view is focusable in touch mode. 6261 * @attr ref android.R.styleable#View_focusableInTouchMode 6262 */ 6263 @ViewDebug.ExportedProperty isFocusableInTouchMode()6264 public final boolean isFocusableInTouchMode() { 6265 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 6266 } 6267 6268 /** 6269 * Find the nearest view in the specified direction that can take focus. 6270 * This does not actually give focus to that view. 6271 * 6272 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 6273 * 6274 * @return The nearest focusable in the specified direction, or null if none 6275 * can be found. 6276 */ focusSearch(int direction)6277 public View focusSearch(int direction) { 6278 if (mParent != null) { 6279 return mParent.focusSearch(this, direction); 6280 } else { 6281 return null; 6282 } 6283 } 6284 6285 /** 6286 * This method is the last chance for the focused view and its ancestors to 6287 * respond to an arrow key. This is called when the focused view did not 6288 * consume the key internally, nor could the view system find a new view in 6289 * the requested direction to give focus to. 6290 * 6291 * @param focused The currently focused view. 6292 * @param direction The direction focus wants to move. One of FOCUS_UP, 6293 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 6294 * @return True if the this view consumed this unhandled move. 6295 */ dispatchUnhandledMove(View focused, int direction)6296 public boolean dispatchUnhandledMove(View focused, int direction) { 6297 return false; 6298 } 6299 6300 /** 6301 * If a user manually specified the next view id for a particular direction, 6302 * use the root to look up the view. 6303 * @param root The root view of the hierarchy containing this view. 6304 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 6305 * or FOCUS_BACKWARD. 6306 * @return The user specified next view, or null if there is none. 6307 */ findUserSetNextFocus(View root, int direction)6308 View findUserSetNextFocus(View root, int direction) { 6309 switch (direction) { 6310 case FOCUS_LEFT: 6311 if (mNextFocusLeftId == View.NO_ID) return null; 6312 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 6313 case FOCUS_RIGHT: 6314 if (mNextFocusRightId == View.NO_ID) return null; 6315 return findViewInsideOutShouldExist(root, mNextFocusRightId); 6316 case FOCUS_UP: 6317 if (mNextFocusUpId == View.NO_ID) return null; 6318 return findViewInsideOutShouldExist(root, mNextFocusUpId); 6319 case FOCUS_DOWN: 6320 if (mNextFocusDownId == View.NO_ID) return null; 6321 return findViewInsideOutShouldExist(root, mNextFocusDownId); 6322 case FOCUS_FORWARD: 6323 if (mNextFocusForwardId == View.NO_ID) return null; 6324 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 6325 case FOCUS_BACKWARD: { 6326 if (mID == View.NO_ID) return null; 6327 final int id = mID; 6328 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 6329 @Override 6330 public boolean apply(View t) { 6331 return t.mNextFocusForwardId == id; 6332 } 6333 }); 6334 } 6335 } 6336 return null; 6337 } 6338 6339 private View findViewInsideOutShouldExist(View root, int id) { 6340 if (mMatchIdPredicate == null) { 6341 mMatchIdPredicate = new MatchIdPredicate(); 6342 } 6343 mMatchIdPredicate.mId = id; 6344 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 6345 if (result == null) { 6346 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 6347 } 6348 return result; 6349 } 6350 6351 /** 6352 * Find and return all focusable views that are descendants of this view, 6353 * possibly including this view if it is focusable itself. 6354 * 6355 * @param direction The direction of the focus 6356 * @return A list of focusable views 6357 */ 6358 public ArrayList<View> getFocusables(int direction) { 6359 ArrayList<View> result = new ArrayList<View>(24); 6360 addFocusables(result, direction); 6361 return result; 6362 } 6363 6364 /** 6365 * Add any focusable views that are descendants of this view (possibly 6366 * including this view if it is focusable itself) to views. If we are in touch mode, 6367 * only add views that are also focusable in touch mode. 6368 * 6369 * @param views Focusable views found so far 6370 * @param direction The direction of the focus 6371 */ 6372 public void addFocusables(ArrayList<View> views, int direction) { 6373 addFocusables(views, direction, FOCUSABLES_TOUCH_MODE); 6374 } 6375 6376 /** 6377 * Adds any focusable views that are descendants of this view (possibly 6378 * including this view if it is focusable itself) to views. This method 6379 * adds all focusable views regardless if we are in touch mode or 6380 * only views focusable in touch mode if we are in touch mode or 6381 * only views that can take accessibility focus if accessibility is enabeld 6382 * depending on the focusable mode paramater. 6383 * 6384 * @param views Focusable views found so far or null if all we are interested is 6385 * the number of focusables. 6386 * @param direction The direction of the focus. 6387 * @param focusableMode The type of focusables to be added. 6388 * 6389 * @see #FOCUSABLES_ALL 6390 * @see #FOCUSABLES_TOUCH_MODE 6391 */ 6392 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 6393 if (views == null) { 6394 return; 6395 } 6396 if (!isFocusable()) { 6397 return; 6398 } 6399 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 6400 && isInTouchMode() && !isFocusableInTouchMode()) { 6401 return; 6402 } 6403 views.add(this); 6404 } 6405 6406 /** 6407 * Finds the Views that contain given text. The containment is case insensitive. 6408 * The search is performed by either the text that the View renders or the content 6409 * description that describes the view for accessibility purposes and the view does 6410 * not render or both. Clients can specify how the search is to be performed via 6411 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 6412 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 6413 * 6414 * @param outViews The output list of matching Views. 6415 * @param searched The text to match against. 6416 * 6417 * @see #FIND_VIEWS_WITH_TEXT 6418 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 6419 * @see #setContentDescription(CharSequence) 6420 */ 6421 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, int flags) { 6422 if (getAccessibilityNodeProvider() != null) { 6423 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 6424 outViews.add(this); 6425 } 6426 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 6427 && (searched != null && searched.length() > 0) 6428 && (mContentDescription != null && mContentDescription.length() > 0)) { 6429 String searchedLowerCase = searched.toString().toLowerCase(); 6430 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 6431 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 6432 outViews.add(this); 6433 } 6434 } 6435 } 6436 6437 /** 6438 * Find and return all touchable views that are descendants of this view, 6439 * possibly including this view if it is touchable itself. 6440 * 6441 * @return A list of touchable views 6442 */ 6443 public ArrayList<View> getTouchables() { 6444 ArrayList<View> result = new ArrayList<View>(); 6445 addTouchables(result); 6446 return result; 6447 } 6448 6449 /** 6450 * Add any touchable views that are descendants of this view (possibly 6451 * including this view if it is touchable itself) to views. 6452 * 6453 * @param views Touchable views found so far 6454 */ 6455 public void addTouchables(ArrayList<View> views) { 6456 final int viewFlags = mViewFlags; 6457 6458 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 6459 && (viewFlags & ENABLED_MASK) == ENABLED) { 6460 views.add(this); 6461 } 6462 } 6463 6464 /** 6465 * Returns whether this View is accessibility focused. 6466 * 6467 * @return True if this View is accessibility focused. 6468 */ 6469 boolean isAccessibilityFocused() { 6470 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 6471 } 6472 6473 /** 6474 * Call this to try to give accessibility focus to this view. 6475 * 6476 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 6477 * returns false or the view is no visible or the view already has accessibility 6478 * focus. 6479 * 6480 * See also {@link #focusSearch(int)}, which is what you call to say that you 6481 * have focus, and you want your parent to look for the next one. 6482 * 6483 * @return Whether this view actually took accessibility focus. 6484 * 6485 * @hide 6486 */ 6487 public boolean requestAccessibilityFocus() { 6488 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 6489 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 6490 return false; 6491 } 6492 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 6493 return false; 6494 } 6495 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 6496 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 6497 ViewRootImpl viewRootImpl = getViewRootImpl(); 6498 if (viewRootImpl != null) { 6499 viewRootImpl.setAccessibilityFocus(this, null); 6500 } 6501 invalidate(); 6502 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 6503 notifyAccessibilityStateChanged(); 6504 return true; 6505 } 6506 return false; 6507 } 6508 6509 /** 6510 * Call this to try to clear accessibility focus of this view. 6511 * 6512 * See also {@link #focusSearch(int)}, which is what you call to say that you 6513 * have focus, and you want your parent to look for the next one. 6514 * 6515 * @hide 6516 */ 6517 public void clearAccessibilityFocus() { 6518 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 6519 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 6520 invalidate(); 6521 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 6522 notifyAccessibilityStateChanged(); 6523 } 6524 // Clear the global reference of accessibility focus if this 6525 // view or any of its descendants had accessibility focus. 6526 ViewRootImpl viewRootImpl = getViewRootImpl(); 6527 if (viewRootImpl != null) { 6528 View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 6529 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 6530 viewRootImpl.setAccessibilityFocus(null, null); 6531 } 6532 } 6533 } 6534 6535 private void sendAccessibilityHoverEvent(int eventType) { 6536 // Since we are not delivering to a client accessibility events from not 6537 // important views (unless the clinet request that) we need to fire the 6538 // event from the deepest view exposed to the client. As a consequence if 6539 // the user crosses a not exposed view the client will see enter and exit 6540 // of the exposed predecessor followed by and enter and exit of that same 6541 // predecessor when entering and exiting the not exposed descendant. This 6542 // is fine since the client has a clear idea which view is hovered at the 6543 // price of a couple more events being sent. This is a simple and 6544 // working solution. 6545 View source = this; 6546 while (true) { 6547 if (source.includeForAccessibility()) { 6548 source.sendAccessibilityEvent(eventType); 6549 return; 6550 } 6551 ViewParent parent = source.getParent(); 6552 if (parent instanceof View) { 6553 source = (View) parent; 6554 } else { 6555 return; 6556 } 6557 } 6558 } 6559 6560 /** 6561 * Clears accessibility focus without calling any callback methods 6562 * normally invoked in {@link #clearAccessibilityFocus()}. This method 6563 * is used for clearing accessibility focus when giving this focus to 6564 * another view. 6565 */ 6566 void clearAccessibilityFocusNoCallbacks() { 6567 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 6568 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 6569 invalidate(); 6570 } 6571 } 6572 6573 /** 6574 * Call this to try to give focus to a specific view or to one of its 6575 * descendants. 6576 * 6577 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 6578 * false), or if it is focusable and it is not focusable in touch mode 6579 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 6580 * 6581 * See also {@link #focusSearch(int)}, which is what you call to say that you 6582 * have focus, and you want your parent to look for the next one. 6583 * 6584 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 6585 * {@link #FOCUS_DOWN} and <code>null</code>. 6586 * 6587 * @return Whether this view or one of its descendants actually took focus. 6588 */ 6589 public final boolean requestFocus() { 6590 return requestFocus(View.FOCUS_DOWN); 6591 } 6592 6593 /** 6594 * Call this to try to give focus to a specific view or to one of its 6595 * descendants and give it a hint about what direction focus is heading. 6596 * 6597 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 6598 * false), or if it is focusable and it is not focusable in touch mode 6599 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 6600 * 6601 * See also {@link #focusSearch(int)}, which is what you call to say that you 6602 * have focus, and you want your parent to look for the next one. 6603 * 6604 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 6605 * <code>null</code> set for the previously focused rectangle. 6606 * 6607 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 6608 * @return Whether this view or one of its descendants actually took focus. 6609 */ 6610 public final boolean requestFocus(int direction) { 6611 return requestFocus(direction, null); 6612 } 6613 6614 /** 6615 * Call this to try to give focus to a specific view or to one of its descendants 6616 * and give it hints about the direction and a specific rectangle that the focus 6617 * is coming from. The rectangle can help give larger views a finer grained hint 6618 * about where focus is coming from, and therefore, where to show selection, or 6619 * forward focus change internally. 6620 * 6621 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 6622 * false), or if it is focusable and it is not focusable in touch mode 6623 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 6624 * 6625 * A View will not take focus if it is not visible. 6626 * 6627 * A View will not take focus if one of its parents has 6628 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 6629 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 6630 * 6631 * See also {@link #focusSearch(int)}, which is what you call to say that you 6632 * have focus, and you want your parent to look for the next one. 6633 * 6634 * You may wish to override this method if your custom {@link View} has an internal 6635 * {@link View} that it wishes to forward the request to. 6636 * 6637 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 6638 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 6639 * to give a finer grained hint about where focus is coming from. May be null 6640 * if there is no hint. 6641 * @return Whether this view or one of its descendants actually took focus. 6642 */ 6643 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 6644 return requestFocusNoSearch(direction, previouslyFocusedRect); 6645 } 6646 6647 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 6648 // need to be focusable 6649 if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE || 6650 (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 6651 return false; 6652 } 6653 6654 // need to be focusable in touch mode if in touch mode 6655 if (isInTouchMode() && 6656 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 6657 return false; 6658 } 6659 6660 // need to not have any parents blocking us 6661 if (hasAncestorThatBlocksDescendantFocus()) { 6662 return false; 6663 } 6664 6665 handleFocusGainInternal(direction, previouslyFocusedRect); 6666 return true; 6667 } 6668 6669 /** 6670 * Call this to try to give focus to a specific view or to one of its descendants. This is a 6671 * special variant of {@link #requestFocus() } that will allow views that are not focuable in 6672 * touch mode to request focus when they are touched. 6673 * 6674 * @return Whether this view or one of its descendants actually took focus. 6675 * 6676 * @see #isInTouchMode() 6677 * 6678 */ 6679 public final boolean requestFocusFromTouch() { 6680 // Leave touch mode if we need to 6681 if (isInTouchMode()) { 6682 ViewRootImpl viewRoot = getViewRootImpl(); 6683 if (viewRoot != null) { 6684 viewRoot.ensureTouchMode(false); 6685 } 6686 } 6687 return requestFocus(View.FOCUS_DOWN); 6688 } 6689 6690 /** 6691 * @return Whether any ancestor of this view blocks descendant focus. 6692 */ 6693 private boolean hasAncestorThatBlocksDescendantFocus() { 6694 ViewParent ancestor = mParent; 6695 while (ancestor instanceof ViewGroup) { 6696 final ViewGroup vgAncestor = (ViewGroup) ancestor; 6697 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS) { 6698 return true; 6699 } else { 6700 ancestor = vgAncestor.getParent(); 6701 } 6702 } 6703 return false; 6704 } 6705 6706 /** 6707 * Gets the mode for determining whether this View is important for accessibility 6708 * which is if it fires accessibility events and if it is reported to 6709 * accessibility services that query the screen. 6710 * 6711 * @return The mode for determining whether a View is important for accessibility. 6712 * 6713 * @attr ref android.R.styleable#View_importantForAccessibility 6714 * 6715 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 6716 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 6717 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 6718 */ 6719 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 6720 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 6721 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 6722 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no") 6723 }) 6724 public int getImportantForAccessibility() { 6725 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 6726 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 6727 } 6728 6729 /** 6730 * Sets how to determine whether this view is important for accessibility 6731 * which is if it fires accessibility events and if it is reported to 6732 * accessibility services that query the screen. 6733 * 6734 * @param mode How to determine whether this view is important for accessibility. 6735 * 6736 * @attr ref android.R.styleable#View_importantForAccessibility 6737 * 6738 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 6739 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 6740 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 6741 */ 6742 public void setImportantForAccessibility(int mode) { 6743 if (mode != getImportantForAccessibility()) { 6744 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 6745 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 6746 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 6747 notifyAccessibilityStateChanged(); 6748 } 6749 } 6750 6751 /** 6752 * Gets whether this view should be exposed for accessibility. 6753 * 6754 * @return Whether the view is exposed for accessibility. 6755 * 6756 * @hide 6757 */ 6758 public boolean isImportantForAccessibility() { 6759 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 6760 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 6761 switch (mode) { 6762 case IMPORTANT_FOR_ACCESSIBILITY_YES: 6763 return true; 6764 case IMPORTANT_FOR_ACCESSIBILITY_NO: 6765 return false; 6766 case IMPORTANT_FOR_ACCESSIBILITY_AUTO: 6767 return isActionableForAccessibility() || hasListenersForAccessibility() 6768 || getAccessibilityNodeProvider() != null; 6769 default: 6770 throw new IllegalArgumentException("Unknow important for accessibility mode: " 6771 + mode); 6772 } 6773 } 6774 6775 /** 6776 * Gets the parent for accessibility purposes. Note that the parent for 6777 * accessibility is not necessary the immediate parent. It is the first 6778 * predecessor that is important for accessibility. 6779 * 6780 * @return The parent for accessibility purposes. 6781 */ 6782 public ViewParent getParentForAccessibility() { 6783 if (mParent instanceof View) { 6784 View parentView = (View) mParent; 6785 if (parentView.includeForAccessibility()) { 6786 return mParent; 6787 } else { 6788 return mParent.getParentForAccessibility(); 6789 } 6790 } 6791 return null; 6792 } 6793 6794 /** 6795 * Adds the children of a given View for accessibility. Since some Views are 6796 * not important for accessibility the children for accessibility are not 6797 * necessarily direct children of the riew, rather they are the first level of 6798 * descendants important for accessibility. 6799 * 6800 * @param children The list of children for accessibility. 6801 */ 6802 public void addChildrenForAccessibility(ArrayList<View> children) { 6803 if (includeForAccessibility()) { 6804 children.add(this); 6805 } 6806 } 6807 6808 /** 6809 * Whether to regard this view for accessibility. A view is regarded for 6810 * accessibility if it is important for accessibility or the querying 6811 * accessibility service has explicitly requested that view not 6812 * important for accessibility are regarded. 6813 * 6814 * @return Whether to regard the view for accessibility. 6815 * 6816 * @hide 6817 */ 6818 public boolean includeForAccessibility() { 6819 if (mAttachInfo != null) { 6820 return mAttachInfo.mIncludeNotImportantViews || isImportantForAccessibility(); 6821 } 6822 return false; 6823 } 6824 6825 /** 6826 * Returns whether the View is considered actionable from 6827 * accessibility perspective. Such view are important for 6828 * accessibility. 6829 * 6830 * @return True if the view is actionable for accessibility. 6831 * 6832 * @hide 6833 */ 6834 public boolean isActionableForAccessibility() { 6835 return (isClickable() || isLongClickable() || isFocusable()); 6836 } 6837 6838 /** 6839 * Returns whether the View has registered callbacks wich makes it 6840 * important for accessibility. 6841 * 6842 * @return True if the view is actionable for accessibility. 6843 */ 6844 private boolean hasListenersForAccessibility() { 6845 ListenerInfo info = getListenerInfo(); 6846 return mTouchDelegate != null || info.mOnKeyListener != null 6847 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 6848 || info.mOnHoverListener != null || info.mOnDragListener != null; 6849 } 6850 6851 /** 6852 * Notifies accessibility services that some view's important for 6853 * accessibility state has changed. Note that such notifications 6854 * are made at most once every 6855 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 6856 * to avoid unnecessary load to the system. Also once a view has 6857 * made a notifucation this method is a NOP until the notification has 6858 * been sent to clients. 6859 * 6860 * @hide 6861 * 6862 * TODO: Makse sure this method is called for any view state change 6863 * that is interesting for accessilility purposes. 6864 */ 6865 public void notifyAccessibilityStateChanged() { 6866 if (!AccessibilityManager.getInstance(mContext).isEnabled()) { 6867 return; 6868 } 6869 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_STATE_CHANGED) == 0) { 6870 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_STATE_CHANGED; 6871 if (mParent != null) { 6872 mParent.childAccessibilityStateChanged(this); 6873 } 6874 } 6875 } 6876 6877 /** 6878 * Reset the state indicating the this view has requested clients 6879 * interested in its accessibility state to be notified. 6880 * 6881 * @hide 6882 */ 6883 public void resetAccessibilityStateChanged() { 6884 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_STATE_CHANGED; 6885 } 6886 6887 /** 6888 * Performs the specified accessibility action on the view. For 6889 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 6890 * <p> 6891 * If an {@link AccessibilityDelegate} has been specified via calling 6892 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6893 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 6894 * is responsible for handling this call. 6895 * </p> 6896 * 6897 * @param action The action to perform. 6898 * @param arguments Optional action arguments. 6899 * @return Whether the action was performed. 6900 */ 6901 public boolean performAccessibilityAction(int action, Bundle arguments) { 6902 if (mAccessibilityDelegate != null) { 6903 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 6904 } else { 6905 return performAccessibilityActionInternal(action, arguments); 6906 } 6907 } 6908 6909 /** 6910 * @see #performAccessibilityAction(int, Bundle) 6911 * 6912 * Note: Called from the default {@link AccessibilityDelegate}. 6913 */ 6914 boolean performAccessibilityActionInternal(int action, Bundle arguments) { 6915 switch (action) { 6916 case AccessibilityNodeInfo.ACTION_CLICK: { 6917 if (isClickable()) { 6918 performClick(); 6919 return true; 6920 } 6921 } break; 6922 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 6923 if (isLongClickable()) { 6924 performLongClick(); 6925 return true; 6926 } 6927 } break; 6928 case AccessibilityNodeInfo.ACTION_FOCUS: { 6929 if (!hasFocus()) { 6930 // Get out of touch mode since accessibility 6931 // wants to move focus around. 6932 getViewRootImpl().ensureTouchMode(false); 6933 return requestFocus(); 6934 } 6935 } break; 6936 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 6937 if (hasFocus()) { 6938 clearFocus(); 6939 return !isFocused(); 6940 } 6941 } break; 6942 case AccessibilityNodeInfo.ACTION_SELECT: { 6943 if (!isSelected()) { 6944 setSelected(true); 6945 return isSelected(); 6946 } 6947 } break; 6948 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 6949 if (isSelected()) { 6950 setSelected(false); 6951 return !isSelected(); 6952 } 6953 } break; 6954 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 6955 if (!isAccessibilityFocused()) { 6956 return requestAccessibilityFocus(); 6957 } 6958 } break; 6959 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 6960 if (isAccessibilityFocused()) { 6961 clearAccessibilityFocus(); 6962 return true; 6963 } 6964 } break; 6965 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 6966 if (arguments != null) { 6967 final int granularity = arguments.getInt( 6968 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 6969 return nextAtGranularity(granularity); 6970 } 6971 } break; 6972 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 6973 if (arguments != null) { 6974 final int granularity = arguments.getInt( 6975 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 6976 return previousAtGranularity(granularity); 6977 } 6978 } break; 6979 } 6980 return false; 6981 } 6982 6983 private boolean nextAtGranularity(int granularity) { 6984 CharSequence text = getIterableTextForAccessibility(); 6985 if (text == null || text.length() == 0) { 6986 return false; 6987 } 6988 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 6989 if (iterator == null) { 6990 return false; 6991 } 6992 final int current = getAccessibilityCursorPosition(); 6993 final int[] range = iterator.following(current); 6994 if (range == null) { 6995 return false; 6996 } 6997 final int start = range[0]; 6998 final int end = range[1]; 6999 setAccessibilityCursorPosition(end); 7000 sendViewTextTraversedAtGranularityEvent( 7001 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, 7002 granularity, start, end); 7003 return true; 7004 } 7005 7006 private boolean previousAtGranularity(int granularity) { 7007 CharSequence text = getIterableTextForAccessibility(); 7008 if (text == null || text.length() == 0) { 7009 return false; 7010 } 7011 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 7012 if (iterator == null) { 7013 return false; 7014 } 7015 int current = getAccessibilityCursorPosition(); 7016 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 7017 current = text.length(); 7018 setAccessibilityCursorPosition(current); 7019 } else if (granularity == AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER) { 7020 // When traversing by character we always put the cursor after the character 7021 // to ease edit and have to compensate before asking the for previous segment. 7022 current--; 7023 setAccessibilityCursorPosition(current); 7024 } 7025 final int[] range = iterator.preceding(current); 7026 if (range == null) { 7027 return false; 7028 } 7029 final int start = range[0]; 7030 final int end = range[1]; 7031 // Always put the cursor after the character to ease edit. 7032 if (granularity == AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER) { 7033 setAccessibilityCursorPosition(end); 7034 } else { 7035 setAccessibilityCursorPosition(start); 7036 } 7037 sendViewTextTraversedAtGranularityEvent( 7038 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, 7039 granularity, start, end); 7040 return true; 7041 } 7042 7043 /** 7044 * Gets the text reported for accessibility purposes. 7045 * 7046 * @return The accessibility text. 7047 * 7048 * @hide 7049 */ 7050 public CharSequence getIterableTextForAccessibility() { 7051 return getContentDescription(); 7052 } 7053 7054 /** 7055 * @hide 7056 */ 7057 public int getAccessibilityCursorPosition() { 7058 return mAccessibilityCursorPosition; 7059 } 7060 7061 /** 7062 * @hide 7063 */ 7064 public void setAccessibilityCursorPosition(int position) { 7065 mAccessibilityCursorPosition = position; 7066 } 7067 7068 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 7069 int fromIndex, int toIndex) { 7070 if (mParent == null) { 7071 return; 7072 } 7073 AccessibilityEvent event = AccessibilityEvent.obtain( 7074 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 7075 onInitializeAccessibilityEvent(event); 7076 onPopulateAccessibilityEvent(event); 7077 event.setFromIndex(fromIndex); 7078 event.setToIndex(toIndex); 7079 event.setAction(action); 7080 event.setMovementGranularity(granularity); 7081 mParent.requestSendAccessibilityEvent(this, event); 7082 } 7083 7084 /** 7085 * @hide 7086 */ 7087 public TextSegmentIterator getIteratorForGranularity(int granularity) { 7088 switch (granularity) { 7089 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 7090 CharSequence text = getIterableTextForAccessibility(); 7091 if (text != null && text.length() > 0) { 7092 CharacterTextSegmentIterator iterator = 7093 CharacterTextSegmentIterator.getInstance( 7094 mContext.getResources().getConfiguration().locale); 7095 iterator.initialize(text.toString()); 7096 return iterator; 7097 } 7098 } break; 7099 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 7100 CharSequence text = getIterableTextForAccessibility(); 7101 if (text != null && text.length() > 0) { 7102 WordTextSegmentIterator iterator = 7103 WordTextSegmentIterator.getInstance( 7104 mContext.getResources().getConfiguration().locale); 7105 iterator.initialize(text.toString()); 7106 return iterator; 7107 } 7108 } break; 7109 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 7110 CharSequence text = getIterableTextForAccessibility(); 7111 if (text != null && text.length() > 0) { 7112 ParagraphTextSegmentIterator iterator = 7113 ParagraphTextSegmentIterator.getInstance(); 7114 iterator.initialize(text.toString()); 7115 return iterator; 7116 } 7117 } break; 7118 } 7119 return null; 7120 } 7121 7122 /** 7123 * @hide 7124 */ 7125 public void dispatchStartTemporaryDetach() { 7126 clearAccessibilityFocus(); 7127 clearDisplayList(); 7128 7129 onStartTemporaryDetach(); 7130 } 7131 7132 /** 7133 * This is called when a container is going to temporarily detach a child, with 7134 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 7135 * It will either be followed by {@link #onFinishTemporaryDetach()} or 7136 * {@link #onDetachedFromWindow()} when the container is done. 7137 */ 7138 public void onStartTemporaryDetach() { 7139 removeUnsetPressCallback(); 7140 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 7141 } 7142 7143 /** 7144 * @hide 7145 */ 7146 public void dispatchFinishTemporaryDetach() { 7147 onFinishTemporaryDetach(); 7148 } 7149 7150 /** 7151 * Called after {@link #onStartTemporaryDetach} when the container is done 7152 * changing the view. 7153 */ 7154 public void onFinishTemporaryDetach() { 7155 } 7156 7157 /** 7158 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 7159 * for this view's window. Returns null if the view is not currently attached 7160 * to the window. Normally you will not need to use this directly, but 7161 * just use the standard high-level event callbacks like 7162 * {@link #onKeyDown(int, KeyEvent)}. 7163 */ 7164 public KeyEvent.DispatcherState getKeyDispatcherState() { 7165 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 7166 } 7167 7168 /** 7169 * Dispatch a key event before it is processed by any input method 7170 * associated with the view hierarchy. This can be used to intercept 7171 * key events in special situations before the IME consumes them; a 7172 * typical example would be handling the BACK key to update the application's 7173 * UI instead of allowing the IME to see it and close itself. 7174 * 7175 * @param event The key event to be dispatched. 7176 * @return True if the event was handled, false otherwise. 7177 */ 7178 public boolean dispatchKeyEventPreIme(KeyEvent event) { 7179 return onKeyPreIme(event.getKeyCode(), event); 7180 } 7181 7182 /** 7183 * Dispatch a key event to the next view on the focus path. This path runs 7184 * from the top of the view tree down to the currently focused view. If this 7185 * view has focus, it will dispatch to itself. Otherwise it will dispatch 7186 * the next node down the focus path. This method also fires any key 7187 * listeners. 7188 * 7189 * @param event The key event to be dispatched. 7190 * @return True if the event was handled, false otherwise. 7191 */ 7192 public boolean dispatchKeyEvent(KeyEvent event) { 7193 if (mInputEventConsistencyVerifier != null) { 7194 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 7195 } 7196 7197 // Give any attached key listener a first crack at the event. 7198 //noinspection SimplifiableIfStatement 7199 ListenerInfo li = mListenerInfo; 7200 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 7201 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 7202 return true; 7203 } 7204 7205 if (event.dispatch(this, mAttachInfo != null 7206 ? mAttachInfo.mKeyDispatchState : null, this)) { 7207 return true; 7208 } 7209 7210 if (mInputEventConsistencyVerifier != null) { 7211 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 7212 } 7213 return false; 7214 } 7215 7216 /** 7217 * Dispatches a key shortcut event. 7218 * 7219 * @param event The key event to be dispatched. 7220 * @return True if the event was handled by the view, false otherwise. 7221 */ 7222 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 7223 return onKeyShortcut(event.getKeyCode(), event); 7224 } 7225 7226 /** 7227 * Pass the touch screen motion event down to the target view, or this 7228 * view if it is the target. 7229 * 7230 * @param event The motion event to be dispatched. 7231 * @return True if the event was handled by the view, false otherwise. 7232 */ 7233 public boolean dispatchTouchEvent(MotionEvent event) { 7234 if (mInputEventConsistencyVerifier != null) { 7235 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 7236 } 7237 7238 if (onFilterTouchEventForSecurity(event)) { 7239 //noinspection SimplifiableIfStatement 7240 ListenerInfo li = mListenerInfo; 7241 if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 7242 && li.mOnTouchListener.onTouch(this, event)) { 7243 return true; 7244 } 7245 7246 if (onTouchEvent(event)) { 7247 return true; 7248 } 7249 } 7250 7251 if (mInputEventConsistencyVerifier != null) { 7252 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 7253 } 7254 return false; 7255 } 7256 7257 /** 7258 * Filter the touch event to apply security policies. 7259 * 7260 * @param event The motion event to be filtered. 7261 * @return True if the event should be dispatched, false if the event should be dropped. 7262 * 7263 * @see #getFilterTouchesWhenObscured 7264 */ 7265 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 7266 //noinspection RedundantIfStatement 7267 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 7268 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 7269 // Window is obscured, drop this touch. 7270 return false; 7271 } 7272 return true; 7273 } 7274 7275 /** 7276 * Pass a trackball motion event down to the focused view. 7277 * 7278 * @param event The motion event to be dispatched. 7279 * @return True if the event was handled by the view, false otherwise. 7280 */ 7281 public boolean dispatchTrackballEvent(MotionEvent event) { 7282 if (mInputEventConsistencyVerifier != null) { 7283 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 7284 } 7285 7286 return onTrackballEvent(event); 7287 } 7288 7289 /** 7290 * Dispatch a generic motion event. 7291 * <p> 7292 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 7293 * are delivered to the view under the pointer. All other generic motion events are 7294 * delivered to the focused view. Hover events are handled specially and are delivered 7295 * to {@link #onHoverEvent(MotionEvent)}. 7296 * </p> 7297 * 7298 * @param event The motion event to be dispatched. 7299 * @return True if the event was handled by the view, false otherwise. 7300 */ 7301 public boolean dispatchGenericMotionEvent(MotionEvent event) { 7302 if (mInputEventConsistencyVerifier != null) { 7303 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 7304 } 7305 7306 final int source = event.getSource(); 7307 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 7308 final int action = event.getAction(); 7309 if (action == MotionEvent.ACTION_HOVER_ENTER 7310 || action == MotionEvent.ACTION_HOVER_MOVE 7311 || action == MotionEvent.ACTION_HOVER_EXIT) { 7312 if (dispatchHoverEvent(event)) { 7313 return true; 7314 } 7315 } else if (dispatchGenericPointerEvent(event)) { 7316 return true; 7317 } 7318 } else if (dispatchGenericFocusedEvent(event)) { 7319 return true; 7320 } 7321 7322 if (dispatchGenericMotionEventInternal(event)) { 7323 return true; 7324 } 7325 7326 if (mInputEventConsistencyVerifier != null) { 7327 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 7328 } 7329 return false; 7330 } 7331 7332 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 7333 //noinspection SimplifiableIfStatement 7334 ListenerInfo li = mListenerInfo; 7335 if (li != null && li.mOnGenericMotionListener != null 7336 && (mViewFlags & ENABLED_MASK) == ENABLED 7337 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 7338 return true; 7339 } 7340 7341 if (onGenericMotionEvent(event)) { 7342 return true; 7343 } 7344 7345 if (mInputEventConsistencyVerifier != null) { 7346 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 7347 } 7348 return false; 7349 } 7350 7351 /** 7352 * Dispatch a hover event. 7353 * <p> 7354 * Do not call this method directly. 7355 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 7356 * </p> 7357 * 7358 * @param event The motion event to be dispatched. 7359 * @return True if the event was handled by the view, false otherwise. 7360 */ 7361 protected boolean dispatchHoverEvent(MotionEvent event) { 7362 //noinspection SimplifiableIfStatement 7363 ListenerInfo li = mListenerInfo; 7364 if (li != null && li.mOnHoverListener != null 7365 && (mViewFlags & ENABLED_MASK) == ENABLED 7366 && li.mOnHoverListener.onHover(this, event)) { 7367 return true; 7368 } 7369 7370 return onHoverEvent(event); 7371 } 7372 7373 /** 7374 * Returns true if the view has a child to which it has recently sent 7375 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 7376 * it does not have a hovered child, then it must be the innermost hovered view. 7377 * @hide 7378 */ 7379 protected boolean hasHoveredChild() { 7380 return false; 7381 } 7382 7383 /** 7384 * Dispatch a generic motion event to the view under the first pointer. 7385 * <p> 7386 * Do not call this method directly. 7387 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 7388 * </p> 7389 * 7390 * @param event The motion event to be dispatched. 7391 * @return True if the event was handled by the view, false otherwise. 7392 */ 7393 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 7394 return false; 7395 } 7396 7397 /** 7398 * Dispatch a generic motion event to the currently focused view. 7399 * <p> 7400 * Do not call this method directly. 7401 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 7402 * </p> 7403 * 7404 * @param event The motion event to be dispatched. 7405 * @return True if the event was handled by the view, false otherwise. 7406 */ 7407 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 7408 return false; 7409 } 7410 7411 /** 7412 * Dispatch a pointer event. 7413 * <p> 7414 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 7415 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 7416 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 7417 * and should not be expected to handle other pointing device features. 7418 * </p> 7419 * 7420 * @param event The motion event to be dispatched. 7421 * @return True if the event was handled by the view, false otherwise. 7422 * @hide 7423 */ 7424 public final boolean dispatchPointerEvent(MotionEvent event) { 7425 if (event.isTouchEvent()) { 7426 return dispatchTouchEvent(event); 7427 } else { 7428 return dispatchGenericMotionEvent(event); 7429 } 7430 } 7431 7432 /** 7433 * Called when the window containing this view gains or loses window focus. 7434 * ViewGroups should override to route to their children. 7435 * 7436 * @param hasFocus True if the window containing this view now has focus, 7437 * false otherwise. 7438 */ 7439 public void dispatchWindowFocusChanged(boolean hasFocus) { 7440 onWindowFocusChanged(hasFocus); 7441 } 7442 7443 /** 7444 * Called when the window containing this view gains or loses focus. Note 7445 * that this is separate from view focus: to receive key events, both 7446 * your view and its window must have focus. If a window is displayed 7447 * on top of yours that takes input focus, then your own window will lose 7448 * focus but the view focus will remain unchanged. 7449 * 7450 * @param hasWindowFocus True if the window containing this view now has 7451 * focus, false otherwise. 7452 */ 7453 public void onWindowFocusChanged(boolean hasWindowFocus) { 7454 InputMethodManager imm = InputMethodManager.peekInstance(); 7455 if (!hasWindowFocus) { 7456 if (isPressed()) { 7457 setPressed(false); 7458 } 7459 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 7460 imm.focusOut(this); 7461 } 7462 removeLongPressCallback(); 7463 removeTapCallback(); 7464 onFocusLost(); 7465 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 7466 imm.focusIn(this); 7467 } 7468 refreshDrawableState(); 7469 } 7470 7471 /** 7472 * Returns true if this view is in a window that currently has window focus. 7473 * Note that this is not the same as the view itself having focus. 7474 * 7475 * @return True if this view is in a window that currently has window focus. 7476 */ 7477 public boolean hasWindowFocus() { 7478 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 7479 } 7480 7481 /** 7482 * Dispatch a view visibility change down the view hierarchy. 7483 * ViewGroups should override to route to their children. 7484 * @param changedView The view whose visibility changed. Could be 'this' or 7485 * an ancestor view. 7486 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 7487 * {@link #INVISIBLE} or {@link #GONE}. 7488 */ 7489 protected void dispatchVisibilityChanged(View changedView, int visibility) { 7490 onVisibilityChanged(changedView, visibility); 7491 } 7492 7493 /** 7494 * Called when the visibility of the view or an ancestor of the view is changed. 7495 * @param changedView The view whose visibility changed. Could be 'this' or 7496 * an ancestor view. 7497 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 7498 * {@link #INVISIBLE} or {@link #GONE}. 7499 */ 7500 protected void onVisibilityChanged(View changedView, int visibility) { 7501 if (visibility == VISIBLE) { 7502 if (mAttachInfo != null) { 7503 initialAwakenScrollBars(); 7504 } else { 7505 mPrivateFlags |= PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH; 7506 } 7507 } 7508 } 7509 7510 /** 7511 * Dispatch a hint about whether this view is displayed. For instance, when 7512 * a View moves out of the screen, it might receives a display hint indicating 7513 * the view is not displayed. Applications should not <em>rely</em> on this hint 7514 * as there is no guarantee that they will receive one. 7515 * 7516 * @param hint A hint about whether or not this view is displayed: 7517 * {@link #VISIBLE} or {@link #INVISIBLE}. 7518 */ 7519 public void dispatchDisplayHint(int hint) { 7520 onDisplayHint(hint); 7521 } 7522 7523 /** 7524 * Gives this view a hint about whether is displayed or not. For instance, when 7525 * a View moves out of the screen, it might receives a display hint indicating 7526 * the view is not displayed. Applications should not <em>rely</em> on this hint 7527 * as there is no guarantee that they will receive one. 7528 * 7529 * @param hint A hint about whether or not this view is displayed: 7530 * {@link #VISIBLE} or {@link #INVISIBLE}. 7531 */ 7532 protected void onDisplayHint(int hint) { 7533 } 7534 7535 /** 7536 * Dispatch a window visibility change down the view hierarchy. 7537 * ViewGroups should override to route to their children. 7538 * 7539 * @param visibility The new visibility of the window. 7540 * 7541 * @see #onWindowVisibilityChanged(int) 7542 */ 7543 public void dispatchWindowVisibilityChanged(int visibility) { 7544 onWindowVisibilityChanged(visibility); 7545 } 7546 7547 /** 7548 * Called when the window containing has change its visibility 7549 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 7550 * that this tells you whether or not your window is being made visible 7551 * to the window manager; this does <em>not</em> tell you whether or not 7552 * your window is obscured by other windows on the screen, even if it 7553 * is itself visible. 7554 * 7555 * @param visibility The new visibility of the window. 7556 */ 7557 protected void onWindowVisibilityChanged(int visibility) { 7558 if (visibility == VISIBLE) { 7559 initialAwakenScrollBars(); 7560 } 7561 } 7562 7563 /** 7564 * Returns the current visibility of the window this view is attached to 7565 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 7566 * 7567 * @return Returns the current visibility of the view's window. 7568 */ 7569 public int getWindowVisibility() { 7570 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 7571 } 7572 7573 /** 7574 * Retrieve the overall visible display size in which the window this view is 7575 * attached to has been positioned in. This takes into account screen 7576 * decorations above the window, for both cases where the window itself 7577 * is being position inside of them or the window is being placed under 7578 * then and covered insets are used for the window to position its content 7579 * inside. In effect, this tells you the available area where content can 7580 * be placed and remain visible to users. 7581 * 7582 * <p>This function requires an IPC back to the window manager to retrieve 7583 * the requested information, so should not be used in performance critical 7584 * code like drawing. 7585 * 7586 * @param outRect Filled in with the visible display frame. If the view 7587 * is not attached to a window, this is simply the raw display size. 7588 */ 7589 public void getWindowVisibleDisplayFrame(Rect outRect) { 7590 if (mAttachInfo != null) { 7591 try { 7592 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 7593 } catch (RemoteException e) { 7594 return; 7595 } 7596 // XXX This is really broken, and probably all needs to be done 7597 // in the window manager, and we need to know more about whether 7598 // we want the area behind or in front of the IME. 7599 final Rect insets = mAttachInfo.mVisibleInsets; 7600 outRect.left += insets.left; 7601 outRect.top += insets.top; 7602 outRect.right -= insets.right; 7603 outRect.bottom -= insets.bottom; 7604 return; 7605 } 7606 // The view is not attached to a display so we don't have a context. 7607 // Make a best guess about the display size. 7608 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 7609 d.getRectSize(outRect); 7610 } 7611 7612 /** 7613 * Dispatch a notification about a resource configuration change down 7614 * the view hierarchy. 7615 * ViewGroups should override to route to their children. 7616 * 7617 * @param newConfig The new resource configuration. 7618 * 7619 * @see #onConfigurationChanged(android.content.res.Configuration) 7620 */ 7621 public void dispatchConfigurationChanged(Configuration newConfig) { 7622 onConfigurationChanged(newConfig); 7623 } 7624 7625 /** 7626 * Called when the current configuration of the resources being used 7627 * by the application have changed. You can use this to decide when 7628 * to reload resources that can changed based on orientation and other 7629 * configuration characterstics. You only need to use this if you are 7630 * not relying on the normal {@link android.app.Activity} mechanism of 7631 * recreating the activity instance upon a configuration change. 7632 * 7633 * @param newConfig The new resource configuration. 7634 */ 7635 protected void onConfigurationChanged(Configuration newConfig) { 7636 } 7637 7638 /** 7639 * Private function to aggregate all per-view attributes in to the view 7640 * root. 7641 */ 7642 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 7643 performCollectViewAttributes(attachInfo, visibility); 7644 } 7645 7646 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 7647 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 7648 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 7649 attachInfo.mKeepScreenOn = true; 7650 } 7651 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 7652 ListenerInfo li = mListenerInfo; 7653 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 7654 attachInfo.mHasSystemUiListeners = true; 7655 } 7656 } 7657 } 7658 7659 void needGlobalAttributesUpdate(boolean force) { 7660 final AttachInfo ai = mAttachInfo; 7661 if (ai != null && !ai.mRecomputeGlobalAttributes) { 7662 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 7663 || ai.mHasSystemUiListeners) { 7664 ai.mRecomputeGlobalAttributes = true; 7665 } 7666 } 7667 } 7668 7669 /** 7670 * Returns whether the device is currently in touch mode. Touch mode is entered 7671 * once the user begins interacting with the device by touch, and affects various 7672 * things like whether focus is always visible to the user. 7673 * 7674 * @return Whether the device is in touch mode. 7675 */ 7676 @ViewDebug.ExportedProperty 7677 public boolean isInTouchMode() { 7678 if (mAttachInfo != null) { 7679 return mAttachInfo.mInTouchMode; 7680 } else { 7681 return ViewRootImpl.isInTouchMode(); 7682 } 7683 } 7684 7685 /** 7686 * Returns the context the view is running in, through which it can 7687 * access the current theme, resources, etc. 7688 * 7689 * @return The view's Context. 7690 */ 7691 @ViewDebug.CapturedViewProperty 7692 public final Context getContext() { 7693 return mContext; 7694 } 7695 7696 /** 7697 * Handle a key event before it is processed by any input method 7698 * associated with the view hierarchy. This can be used to intercept 7699 * key events in special situations before the IME consumes them; a 7700 * typical example would be handling the BACK key to update the application's 7701 * UI instead of allowing the IME to see it and close itself. 7702 * 7703 * @param keyCode The value in event.getKeyCode(). 7704 * @param event Description of the key event. 7705 * @return If you handled the event, return true. If you want to allow the 7706 * event to be handled by the next receiver, return false. 7707 */ 7708 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 7709 return false; 7710 } 7711 7712 /** 7713 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 7714 * KeyEvent.Callback.onKeyDown()}: perform press of the view 7715 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 7716 * is released, if the view is enabled and clickable. 7717 * 7718 * <p>Key presses in software keyboards will generally NOT trigger this listener, 7719 * although some may elect to do so in some situations. Do not rely on this to 7720 * catch software key presses. 7721 * 7722 * @param keyCode A key code that represents the button pressed, from 7723 * {@link android.view.KeyEvent}. 7724 * @param event The KeyEvent object that defines the button action. 7725 */ 7726 public boolean onKeyDown(int keyCode, KeyEvent event) { 7727 boolean result = false; 7728 7729 switch (keyCode) { 7730 case KeyEvent.KEYCODE_DPAD_CENTER: 7731 case KeyEvent.KEYCODE_ENTER: { 7732 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 7733 return true; 7734 } 7735 // Long clickable items don't necessarily have to be clickable 7736 if (((mViewFlags & CLICKABLE) == CLICKABLE || 7737 (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) && 7738 (event.getRepeatCount() == 0)) { 7739 setPressed(true); 7740 checkForLongClick(0); 7741 return true; 7742 } 7743 break; 7744 } 7745 } 7746 return result; 7747 } 7748 7749 /** 7750 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 7751 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 7752 * the event). 7753 * <p>Key presses in software keyboards will generally NOT trigger this listener, 7754 * although some may elect to do so in some situations. Do not rely on this to 7755 * catch software key presses. 7756 */ 7757 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 7758 return false; 7759 } 7760 7761 /** 7762 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 7763 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 7764 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or 7765 * {@link KeyEvent#KEYCODE_ENTER} is released. 7766 * <p>Key presses in software keyboards will generally NOT trigger this listener, 7767 * although some may elect to do so in some situations. Do not rely on this to 7768 * catch software key presses. 7769 * 7770 * @param keyCode A key code that represents the button pressed, from 7771 * {@link android.view.KeyEvent}. 7772 * @param event The KeyEvent object that defines the button action. 7773 */ 7774 public boolean onKeyUp(int keyCode, KeyEvent event) { 7775 boolean result = false; 7776 7777 switch (keyCode) { 7778 case KeyEvent.KEYCODE_DPAD_CENTER: 7779 case KeyEvent.KEYCODE_ENTER: { 7780 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 7781 return true; 7782 } 7783 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 7784 setPressed(false); 7785 7786 if (!mHasPerformedLongPress) { 7787 // This is a tap, so remove the longpress check 7788 removeLongPressCallback(); 7789 7790 result = performClick(); 7791 } 7792 } 7793 break; 7794 } 7795 } 7796 return result; 7797 } 7798 7799 /** 7800 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 7801 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 7802 * the event). 7803 * <p>Key presses in software keyboards will generally NOT trigger this listener, 7804 * although some may elect to do so in some situations. Do not rely on this to 7805 * catch software key presses. 7806 * 7807 * @param keyCode A key code that represents the button pressed, from 7808 * {@link android.view.KeyEvent}. 7809 * @param repeatCount The number of times the action was made. 7810 * @param event The KeyEvent object that defines the button action. 7811 */ 7812 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 7813 return false; 7814 } 7815 7816 /** 7817 * Called on the focused view when a key shortcut event is not handled. 7818 * Override this method to implement local key shortcuts for the View. 7819 * Key shortcuts can also be implemented by setting the 7820 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 7821 * 7822 * @param keyCode The value in event.getKeyCode(). 7823 * @param event Description of the key event. 7824 * @return If you handled the event, return true. If you want to allow the 7825 * event to be handled by the next receiver, return false. 7826 */ 7827 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 7828 return false; 7829 } 7830 7831 /** 7832 * Check whether the called view is a text editor, in which case it 7833 * would make sense to automatically display a soft input window for 7834 * it. Subclasses should override this if they implement 7835 * {@link #onCreateInputConnection(EditorInfo)} to return true if 7836 * a call on that method would return a non-null InputConnection, and 7837 * they are really a first-class editor that the user would normally 7838 * start typing on when the go into a window containing your view. 7839 * 7840 * <p>The default implementation always returns false. This does 7841 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 7842 * will not be called or the user can not otherwise perform edits on your 7843 * view; it is just a hint to the system that this is not the primary 7844 * purpose of this view. 7845 * 7846 * @return Returns true if this view is a text editor, else false. 7847 */ 7848 public boolean onCheckIsTextEditor() { 7849 return false; 7850 } 7851 7852 /** 7853 * Create a new InputConnection for an InputMethod to interact 7854 * with the view. The default implementation returns null, since it doesn't 7855 * support input methods. You can override this to implement such support. 7856 * This is only needed for views that take focus and text input. 7857 * 7858 * <p>When implementing this, you probably also want to implement 7859 * {@link #onCheckIsTextEditor()} to indicate you will return a 7860 * non-null InputConnection. 7861 * 7862 * @param outAttrs Fill in with attribute information about the connection. 7863 */ 7864 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 7865 return null; 7866 } 7867 7868 /** 7869 * Called by the {@link android.view.inputmethod.InputMethodManager} 7870 * when a view who is not the current 7871 * input connection target is trying to make a call on the manager. The 7872 * default implementation returns false; you can override this to return 7873 * true for certain views if you are performing InputConnection proxying 7874 * to them. 7875 * @param view The View that is making the InputMethodManager call. 7876 * @return Return true to allow the call, false to reject. 7877 */ 7878 public boolean checkInputConnectionProxy(View view) { 7879 return false; 7880 } 7881 7882 /** 7883 * Show the context menu for this view. It is not safe to hold on to the 7884 * menu after returning from this method. 7885 * 7886 * You should normally not overload this method. Overload 7887 * {@link #onCreateContextMenu(ContextMenu)} or define an 7888 * {@link OnCreateContextMenuListener} to add items to the context menu. 7889 * 7890 * @param menu The context menu to populate 7891 */ 7892 public void createContextMenu(ContextMenu menu) { 7893 ContextMenuInfo menuInfo = getContextMenuInfo(); 7894 7895 // Sets the current menu info so all items added to menu will have 7896 // my extra info set. 7897 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 7898 7899 onCreateContextMenu(menu); 7900 ListenerInfo li = mListenerInfo; 7901 if (li != null && li.mOnCreateContextMenuListener != null) { 7902 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 7903 } 7904 7905 // Clear the extra information so subsequent items that aren't mine don't 7906 // have my extra info. 7907 ((MenuBuilder)menu).setCurrentMenuInfo(null); 7908 7909 if (mParent != null) { 7910 mParent.createContextMenu(menu); 7911 } 7912 } 7913 7914 /** 7915 * Views should implement this if they have extra information to associate 7916 * with the context menu. The return result is supplied as a parameter to 7917 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 7918 * callback. 7919 * 7920 * @return Extra information about the item for which the context menu 7921 * should be shown. This information will vary across different 7922 * subclasses of View. 7923 */ 7924 protected ContextMenuInfo getContextMenuInfo() { 7925 return null; 7926 } 7927 7928 /** 7929 * Views should implement this if the view itself is going to add items to 7930 * the context menu. 7931 * 7932 * @param menu the context menu to populate 7933 */ 7934 protected void onCreateContextMenu(ContextMenu menu) { 7935 } 7936 7937 /** 7938 * Implement this method to handle trackball motion events. The 7939 * <em>relative</em> movement of the trackball since the last event 7940 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 7941 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 7942 * that a movement of 1 corresponds to the user pressing one DPAD key (so 7943 * they will often be fractional values, representing the more fine-grained 7944 * movement information available from a trackball). 7945 * 7946 * @param event The motion event. 7947 * @return True if the event was handled, false otherwise. 7948 */ 7949 public boolean onTrackballEvent(MotionEvent event) { 7950 return false; 7951 } 7952 7953 /** 7954 * Implement this method to handle generic motion events. 7955 * <p> 7956 * Generic motion events describe joystick movements, mouse hovers, track pad 7957 * touches, scroll wheel movements and other input events. The 7958 * {@link MotionEvent#getSource() source} of the motion event specifies 7959 * the class of input that was received. Implementations of this method 7960 * must examine the bits in the source before processing the event. 7961 * The following code example shows how this is done. 7962 * </p><p> 7963 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 7964 * are delivered to the view under the pointer. All other generic motion events are 7965 * delivered to the focused view. 7966 * </p> 7967 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 7968 * if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 7969 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 7970 * // process the joystick movement... 7971 * return true; 7972 * } 7973 * } 7974 * if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { 7975 * switch (event.getAction()) { 7976 * case MotionEvent.ACTION_HOVER_MOVE: 7977 * // process the mouse hover movement... 7978 * return true; 7979 * case MotionEvent.ACTION_SCROLL: 7980 * // process the scroll wheel movement... 7981 * return true; 7982 * } 7983 * } 7984 * return super.onGenericMotionEvent(event); 7985 * }</pre> 7986 * 7987 * @param event The generic motion event being processed. 7988 * @return True if the event was handled, false otherwise. 7989 */ 7990 public boolean onGenericMotionEvent(MotionEvent event) { 7991 return false; 7992 } 7993 7994 /** 7995 * Implement this method to handle hover events. 7996 * <p> 7997 * This method is called whenever a pointer is hovering into, over, or out of the 7998 * bounds of a view and the view is not currently being touched. 7999 * Hover events are represented as pointer events with action 8000 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 8001 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 8002 * </p> 8003 * <ul> 8004 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 8005 * when the pointer enters the bounds of the view.</li> 8006 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 8007 * when the pointer has already entered the bounds of the view and has moved.</li> 8008 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 8009 * when the pointer has exited the bounds of the view or when the pointer is 8010 * about to go down due to a button click, tap, or similar user action that 8011 * causes the view to be touched.</li> 8012 * </ul> 8013 * <p> 8014 * The view should implement this method to return true to indicate that it is 8015 * handling the hover event, such as by changing its drawable state. 8016 * </p><p> 8017 * The default implementation calls {@link #setHovered} to update the hovered state 8018 * of the view when a hover enter or hover exit event is received, if the view 8019 * is enabled and is clickable. The default implementation also sends hover 8020 * accessibility events. 8021 * </p> 8022 * 8023 * @param event The motion event that describes the hover. 8024 * @return True if the view handled the hover event. 8025 * 8026 * @see #isHovered 8027 * @see #setHovered 8028 * @see #onHoverChanged 8029 */ 8030 public boolean onHoverEvent(MotionEvent event) { 8031 // The root view may receive hover (or touch) events that are outside the bounds of 8032 // the window. This code ensures that we only send accessibility events for 8033 // hovers that are actually within the bounds of the root view. 8034 final int action = event.getActionMasked(); 8035 if (!mSendingHoverAccessibilityEvents) { 8036 if ((action == MotionEvent.ACTION_HOVER_ENTER 8037 || action == MotionEvent.ACTION_HOVER_MOVE) 8038 && !hasHoveredChild() 8039 && pointInView(event.getX(), event.getY())) { 8040 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 8041 mSendingHoverAccessibilityEvents = true; 8042 } 8043 } else { 8044 if (action == MotionEvent.ACTION_HOVER_EXIT 8045 || (action == MotionEvent.ACTION_MOVE 8046 && !pointInView(event.getX(), event.getY()))) { 8047 mSendingHoverAccessibilityEvents = false; 8048 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 8049 // If the window does not have input focus we take away accessibility 8050 // focus as soon as the user stop hovering over the view. 8051 if (mAttachInfo != null && !mAttachInfo.mHasWindowFocus) { 8052 getViewRootImpl().setAccessibilityFocus(null, null); 8053 } 8054 } 8055 } 8056 8057 if (isHoverable()) { 8058 switch (action) { 8059 case MotionEvent.ACTION_HOVER_ENTER: 8060 setHovered(true); 8061 break; 8062 case MotionEvent.ACTION_HOVER_EXIT: 8063 setHovered(false); 8064 break; 8065 } 8066 8067 // Dispatch the event to onGenericMotionEvent before returning true. 8068 // This is to provide compatibility with existing applications that 8069 // handled HOVER_MOVE events in onGenericMotionEvent and that would 8070 // break because of the new default handling for hoverable views 8071 // in onHoverEvent. 8072 // Note that onGenericMotionEvent will be called by default when 8073 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 8074 dispatchGenericMotionEventInternal(event); 8075 return true; 8076 } 8077 8078 return false; 8079 } 8080 8081 /** 8082 * Returns true if the view should handle {@link #onHoverEvent} 8083 * by calling {@link #setHovered} to change its hovered state. 8084 * 8085 * @return True if the view is hoverable. 8086 */ 8087 private boolean isHoverable() { 8088 final int viewFlags = mViewFlags; 8089 if ((viewFlags & ENABLED_MASK) == DISABLED) { 8090 return false; 8091 } 8092 8093 return (viewFlags & CLICKABLE) == CLICKABLE 8094 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 8095 } 8096 8097 /** 8098 * Returns true if the view is currently hovered. 8099 * 8100 * @return True if the view is currently hovered. 8101 * 8102 * @see #setHovered 8103 * @see #onHoverChanged 8104 */ 8105 @ViewDebug.ExportedProperty 8106 public boolean isHovered() { 8107 return (mPrivateFlags & PFLAG_HOVERED) != 0; 8108 } 8109 8110 /** 8111 * Sets whether the view is currently hovered. 8112 * <p> 8113 * Calling this method also changes the drawable state of the view. This 8114 * enables the view to react to hover by using different drawable resources 8115 * to change its appearance. 8116 * </p><p> 8117 * The {@link #onHoverChanged} method is called when the hovered state changes. 8118 * </p> 8119 * 8120 * @param hovered True if the view is hovered. 8121 * 8122 * @see #isHovered 8123 * @see #onHoverChanged 8124 */ 8125 public void setHovered(boolean hovered) { 8126 if (hovered) { 8127 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 8128 mPrivateFlags |= PFLAG_HOVERED; 8129 refreshDrawableState(); 8130 onHoverChanged(true); 8131 } 8132 } else { 8133 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 8134 mPrivateFlags &= ~PFLAG_HOVERED; 8135 refreshDrawableState(); 8136 onHoverChanged(false); 8137 } 8138 } 8139 } 8140 8141 /** 8142 * Implement this method to handle hover state changes. 8143 * <p> 8144 * This method is called whenever the hover state changes as a result of a 8145 * call to {@link #setHovered}. 8146 * </p> 8147 * 8148 * @param hovered The current hover state, as returned by {@link #isHovered}. 8149 * 8150 * @see #isHovered 8151 * @see #setHovered 8152 */ 8153 public void onHoverChanged(boolean hovered) { 8154 } 8155 8156 /** 8157 * Implement this method to handle touch screen motion events. 8158 * 8159 * @param event The motion event. 8160 * @return True if the event was handled, false otherwise. 8161 */ 8162 public boolean onTouchEvent(MotionEvent event) { 8163 final int viewFlags = mViewFlags; 8164 8165 if ((viewFlags & ENABLED_MASK) == DISABLED) { 8166 if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 8167 setPressed(false); 8168 } 8169 // A disabled view that is clickable still consumes the touch 8170 // events, it just doesn't respond to them. 8171 return (((viewFlags & CLICKABLE) == CLICKABLE || 8172 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); 8173 } 8174 8175 if (mTouchDelegate != null) { 8176 if (mTouchDelegate.onTouchEvent(event)) { 8177 return true; 8178 } 8179 } 8180 8181 if (((viewFlags & CLICKABLE) == CLICKABLE || 8182 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { 8183 switch (event.getAction()) { 8184 case MotionEvent.ACTION_UP: 8185 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 8186 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 8187 // take focus if we don't have it already and we should in 8188 // touch mode. 8189 boolean focusTaken = false; 8190 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 8191 focusTaken = requestFocus(); 8192 } 8193 8194 if (prepressed) { 8195 // The button is being released before we actually 8196 // showed it as pressed. Make it show the pressed 8197 // state now (before scheduling the click) to ensure 8198 // the user sees it. 8199 setPressed(true); 8200 } 8201 8202 if (!mHasPerformedLongPress) { 8203 // This is a tap, so remove the longpress check 8204 removeLongPressCallback(); 8205 8206 // Only perform take click actions if we were in the pressed state 8207 if (!focusTaken) { 8208 // Use a Runnable and post this rather than calling 8209 // performClick directly. This lets other visual state 8210 // of the view update before click actions start. 8211 if (mPerformClick == null) { 8212 mPerformClick = new PerformClick(); 8213 } 8214 if (!post(mPerformClick)) { 8215 performClick(); 8216 } 8217 } 8218 } 8219 8220 if (mUnsetPressedState == null) { 8221 mUnsetPressedState = new UnsetPressedState(); 8222 } 8223 8224 if (prepressed) { 8225 postDelayed(mUnsetPressedState, 8226 ViewConfiguration.getPressedStateDuration()); 8227 } else if (!post(mUnsetPressedState)) { 8228 // If the post failed, unpress right now 8229 mUnsetPressedState.run(); 8230 } 8231 removeTapCallback(); 8232 } 8233 break; 8234 8235 case MotionEvent.ACTION_DOWN: 8236 mHasPerformedLongPress = false; 8237 8238 if (performButtonActionOnTouchDown(event)) { 8239 break; 8240 } 8241 8242 // Walk up the hierarchy to determine if we're inside a scrolling container. 8243 boolean isInScrollingContainer = isInScrollingContainer(); 8244 8245 // For views inside a scrolling container, delay the pressed feedback for 8246 // a short period in case this is a scroll. 8247 if (isInScrollingContainer) { 8248 mPrivateFlags |= PFLAG_PREPRESSED; 8249 if (mPendingCheckForTap == null) { 8250 mPendingCheckForTap = new CheckForTap(); 8251 } 8252 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 8253 } else { 8254 // Not inside a scrolling container, so show the feedback right away 8255 setPressed(true); 8256 checkForLongClick(0); 8257 } 8258 break; 8259 8260 case MotionEvent.ACTION_CANCEL: 8261 setPressed(false); 8262 removeTapCallback(); 8263 removeLongPressCallback(); 8264 break; 8265 8266 case MotionEvent.ACTION_MOVE: 8267 final int x = (int) event.getX(); 8268 final int y = (int) event.getY(); 8269 8270 // Be lenient about moving outside of buttons 8271 if (!pointInView(x, y, mTouchSlop)) { 8272 // Outside button 8273 removeTapCallback(); 8274 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 8275 // Remove any future long press/tap checks 8276 removeLongPressCallback(); 8277 8278 setPressed(false); 8279 } 8280 } 8281 break; 8282 } 8283 return true; 8284 } 8285 8286 return false; 8287 } 8288 8289 /** 8290 * @hide 8291 */ 8292 public boolean isInScrollingContainer() { 8293 ViewParent p = getParent(); 8294 while (p != null && p instanceof ViewGroup) { 8295 if (((ViewGroup) p).shouldDelayChildPressedState()) { 8296 return true; 8297 } 8298 p = p.getParent(); 8299 } 8300 return false; 8301 } 8302 8303 /** 8304 * Remove the longpress detection timer. 8305 */ 8306 private void removeLongPressCallback() { 8307 if (mPendingCheckForLongPress != null) { 8308 removeCallbacks(mPendingCheckForLongPress); 8309 } 8310 } 8311 8312 /** 8313 * Remove the pending click action 8314 */ 8315 private void removePerformClickCallback() { 8316 if (mPerformClick != null) { 8317 removeCallbacks(mPerformClick); 8318 } 8319 } 8320 8321 /** 8322 * Remove the prepress detection timer. 8323 */ 8324 private void removeUnsetPressCallback() { 8325 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 8326 setPressed(false); 8327 removeCallbacks(mUnsetPressedState); 8328 } 8329 } 8330 8331 /** 8332 * Remove the tap detection timer. 8333 */ 8334 private void removeTapCallback() { 8335 if (mPendingCheckForTap != null) { 8336 mPrivateFlags &= ~PFLAG_PREPRESSED; 8337 removeCallbacks(mPendingCheckForTap); 8338 } 8339 } 8340 8341 /** 8342 * Cancels a pending long press. Your subclass can use this if you 8343 * want the context menu to come up if the user presses and holds 8344 * at the same place, but you don't want it to come up if they press 8345 * and then move around enough to cause scrolling. 8346 */ 8347 public void cancelLongPress() { 8348 removeLongPressCallback(); 8349 8350 /* 8351 * The prepressed state handled by the tap callback is a display 8352 * construct, but the tap callback will post a long press callback 8353 * less its own timeout. Remove it here. 8354 */ 8355 removeTapCallback(); 8356 } 8357 8358 /** 8359 * Remove the pending callback for sending a 8360 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 8361 */ 8362 private void removeSendViewScrolledAccessibilityEventCallback() { 8363 if (mSendViewScrolledAccessibilityEvent != null) { 8364 removeCallbacks(mSendViewScrolledAccessibilityEvent); 8365 mSendViewScrolledAccessibilityEvent.mIsPending = false; 8366 } 8367 } 8368 8369 /** 8370 * Sets the TouchDelegate for this View. 8371 */ 8372 public void setTouchDelegate(TouchDelegate delegate) { 8373 mTouchDelegate = delegate; 8374 } 8375 8376 /** 8377 * Gets the TouchDelegate for this View. 8378 */ 8379 public TouchDelegate getTouchDelegate() { 8380 return mTouchDelegate; 8381 } 8382 8383 /** 8384 * Set flags controlling behavior of this view. 8385 * 8386 * @param flags Constant indicating the value which should be set 8387 * @param mask Constant indicating the bit range that should be changed 8388 */ 8389 void setFlags(int flags, int mask) { 8390 int old = mViewFlags; 8391 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 8392 8393 int changed = mViewFlags ^ old; 8394 if (changed == 0) { 8395 return; 8396 } 8397 int privateFlags = mPrivateFlags; 8398 8399 /* Check if the FOCUSABLE bit has changed */ 8400 if (((changed & FOCUSABLE_MASK) != 0) && 8401 ((privateFlags & PFLAG_HAS_BOUNDS) !=0)) { 8402 if (((old & FOCUSABLE_MASK) == FOCUSABLE) 8403 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 8404 /* Give up focus if we are no longer focusable */ 8405 clearFocus(); 8406 } else if (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE) 8407 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 8408 /* 8409 * Tell the view system that we are now available to take focus 8410 * if no one else already has it. 8411 */ 8412 if (mParent != null) mParent.focusableViewAvailable(this); 8413 } 8414 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 8415 notifyAccessibilityStateChanged(); 8416 } 8417 } 8418 8419 if ((flags & VISIBILITY_MASK) == VISIBLE) { 8420 if ((changed & VISIBILITY_MASK) != 0) { 8421 /* 8422 * If this view is becoming visible, invalidate it in case it changed while 8423 * it was not visible. Marking it drawn ensures that the invalidation will 8424 * go through. 8425 */ 8426 mPrivateFlags |= PFLAG_DRAWN; 8427 invalidate(true); 8428 8429 needGlobalAttributesUpdate(true); 8430 8431 // a view becoming visible is worth notifying the parent 8432 // about in case nothing has focus. even if this specific view 8433 // isn't focusable, it may contain something that is, so let 8434 // the root view try to give this focus if nothing else does. 8435 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 8436 mParent.focusableViewAvailable(this); 8437 } 8438 } 8439 } 8440 8441 /* Check if the GONE bit has changed */ 8442 if ((changed & GONE) != 0) { 8443 needGlobalAttributesUpdate(false); 8444 requestLayout(); 8445 8446 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 8447 if (hasFocus()) clearFocus(); 8448 clearAccessibilityFocus(); 8449 destroyDrawingCache(); 8450 if (mParent instanceof View) { 8451 // GONE views noop invalidation, so invalidate the parent 8452 ((View) mParent).invalidate(true); 8453 } 8454 // Mark the view drawn to ensure that it gets invalidated properly the next 8455 // time it is visible and gets invalidated 8456 mPrivateFlags |= PFLAG_DRAWN; 8457 } 8458 if (mAttachInfo != null) { 8459 mAttachInfo.mViewVisibilityChanged = true; 8460 } 8461 } 8462 8463 /* Check if the VISIBLE bit has changed */ 8464 if ((changed & INVISIBLE) != 0) { 8465 needGlobalAttributesUpdate(false); 8466 /* 8467 * If this view is becoming invisible, set the DRAWN flag so that 8468 * the next invalidate() will not be skipped. 8469 */ 8470 mPrivateFlags |= PFLAG_DRAWN; 8471 8472 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE) && hasFocus()) { 8473 // root view becoming invisible shouldn't clear focus and accessibility focus 8474 if (getRootView() != this) { 8475 clearFocus(); 8476 clearAccessibilityFocus(); 8477 } 8478 } 8479 if (mAttachInfo != null) { 8480 mAttachInfo.mViewVisibilityChanged = true; 8481 } 8482 } 8483 8484 if ((changed & VISIBILITY_MASK) != 0) { 8485 if (mParent instanceof ViewGroup) { 8486 ((ViewGroup) mParent).onChildVisibilityChanged(this, 8487 (changed & VISIBILITY_MASK), (flags & VISIBILITY_MASK)); 8488 ((View) mParent).invalidate(true); 8489 } else if (mParent != null) { 8490 mParent.invalidateChild(this, null); 8491 } 8492 dispatchVisibilityChanged(this, (flags & VISIBILITY_MASK)); 8493 } 8494 8495 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 8496 destroyDrawingCache(); 8497 } 8498 8499 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 8500 destroyDrawingCache(); 8501 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 8502 invalidateParentCaches(); 8503 } 8504 8505 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 8506 destroyDrawingCache(); 8507 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 8508 } 8509 8510 if ((changed & DRAW_MASK) != 0) { 8511 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 8512 if (mBackground != null) { 8513 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 8514 mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND; 8515 } else { 8516 mPrivateFlags |= PFLAG_SKIP_DRAW; 8517 } 8518 } else { 8519 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 8520 } 8521 requestLayout(); 8522 invalidate(true); 8523 } 8524 8525 if ((changed & KEEP_SCREEN_ON) != 0) { 8526 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 8527 mParent.recomputeViewAttributes(this); 8528 } 8529 } 8530 8531 if (AccessibilityManager.getInstance(mContext).isEnabled() 8532 && ((changed & FOCUSABLE) != 0 || (changed & CLICKABLE) != 0 8533 || (changed & LONG_CLICKABLE) != 0 || (changed & ENABLED) != 0)) { 8534 notifyAccessibilityStateChanged(); 8535 } 8536 } 8537 8538 /** 8539 * Change the view's z order in the tree, so it's on top of other sibling 8540 * views 8541 */ 8542 public void bringToFront() { 8543 if (mParent != null) { 8544 mParent.bringChildToFront(this); 8545 } 8546 } 8547 8548 /** 8549 * This is called in response to an internal scroll in this view (i.e., the 8550 * view scrolled its own contents). This is typically as a result of 8551 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 8552 * called. 8553 * 8554 * @param l Current horizontal scroll origin. 8555 * @param t Current vertical scroll origin. 8556 * @param oldl Previous horizontal scroll origin. 8557 * @param oldt Previous vertical scroll origin. 8558 */ 8559 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 8560 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 8561 postSendViewScrolledAccessibilityEventCallback(); 8562 } 8563 8564 mBackgroundSizeChanged = true; 8565 8566 final AttachInfo ai = mAttachInfo; 8567 if (ai != null) { 8568 ai.mViewScrollChanged = true; 8569 } 8570 } 8571 8572 /** 8573 * Interface definition for a callback to be invoked when the layout bounds of a view 8574 * changes due to layout processing. 8575 */ 8576 public interface OnLayoutChangeListener { 8577 /** 8578 * Called when the focus state of a view has changed. 8579 * 8580 * @param v The view whose state has changed. 8581 * @param left The new value of the view's left property. 8582 * @param top The new value of the view's top property. 8583 * @param right The new value of the view's right property. 8584 * @param bottom The new value of the view's bottom property. 8585 * @param oldLeft The previous value of the view's left property. 8586 * @param oldTop The previous value of the view's top property. 8587 * @param oldRight The previous value of the view's right property. 8588 * @param oldBottom The previous value of the view's bottom property. 8589 */ 8590 void onLayoutChange(View v, int left, int top, int right, int bottom, 8591 int oldLeft, int oldTop, int oldRight, int oldBottom); 8592 } 8593 8594 /** 8595 * This is called during layout when the size of this view has changed. If 8596 * you were just added to the view hierarchy, you're called with the old 8597 * values of 0. 8598 * 8599 * @param w Current width of this view. 8600 * @param h Current height of this view. 8601 * @param oldw Old width of this view. 8602 * @param oldh Old height of this view. 8603 */ 8604 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 8605 } 8606 8607 /** 8608 * Called by draw to draw the child views. This may be overridden 8609 * by derived classes to gain control just before its children are drawn 8610 * (but after its own view has been drawn). 8611 * @param canvas the canvas on which to draw the view 8612 */ 8613 protected void dispatchDraw(Canvas canvas) { 8614 8615 } 8616 8617 /** 8618 * Gets the parent of this view. Note that the parent is a 8619 * ViewParent and not necessarily a View. 8620 * 8621 * @return Parent of this view. 8622 */ 8623 public final ViewParent getParent() { 8624 return mParent; 8625 } 8626 8627 /** 8628 * Set the horizontal scrolled position of your view. This will cause a call to 8629 * {@link #onScrollChanged(int, int, int, int)} and the view will be 8630 * invalidated. 8631 * @param value the x position to scroll to 8632 */ 8633 public void setScrollX(int value) { 8634 scrollTo(value, mScrollY); 8635 } 8636 8637 /** 8638 * Set the vertical scrolled position of your view. This will cause a call to 8639 * {@link #onScrollChanged(int, int, int, int)} and the view will be 8640 * invalidated. 8641 * @param value the y position to scroll to 8642 */ 8643 public void setScrollY(int value) { 8644 scrollTo(mScrollX, value); 8645 } 8646 8647 /** 8648 * Return the scrolled left position of this view. This is the left edge of 8649 * the displayed part of your view. You do not need to draw any pixels 8650 * farther left, since those are outside of the frame of your view on 8651 * screen. 8652 * 8653 * @return The left edge of the displayed part of your view, in pixels. 8654 */ 8655 public final int getScrollX() { 8656 return mScrollX; 8657 } 8658 8659 /** 8660 * Return the scrolled top position of this view. This is the top edge of 8661 * the displayed part of your view. You do not need to draw any pixels above 8662 * it, since those are outside of the frame of your view on screen. 8663 * 8664 * @return The top edge of the displayed part of your view, in pixels. 8665 */ 8666 public final int getScrollY() { 8667 return mScrollY; 8668 } 8669 8670 /** 8671 * Return the width of the your view. 8672 * 8673 * @return The width of your view, in pixels. 8674 */ 8675 @ViewDebug.ExportedProperty(category = "layout") 8676 public final int getWidth() { 8677 return mRight - mLeft; 8678 } 8679 8680 /** 8681 * Return the height of your view. 8682 * 8683 * @return The height of your view, in pixels. 8684 */ 8685 @ViewDebug.ExportedProperty(category = "layout") 8686 public final int getHeight() { 8687 return mBottom - mTop; 8688 } 8689 8690 /** 8691 * Return the visible drawing bounds of your view. Fills in the output 8692 * rectangle with the values from getScrollX(), getScrollY(), 8693 * getWidth(), and getHeight(). These bounds do not account for any 8694 * transformation properties currently set on the view, such as 8695 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 8696 * 8697 * @param outRect The (scrolled) drawing bounds of the view. 8698 */ 8699 public void getDrawingRect(Rect outRect) { 8700 outRect.left = mScrollX; 8701 outRect.top = mScrollY; 8702 outRect.right = mScrollX + (mRight - mLeft); 8703 outRect.bottom = mScrollY + (mBottom - mTop); 8704 } 8705 8706 /** 8707 * Like {@link #getMeasuredWidthAndState()}, but only returns the 8708 * raw width component (that is the result is masked by 8709 * {@link #MEASURED_SIZE_MASK}). 8710 * 8711 * @return The raw measured width of this view. 8712 */ 8713 public final int getMeasuredWidth() { 8714 return mMeasuredWidth & MEASURED_SIZE_MASK; 8715 } 8716 8717 /** 8718 * Return the full width measurement information for this view as computed 8719 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 8720 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 8721 * This should be used during measurement and layout calculations only. Use 8722 * {@link #getWidth()} to see how wide a view is after layout. 8723 * 8724 * @return The measured width of this view as a bit mask. 8725 */ 8726 public final int getMeasuredWidthAndState() { 8727 return mMeasuredWidth; 8728 } 8729 8730 /** 8731 * Like {@link #getMeasuredHeightAndState()}, but only returns the 8732 * raw width component (that is the result is masked by 8733 * {@link #MEASURED_SIZE_MASK}). 8734 * 8735 * @return The raw measured height of this view. 8736 */ 8737 public final int getMeasuredHeight() { 8738 return mMeasuredHeight & MEASURED_SIZE_MASK; 8739 } 8740 8741 /** 8742 * Return the full height measurement information for this view as computed 8743 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 8744 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 8745 * This should be used during measurement and layout calculations only. Use 8746 * {@link #getHeight()} to see how wide a view is after layout. 8747 * 8748 * @return The measured width of this view as a bit mask. 8749 */ 8750 public final int getMeasuredHeightAndState() { 8751 return mMeasuredHeight; 8752 } 8753 8754 /** 8755 * Return only the state bits of {@link #getMeasuredWidthAndState()} 8756 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 8757 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 8758 * and the height component is at the shifted bits 8759 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 8760 */ 8761 public final int getMeasuredState() { 8762 return (mMeasuredWidth&MEASURED_STATE_MASK) 8763 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 8764 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 8765 } 8766 8767 /** 8768 * The transform matrix of this view, which is calculated based on the current 8769 * roation, scale, and pivot properties. 8770 * 8771 * @see #getRotation() 8772 * @see #getScaleX() 8773 * @see #getScaleY() 8774 * @see #getPivotX() 8775 * @see #getPivotY() 8776 * @return The current transform matrix for the view 8777 */ 8778 public Matrix getMatrix() { 8779 if (mTransformationInfo != null) { 8780 updateMatrix(); 8781 return mTransformationInfo.mMatrix; 8782 } 8783 return Matrix.IDENTITY_MATRIX; 8784 } 8785 8786 /** 8787 * Utility function to determine if the value is far enough away from zero to be 8788 * considered non-zero. 8789 * @param value A floating point value to check for zero-ness 8790 * @return whether the passed-in value is far enough away from zero to be considered non-zero 8791 */ 8792 private static boolean nonzero(float value) { 8793 return (value < -NONZERO_EPSILON || value > NONZERO_EPSILON); 8794 } 8795 8796 /** 8797 * Returns true if the transform matrix is the identity matrix. 8798 * Recomputes the matrix if necessary. 8799 * 8800 * @return True if the transform matrix is the identity matrix, false otherwise. 8801 */ 8802 final boolean hasIdentityMatrix() { 8803 if (mTransformationInfo != null) { 8804 updateMatrix(); 8805 return mTransformationInfo.mMatrixIsIdentity; 8806 } 8807 return true; 8808 } 8809 8810 void ensureTransformationInfo() { 8811 if (mTransformationInfo == null) { 8812 mTransformationInfo = new TransformationInfo(); 8813 } 8814 } 8815 8816 /** 8817 * Recomputes the transform matrix if necessary. 8818 */ 8819 private void updateMatrix() { 8820 final TransformationInfo info = mTransformationInfo; 8821 if (info == null) { 8822 return; 8823 } 8824 if (info.mMatrixDirty) { 8825 // transform-related properties have changed since the last time someone 8826 // asked for the matrix; recalculate it with the current values 8827 8828 // Figure out if we need to update the pivot point 8829 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) { 8830 if ((mRight - mLeft) != info.mPrevWidth || (mBottom - mTop) != info.mPrevHeight) { 8831 info.mPrevWidth = mRight - mLeft; 8832 info.mPrevHeight = mBottom - mTop; 8833 info.mPivotX = info.mPrevWidth / 2f; 8834 info.mPivotY = info.mPrevHeight / 2f; 8835 } 8836 } 8837 info.mMatrix.reset(); 8838 if (!nonzero(info.mRotationX) && !nonzero(info.mRotationY)) { 8839 info.mMatrix.setTranslate(info.mTranslationX, info.mTranslationY); 8840 info.mMatrix.preRotate(info.mRotation, info.mPivotX, info.mPivotY); 8841 info.mMatrix.preScale(info.mScaleX, info.mScaleY, info.mPivotX, info.mPivotY); 8842 } else { 8843 if (info.mCamera == null) { 8844 info.mCamera = new Camera(); 8845 info.matrix3D = new Matrix(); 8846 } 8847 info.mCamera.save(); 8848 info.mMatrix.preScale(info.mScaleX, info.mScaleY, info.mPivotX, info.mPivotY); 8849 info.mCamera.rotate(info.mRotationX, info.mRotationY, -info.mRotation); 8850 info.mCamera.getMatrix(info.matrix3D); 8851 info.matrix3D.preTranslate(-info.mPivotX, -info.mPivotY); 8852 info.matrix3D.postTranslate(info.mPivotX + info.mTranslationX, 8853 info.mPivotY + info.mTranslationY); 8854 info.mMatrix.postConcat(info.matrix3D); 8855 info.mCamera.restore(); 8856 } 8857 info.mMatrixDirty = false; 8858 info.mMatrixIsIdentity = info.mMatrix.isIdentity(); 8859 info.mInverseMatrixDirty = true; 8860 } 8861 } 8862 8863 /** 8864 * Utility method to retrieve the inverse of the current mMatrix property. 8865 * We cache the matrix to avoid recalculating it when transform properties 8866 * have not changed. 8867 * 8868 * @return The inverse of the current matrix of this view. 8869 */ 8870 final Matrix getInverseMatrix() { 8871 final TransformationInfo info = mTransformationInfo; 8872 if (info != null) { 8873 updateMatrix(); 8874 if (info.mInverseMatrixDirty) { 8875 if (info.mInverseMatrix == null) { 8876 info.mInverseMatrix = new Matrix(); 8877 } 8878 info.mMatrix.invert(info.mInverseMatrix); 8879 info.mInverseMatrixDirty = false; 8880 } 8881 return info.mInverseMatrix; 8882 } 8883 return Matrix.IDENTITY_MATRIX; 8884 } 8885 8886 /** 8887 * Gets the distance along the Z axis from the camera to this view. 8888 * 8889 * @see #setCameraDistance(float) 8890 * 8891 * @return The distance along the Z axis. 8892 */ 8893 public float getCameraDistance() { 8894 ensureTransformationInfo(); 8895 final float dpi = mResources.getDisplayMetrics().densityDpi; 8896 final TransformationInfo info = mTransformationInfo; 8897 if (info.mCamera == null) { 8898 info.mCamera = new Camera(); 8899 info.matrix3D = new Matrix(); 8900 } 8901 return -(info.mCamera.getLocationZ() * dpi); 8902 } 8903 8904 /** 8905 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 8906 * views are drawn) from the camera to this view. The camera's distance 8907 * affects 3D transformations, for instance rotations around the X and Y 8908 * axis. If the rotationX or rotationY properties are changed and this view is 8909 * large (more than half the size of the screen), it is recommended to always 8910 * use a camera distance that's greater than the height (X axis rotation) or 8911 * the width (Y axis rotation) of this view.</p> 8912 * 8913 * <p>The distance of the camera from the view plane can have an affect on the 8914 * perspective distortion of the view when it is rotated around the x or y axis. 8915 * For example, a large distance will result in a large viewing angle, and there 8916 * will not be much perspective distortion of the view as it rotates. A short 8917 * distance may cause much more perspective distortion upon rotation, and can 8918 * also result in some drawing artifacts if the rotated view ends up partially 8919 * behind the camera (which is why the recommendation is to use a distance at 8920 * least as far as the size of the view, if the view is to be rotated.)</p> 8921 * 8922 * <p>The distance is expressed in "depth pixels." The default distance depends 8923 * on the screen density. For instance, on a medium density display, the 8924 * default distance is 1280. On a high density display, the default distance 8925 * is 1920.</p> 8926 * 8927 * <p>If you want to specify a distance that leads to visually consistent 8928 * results across various densities, use the following formula:</p> 8929 * <pre> 8930 * float scale = context.getResources().getDisplayMetrics().density; 8931 * view.setCameraDistance(distance * scale); 8932 * </pre> 8933 * 8934 * <p>The density scale factor of a high density display is 1.5, 8935 * and 1920 = 1280 * 1.5.</p> 8936 * 8937 * @param distance The distance in "depth pixels", if negative the opposite 8938 * value is used 8939 * 8940 * @see #setRotationX(float) 8941 * @see #setRotationY(float) 8942 */ 8943 public void setCameraDistance(float distance) { 8944 invalidateViewProperty(true, false); 8945 8946 ensureTransformationInfo(); 8947 final float dpi = mResources.getDisplayMetrics().densityDpi; 8948 final TransformationInfo info = mTransformationInfo; 8949 if (info.mCamera == null) { 8950 info.mCamera = new Camera(); 8951 info.matrix3D = new Matrix(); 8952 } 8953 8954 info.mCamera.setLocation(0.0f, 0.0f, -Math.abs(distance) / dpi); 8955 info.mMatrixDirty = true; 8956 8957 invalidateViewProperty(false, false); 8958 if (mDisplayList != null) { 8959 mDisplayList.setCameraDistance(-Math.abs(distance) / dpi); 8960 } 8961 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 8962 // View was rejected last time it was drawn by its parent; this may have changed 8963 invalidateParentIfNeeded(); 8964 } 8965 } 8966 8967 /** 8968 * The degrees that the view is rotated around the pivot point. 8969 * 8970 * @see #setRotation(float) 8971 * @see #getPivotX() 8972 * @see #getPivotY() 8973 * 8974 * @return The degrees of rotation. 8975 */ 8976 @ViewDebug.ExportedProperty(category = "drawing") 8977 public float getRotation() { 8978 return mTransformationInfo != null ? mTransformationInfo.mRotation : 0; 8979 } 8980 8981 /** 8982 * Sets the degrees that the view is rotated around the pivot point. Increasing values 8983 * result in clockwise rotation. 8984 * 8985 * @param rotation The degrees of rotation. 8986 * 8987 * @see #getRotation() 8988 * @see #getPivotX() 8989 * @see #getPivotY() 8990 * @see #setRotationX(float) 8991 * @see #setRotationY(float) 8992 * 8993 * @attr ref android.R.styleable#View_rotation 8994 */ 8995 public void setRotation(float rotation) { 8996 ensureTransformationInfo(); 8997 final TransformationInfo info = mTransformationInfo; 8998 if (info.mRotation != rotation) { 8999 // Double-invalidation is necessary to capture view's old and new areas 9000 invalidateViewProperty(true, false); 9001 info.mRotation = rotation; 9002 info.mMatrixDirty = true; 9003 invalidateViewProperty(false, true); 9004 if (mDisplayList != null) { 9005 mDisplayList.setRotation(rotation); 9006 } 9007 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9008 // View was rejected last time it was drawn by its parent; this may have changed 9009 invalidateParentIfNeeded(); 9010 } 9011 } 9012 } 9013 9014 /** 9015 * The degrees that the view is rotated around the vertical axis through the pivot point. 9016 * 9017 * @see #getPivotX() 9018 * @see #getPivotY() 9019 * @see #setRotationY(float) 9020 * 9021 * @return The degrees of Y rotation. 9022 */ 9023 @ViewDebug.ExportedProperty(category = "drawing") 9024 public float getRotationY() { 9025 return mTransformationInfo != null ? mTransformationInfo.mRotationY : 0; 9026 } 9027 9028 /** 9029 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 9030 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 9031 * down the y axis. 9032 * 9033 * When rotating large views, it is recommended to adjust the camera distance 9034 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 9035 * 9036 * @param rotationY The degrees of Y rotation. 9037 * 9038 * @see #getRotationY() 9039 * @see #getPivotX() 9040 * @see #getPivotY() 9041 * @see #setRotation(float) 9042 * @see #setRotationX(float) 9043 * @see #setCameraDistance(float) 9044 * 9045 * @attr ref android.R.styleable#View_rotationY 9046 */ 9047 public void setRotationY(float rotationY) { 9048 ensureTransformationInfo(); 9049 final TransformationInfo info = mTransformationInfo; 9050 if (info.mRotationY != rotationY) { 9051 invalidateViewProperty(true, false); 9052 info.mRotationY = rotationY; 9053 info.mMatrixDirty = true; 9054 invalidateViewProperty(false, true); 9055 if (mDisplayList != null) { 9056 mDisplayList.setRotationY(rotationY); 9057 } 9058 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9059 // View was rejected last time it was drawn by its parent; this may have changed 9060 invalidateParentIfNeeded(); 9061 } 9062 } 9063 } 9064 9065 /** 9066 * The degrees that the view is rotated around the horizontal axis through the pivot point. 9067 * 9068 * @see #getPivotX() 9069 * @see #getPivotY() 9070 * @see #setRotationX(float) 9071 * 9072 * @return The degrees of X rotation. 9073 */ 9074 @ViewDebug.ExportedProperty(category = "drawing") 9075 public float getRotationX() { 9076 return mTransformationInfo != null ? mTransformationInfo.mRotationX : 0; 9077 } 9078 9079 /** 9080 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 9081 * Increasing values result in clockwise rotation from the viewpoint of looking down the 9082 * x axis. 9083 * 9084 * When rotating large views, it is recommended to adjust the camera distance 9085 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 9086 * 9087 * @param rotationX The degrees of X rotation. 9088 * 9089 * @see #getRotationX() 9090 * @see #getPivotX() 9091 * @see #getPivotY() 9092 * @see #setRotation(float) 9093 * @see #setRotationY(float) 9094 * @see #setCameraDistance(float) 9095 * 9096 * @attr ref android.R.styleable#View_rotationX 9097 */ 9098 public void setRotationX(float rotationX) { 9099 ensureTransformationInfo(); 9100 final TransformationInfo info = mTransformationInfo; 9101 if (info.mRotationX != rotationX) { 9102 invalidateViewProperty(true, false); 9103 info.mRotationX = rotationX; 9104 info.mMatrixDirty = true; 9105 invalidateViewProperty(false, true); 9106 if (mDisplayList != null) { 9107 mDisplayList.setRotationX(rotationX); 9108 } 9109 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9110 // View was rejected last time it was drawn by its parent; this may have changed 9111 invalidateParentIfNeeded(); 9112 } 9113 } 9114 } 9115 9116 /** 9117 * The amount that the view is scaled in x around the pivot point, as a proportion of 9118 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 9119 * 9120 * <p>By default, this is 1.0f. 9121 * 9122 * @see #getPivotX() 9123 * @see #getPivotY() 9124 * @return The scaling factor. 9125 */ 9126 @ViewDebug.ExportedProperty(category = "drawing") 9127 public float getScaleX() { 9128 return mTransformationInfo != null ? mTransformationInfo.mScaleX : 1; 9129 } 9130 9131 /** 9132 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 9133 * the view's unscaled width. A value of 1 means that no scaling is applied. 9134 * 9135 * @param scaleX The scaling factor. 9136 * @see #getPivotX() 9137 * @see #getPivotY() 9138 * 9139 * @attr ref android.R.styleable#View_scaleX 9140 */ 9141 public void setScaleX(float scaleX) { 9142 ensureTransformationInfo(); 9143 final TransformationInfo info = mTransformationInfo; 9144 if (info.mScaleX != scaleX) { 9145 invalidateViewProperty(true, false); 9146 info.mScaleX = scaleX; 9147 info.mMatrixDirty = true; 9148 invalidateViewProperty(false, true); 9149 if (mDisplayList != null) { 9150 mDisplayList.setScaleX(scaleX); 9151 } 9152 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9153 // View was rejected last time it was drawn by its parent; this may have changed 9154 invalidateParentIfNeeded(); 9155 } 9156 } 9157 } 9158 9159 /** 9160 * The amount that the view is scaled in y around the pivot point, as a proportion of 9161 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 9162 * 9163 * <p>By default, this is 1.0f. 9164 * 9165 * @see #getPivotX() 9166 * @see #getPivotY() 9167 * @return The scaling factor. 9168 */ 9169 @ViewDebug.ExportedProperty(category = "drawing") 9170 public float getScaleY() { 9171 return mTransformationInfo != null ? mTransformationInfo.mScaleY : 1; 9172 } 9173 9174 /** 9175 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 9176 * the view's unscaled width. A value of 1 means that no scaling is applied. 9177 * 9178 * @param scaleY The scaling factor. 9179 * @see #getPivotX() 9180 * @see #getPivotY() 9181 * 9182 * @attr ref android.R.styleable#View_scaleY 9183 */ 9184 public void setScaleY(float scaleY) { 9185 ensureTransformationInfo(); 9186 final TransformationInfo info = mTransformationInfo; 9187 if (info.mScaleY != scaleY) { 9188 invalidateViewProperty(true, false); 9189 info.mScaleY = scaleY; 9190 info.mMatrixDirty = true; 9191 invalidateViewProperty(false, true); 9192 if (mDisplayList != null) { 9193 mDisplayList.setScaleY(scaleY); 9194 } 9195 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9196 // View was rejected last time it was drawn by its parent; this may have changed 9197 invalidateParentIfNeeded(); 9198 } 9199 } 9200 } 9201 9202 /** 9203 * The x location of the point around which the view is {@link #setRotation(float) rotated} 9204 * and {@link #setScaleX(float) scaled}. 9205 * 9206 * @see #getRotation() 9207 * @see #getScaleX() 9208 * @see #getScaleY() 9209 * @see #getPivotY() 9210 * @return The x location of the pivot point. 9211 * 9212 * @attr ref android.R.styleable#View_transformPivotX 9213 */ 9214 @ViewDebug.ExportedProperty(category = "drawing") 9215 public float getPivotX() { 9216 return mTransformationInfo != null ? mTransformationInfo.mPivotX : 0; 9217 } 9218 9219 /** 9220 * Sets the x location of the point around which the view is 9221 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 9222 * By default, the pivot point is centered on the object. 9223 * Setting this property disables this behavior and causes the view to use only the 9224 * explicitly set pivotX and pivotY values. 9225 * 9226 * @param pivotX The x location of the pivot point. 9227 * @see #getRotation() 9228 * @see #getScaleX() 9229 * @see #getScaleY() 9230 * @see #getPivotY() 9231 * 9232 * @attr ref android.R.styleable#View_transformPivotX 9233 */ 9234 public void setPivotX(float pivotX) { 9235 ensureTransformationInfo(); 9236 mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET; 9237 final TransformationInfo info = mTransformationInfo; 9238 if (info.mPivotX != pivotX) { 9239 invalidateViewProperty(true, false); 9240 info.mPivotX = pivotX; 9241 info.mMatrixDirty = true; 9242 invalidateViewProperty(false, true); 9243 if (mDisplayList != null) { 9244 mDisplayList.setPivotX(pivotX); 9245 } 9246 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9247 // View was rejected last time it was drawn by its parent; this may have changed 9248 invalidateParentIfNeeded(); 9249 } 9250 } 9251 } 9252 9253 /** 9254 * The y location of the point around which the view is {@link #setRotation(float) rotated} 9255 * and {@link #setScaleY(float) scaled}. 9256 * 9257 * @see #getRotation() 9258 * @see #getScaleX() 9259 * @see #getScaleY() 9260 * @see #getPivotY() 9261 * @return The y location of the pivot point. 9262 * 9263 * @attr ref android.R.styleable#View_transformPivotY 9264 */ 9265 @ViewDebug.ExportedProperty(category = "drawing") 9266 public float getPivotY() { 9267 return mTransformationInfo != null ? mTransformationInfo.mPivotY : 0; 9268 } 9269 9270 /** 9271 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 9272 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 9273 * Setting this property disables this behavior and causes the view to use only the 9274 * explicitly set pivotX and pivotY values. 9275 * 9276 * @param pivotY The y location of the pivot point. 9277 * @see #getRotation() 9278 * @see #getScaleX() 9279 * @see #getScaleY() 9280 * @see #getPivotY() 9281 * 9282 * @attr ref android.R.styleable#View_transformPivotY 9283 */ 9284 public void setPivotY(float pivotY) { 9285 ensureTransformationInfo(); 9286 mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET; 9287 final TransformationInfo info = mTransformationInfo; 9288 if (info.mPivotY != pivotY) { 9289 invalidateViewProperty(true, false); 9290 info.mPivotY = pivotY; 9291 info.mMatrixDirty = true; 9292 invalidateViewProperty(false, true); 9293 if (mDisplayList != null) { 9294 mDisplayList.setPivotY(pivotY); 9295 } 9296 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9297 // View was rejected last time it was drawn by its parent; this may have changed 9298 invalidateParentIfNeeded(); 9299 } 9300 } 9301 } 9302 9303 /** 9304 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 9305 * completely transparent and 1 means the view is completely opaque. 9306 * 9307 * <p>By default this is 1.0f. 9308 * @return The opacity of the view. 9309 */ 9310 @ViewDebug.ExportedProperty(category = "drawing") 9311 public float getAlpha() { 9312 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 9313 } 9314 9315 /** 9316 * Returns whether this View has content which overlaps. This function, intended to be 9317 * overridden by specific View types, is an optimization when alpha is set on a view. If 9318 * rendering overlaps in a view with alpha < 1, that view is drawn to an offscreen buffer 9319 * and then composited it into place, which can be expensive. If the view has no overlapping 9320 * rendering, the view can draw each primitive with the appropriate alpha value directly. 9321 * An example of overlapping rendering is a TextView with a background image, such as a 9322 * Button. An example of non-overlapping rendering is a TextView with no background, or 9323 * an ImageView with only the foreground image. The default implementation returns true; 9324 * subclasses should override if they have cases which can be optimized. 9325 * 9326 * @return true if the content in this view might overlap, false otherwise. 9327 */ 9328 public boolean hasOverlappingRendering() { 9329 return true; 9330 } 9331 9332 /** 9333 * <p>Sets the opacity of the view. This is a value from 0 to 1, where 0 means the view is 9334 * completely transparent and 1 means the view is completely opaque.</p> 9335 * 9336 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 9337 * responsible for applying the opacity itself. Otherwise, calling this method is 9338 * equivalent to calling {@link #setLayerType(int, android.graphics.Paint)} and 9339 * setting a hardware layer.</p> 9340 * 9341 * <p>Note that setting alpha to a translucent value (0 < alpha < 1) may have 9342 * performance implications. It is generally best to use the alpha property sparingly and 9343 * transiently, as in the case of fading animations.</p> 9344 * 9345 * @param alpha The opacity of the view. 9346 * 9347 * @see #setLayerType(int, android.graphics.Paint) 9348 * 9349 * @attr ref android.R.styleable#View_alpha 9350 */ 9351 public void setAlpha(float alpha) { 9352 ensureTransformationInfo(); 9353 if (mTransformationInfo.mAlpha != alpha) { 9354 mTransformationInfo.mAlpha = alpha; 9355 if (onSetAlpha((int) (alpha * 255))) { 9356 mPrivateFlags |= PFLAG_ALPHA_SET; 9357 // subclass is handling alpha - don't optimize rendering cache invalidation 9358 invalidateParentCaches(); 9359 invalidate(true); 9360 } else { 9361 mPrivateFlags &= ~PFLAG_ALPHA_SET; 9362 invalidateViewProperty(true, false); 9363 if (mDisplayList != null) { 9364 mDisplayList.setAlpha(alpha); 9365 } 9366 } 9367 } 9368 } 9369 9370 /** 9371 * Faster version of setAlpha() which performs the same steps except there are 9372 * no calls to invalidate(). The caller of this function should perform proper invalidation 9373 * on the parent and this object. The return value indicates whether the subclass handles 9374 * alpha (the return value for onSetAlpha()). 9375 * 9376 * @param alpha The new value for the alpha property 9377 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 9378 * the new value for the alpha property is different from the old value 9379 */ 9380 boolean setAlphaNoInvalidation(float alpha) { 9381 ensureTransformationInfo(); 9382 if (mTransformationInfo.mAlpha != alpha) { 9383 mTransformationInfo.mAlpha = alpha; 9384 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 9385 if (subclassHandlesAlpha) { 9386 mPrivateFlags |= PFLAG_ALPHA_SET; 9387 return true; 9388 } else { 9389 mPrivateFlags &= ~PFLAG_ALPHA_SET; 9390 if (mDisplayList != null) { 9391 mDisplayList.setAlpha(alpha); 9392 } 9393 } 9394 } 9395 return false; 9396 } 9397 9398 /** 9399 * Top position of this view relative to its parent. 9400 * 9401 * @return The top of this view, in pixels. 9402 */ 9403 @ViewDebug.CapturedViewProperty 9404 public final int getTop() { 9405 return mTop; 9406 } 9407 9408 /** 9409 * Sets the top position of this view relative to its parent. This method is meant to be called 9410 * by the layout system and should not generally be called otherwise, because the property 9411 * may be changed at any time by the layout. 9412 * 9413 * @param top The top of this view, in pixels. 9414 */ 9415 public final void setTop(int top) { 9416 if (top != mTop) { 9417 updateMatrix(); 9418 final boolean matrixIsIdentity = mTransformationInfo == null 9419 || mTransformationInfo.mMatrixIsIdentity; 9420 if (matrixIsIdentity) { 9421 if (mAttachInfo != null) { 9422 int minTop; 9423 int yLoc; 9424 if (top < mTop) { 9425 minTop = top; 9426 yLoc = top - mTop; 9427 } else { 9428 minTop = mTop; 9429 yLoc = 0; 9430 } 9431 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 9432 } 9433 } else { 9434 // Double-invalidation is necessary to capture view's old and new areas 9435 invalidate(true); 9436 } 9437 9438 int width = mRight - mLeft; 9439 int oldHeight = mBottom - mTop; 9440 9441 mTop = top; 9442 if (mDisplayList != null) { 9443 mDisplayList.setTop(mTop); 9444 } 9445 9446 onSizeChanged(width, mBottom - mTop, width, oldHeight); 9447 9448 if (!matrixIsIdentity) { 9449 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) { 9450 // A change in dimension means an auto-centered pivot point changes, too 9451 mTransformationInfo.mMatrixDirty = true; 9452 } 9453 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 9454 invalidate(true); 9455 } 9456 mBackgroundSizeChanged = true; 9457 invalidateParentIfNeeded(); 9458 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9459 // View was rejected last time it was drawn by its parent; this may have changed 9460 invalidateParentIfNeeded(); 9461 } 9462 } 9463 } 9464 9465 /** 9466 * Bottom position of this view relative to its parent. 9467 * 9468 * @return The bottom of this view, in pixels. 9469 */ 9470 @ViewDebug.CapturedViewProperty 9471 public final int getBottom() { 9472 return mBottom; 9473 } 9474 9475 /** 9476 * True if this view has changed since the last time being drawn. 9477 * 9478 * @return The dirty state of this view. 9479 */ 9480 public boolean isDirty() { 9481 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 9482 } 9483 9484 /** 9485 * Sets the bottom position of this view relative to its parent. This method is meant to be 9486 * called by the layout system and should not generally be called otherwise, because the 9487 * property may be changed at any time by the layout. 9488 * 9489 * @param bottom The bottom of this view, in pixels. 9490 */ 9491 public final void setBottom(int bottom) { 9492 if (bottom != mBottom) { 9493 updateMatrix(); 9494 final boolean matrixIsIdentity = mTransformationInfo == null 9495 || mTransformationInfo.mMatrixIsIdentity; 9496 if (matrixIsIdentity) { 9497 if (mAttachInfo != null) { 9498 int maxBottom; 9499 if (bottom < mBottom) { 9500 maxBottom = mBottom; 9501 } else { 9502 maxBottom = bottom; 9503 } 9504 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 9505 } 9506 } else { 9507 // Double-invalidation is necessary to capture view's old and new areas 9508 invalidate(true); 9509 } 9510 9511 int width = mRight - mLeft; 9512 int oldHeight = mBottom - mTop; 9513 9514 mBottom = bottom; 9515 if (mDisplayList != null) { 9516 mDisplayList.setBottom(mBottom); 9517 } 9518 9519 onSizeChanged(width, mBottom - mTop, width, oldHeight); 9520 9521 if (!matrixIsIdentity) { 9522 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) { 9523 // A change in dimension means an auto-centered pivot point changes, too 9524 mTransformationInfo.mMatrixDirty = true; 9525 } 9526 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 9527 invalidate(true); 9528 } 9529 mBackgroundSizeChanged = true; 9530 invalidateParentIfNeeded(); 9531 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9532 // View was rejected last time it was drawn by its parent; this may have changed 9533 invalidateParentIfNeeded(); 9534 } 9535 } 9536 } 9537 9538 /** 9539 * Left position of this view relative to its parent. 9540 * 9541 * @return The left edge of this view, in pixels. 9542 */ 9543 @ViewDebug.CapturedViewProperty 9544 public final int getLeft() { 9545 return mLeft; 9546 } 9547 9548 /** 9549 * Sets the left position of this view relative to its parent. This method is meant to be called 9550 * by the layout system and should not generally be called otherwise, because the property 9551 * may be changed at any time by the layout. 9552 * 9553 * @param left The bottom of this view, in pixels. 9554 */ 9555 public final void setLeft(int left) { 9556 if (left != mLeft) { 9557 updateMatrix(); 9558 final boolean matrixIsIdentity = mTransformationInfo == null 9559 || mTransformationInfo.mMatrixIsIdentity; 9560 if (matrixIsIdentity) { 9561 if (mAttachInfo != null) { 9562 int minLeft; 9563 int xLoc; 9564 if (left < mLeft) { 9565 minLeft = left; 9566 xLoc = left - mLeft; 9567 } else { 9568 minLeft = mLeft; 9569 xLoc = 0; 9570 } 9571 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 9572 } 9573 } else { 9574 // Double-invalidation is necessary to capture view's old and new areas 9575 invalidate(true); 9576 } 9577 9578 int oldWidth = mRight - mLeft; 9579 int height = mBottom - mTop; 9580 9581 mLeft = left; 9582 if (mDisplayList != null) { 9583 mDisplayList.setLeft(left); 9584 } 9585 9586 onSizeChanged(mRight - mLeft, height, oldWidth, height); 9587 9588 if (!matrixIsIdentity) { 9589 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) { 9590 // A change in dimension means an auto-centered pivot point changes, too 9591 mTransformationInfo.mMatrixDirty = true; 9592 } 9593 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 9594 invalidate(true); 9595 } 9596 mBackgroundSizeChanged = true; 9597 invalidateParentIfNeeded(); 9598 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9599 // View was rejected last time it was drawn by its parent; this may have changed 9600 invalidateParentIfNeeded(); 9601 } 9602 } 9603 } 9604 9605 /** 9606 * Right position of this view relative to its parent. 9607 * 9608 * @return The right edge of this view, in pixels. 9609 */ 9610 @ViewDebug.CapturedViewProperty 9611 public final int getRight() { 9612 return mRight; 9613 } 9614 9615 /** 9616 * Sets the right position of this view relative to its parent. This method is meant to be called 9617 * by the layout system and should not generally be called otherwise, because the property 9618 * may be changed at any time by the layout. 9619 * 9620 * @param right The bottom of this view, in pixels. 9621 */ 9622 public final void setRight(int right) { 9623 if (right != mRight) { 9624 updateMatrix(); 9625 final boolean matrixIsIdentity = mTransformationInfo == null 9626 || mTransformationInfo.mMatrixIsIdentity; 9627 if (matrixIsIdentity) { 9628 if (mAttachInfo != null) { 9629 int maxRight; 9630 if (right < mRight) { 9631 maxRight = mRight; 9632 } else { 9633 maxRight = right; 9634 } 9635 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 9636 } 9637 } else { 9638 // Double-invalidation is necessary to capture view's old and new areas 9639 invalidate(true); 9640 } 9641 9642 int oldWidth = mRight - mLeft; 9643 int height = mBottom - mTop; 9644 9645 mRight = right; 9646 if (mDisplayList != null) { 9647 mDisplayList.setRight(mRight); 9648 } 9649 9650 onSizeChanged(mRight - mLeft, height, oldWidth, height); 9651 9652 if (!matrixIsIdentity) { 9653 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) { 9654 // A change in dimension means an auto-centered pivot point changes, too 9655 mTransformationInfo.mMatrixDirty = true; 9656 } 9657 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 9658 invalidate(true); 9659 } 9660 mBackgroundSizeChanged = true; 9661 invalidateParentIfNeeded(); 9662 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9663 // View was rejected last time it was drawn by its parent; this may have changed 9664 invalidateParentIfNeeded(); 9665 } 9666 } 9667 } 9668 9669 /** 9670 * The visual x position of this view, in pixels. This is equivalent to the 9671 * {@link #setTranslationX(float) translationX} property plus the current 9672 * {@link #getLeft() left} property. 9673 * 9674 * @return The visual x position of this view, in pixels. 9675 */ 9676 @ViewDebug.ExportedProperty(category = "drawing") 9677 public float getX() { 9678 return mLeft + (mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0); 9679 } 9680 9681 /** 9682 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 9683 * {@link #setTranslationX(float) translationX} property to be the difference between 9684 * the x value passed in and the current {@link #getLeft() left} property. 9685 * 9686 * @param x The visual x position of this view, in pixels. 9687 */ 9688 public void setX(float x) { 9689 setTranslationX(x - mLeft); 9690 } 9691 9692 /** 9693 * The visual y position of this view, in pixels. This is equivalent to the 9694 * {@link #setTranslationY(float) translationY} property plus the current 9695 * {@link #getTop() top} property. 9696 * 9697 * @return The visual y position of this view, in pixels. 9698 */ 9699 @ViewDebug.ExportedProperty(category = "drawing") 9700 public float getY() { 9701 return mTop + (mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0); 9702 } 9703 9704 /** 9705 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 9706 * {@link #setTranslationY(float) translationY} property to be the difference between 9707 * the y value passed in and the current {@link #getTop() top} property. 9708 * 9709 * @param y The visual y position of this view, in pixels. 9710 */ 9711 public void setY(float y) { 9712 setTranslationY(y - mTop); 9713 } 9714 9715 9716 /** 9717 * The horizontal location of this view relative to its {@link #getLeft() left} position. 9718 * This position is post-layout, in addition to wherever the object's 9719 * layout placed it. 9720 * 9721 * @return The horizontal position of this view relative to its left position, in pixels. 9722 */ 9723 @ViewDebug.ExportedProperty(category = "drawing") 9724 public float getTranslationX() { 9725 return mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0; 9726 } 9727 9728 /** 9729 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 9730 * This effectively positions the object post-layout, in addition to wherever the object's 9731 * layout placed it. 9732 * 9733 * @param translationX The horizontal position of this view relative to its left position, 9734 * in pixels. 9735 * 9736 * @attr ref android.R.styleable#View_translationX 9737 */ 9738 public void setTranslationX(float translationX) { 9739 ensureTransformationInfo(); 9740 final TransformationInfo info = mTransformationInfo; 9741 if (info.mTranslationX != translationX) { 9742 // Double-invalidation is necessary to capture view's old and new areas 9743 invalidateViewProperty(true, false); 9744 info.mTranslationX = translationX; 9745 info.mMatrixDirty = true; 9746 invalidateViewProperty(false, true); 9747 if (mDisplayList != null) { 9748 mDisplayList.setTranslationX(translationX); 9749 } 9750 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9751 // View was rejected last time it was drawn by its parent; this may have changed 9752 invalidateParentIfNeeded(); 9753 } 9754 } 9755 } 9756 9757 /** 9758 * The horizontal location of this view relative to its {@link #getTop() top} position. 9759 * This position is post-layout, in addition to wherever the object's 9760 * layout placed it. 9761 * 9762 * @return The vertical position of this view relative to its top position, 9763 * in pixels. 9764 */ 9765 @ViewDebug.ExportedProperty(category = "drawing") 9766 public float getTranslationY() { 9767 return mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0; 9768 } 9769 9770 /** 9771 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 9772 * This effectively positions the object post-layout, in addition to wherever the object's 9773 * layout placed it. 9774 * 9775 * @param translationY The vertical position of this view relative to its top position, 9776 * in pixels. 9777 * 9778 * @attr ref android.R.styleable#View_translationY 9779 */ 9780 public void setTranslationY(float translationY) { 9781 ensureTransformationInfo(); 9782 final TransformationInfo info = mTransformationInfo; 9783 if (info.mTranslationY != translationY) { 9784 invalidateViewProperty(true, false); 9785 info.mTranslationY = translationY; 9786 info.mMatrixDirty = true; 9787 invalidateViewProperty(false, true); 9788 if (mDisplayList != null) { 9789 mDisplayList.setTranslationY(translationY); 9790 } 9791 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 9792 // View was rejected last time it was drawn by its parent; this may have changed 9793 invalidateParentIfNeeded(); 9794 } 9795 } 9796 } 9797 9798 /** 9799 * Hit rectangle in parent's coordinates 9800 * 9801 * @param outRect The hit rectangle of the view. 9802 */ 9803 public void getHitRect(Rect outRect) { 9804 updateMatrix(); 9805 final TransformationInfo info = mTransformationInfo; 9806 if (info == null || info.mMatrixIsIdentity || mAttachInfo == null) { 9807 outRect.set(mLeft, mTop, mRight, mBottom); 9808 } else { 9809 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 9810 tmpRect.set(-info.mPivotX, -info.mPivotY, 9811 getWidth() - info.mPivotX, getHeight() - info.mPivotY); 9812 info.mMatrix.mapRect(tmpRect); 9813 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 9814 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 9815 } 9816 } 9817 9818 /** 9819 * Determines whether the given point, in local coordinates is inside the view. 9820 */ 9821 /*package*/ final boolean pointInView(float localX, float localY) { 9822 return localX >= 0 && localX < (mRight - mLeft) 9823 && localY >= 0 && localY < (mBottom - mTop); 9824 } 9825 9826 /** 9827 * Utility method to determine whether the given point, in local coordinates, 9828 * is inside the view, where the area of the view is expanded by the slop factor. 9829 * This method is called while processing touch-move events to determine if the event 9830 * is still within the view. 9831 */ 9832 private boolean pointInView(float localX, float localY, float slop) { 9833 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 9834 localY < ((mBottom - mTop) + slop); 9835 } 9836 9837 /** 9838 * When a view has focus and the user navigates away from it, the next view is searched for 9839 * starting from the rectangle filled in by this method. 9840 * 9841 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 9842 * of the view. However, if your view maintains some idea of internal selection, 9843 * such as a cursor, or a selected row or column, you should override this method and 9844 * fill in a more specific rectangle. 9845 * 9846 * @param r The rectangle to fill in, in this view's coordinates. 9847 */ 9848 public void getFocusedRect(Rect r) { 9849 getDrawingRect(r); 9850 } 9851 9852 /** 9853 * If some part of this view is not clipped by any of its parents, then 9854 * return that area in r in global (root) coordinates. To convert r to local 9855 * coordinates (without taking possible View rotations into account), offset 9856 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 9857 * If the view is completely clipped or translated out, return false. 9858 * 9859 * @param r If true is returned, r holds the global coordinates of the 9860 * visible portion of this view. 9861 * @param globalOffset If true is returned, globalOffset holds the dx,dy 9862 * between this view and its root. globalOffet may be null. 9863 * @return true if r is non-empty (i.e. part of the view is visible at the 9864 * root level. 9865 */ 9866 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 9867 int width = mRight - mLeft; 9868 int height = mBottom - mTop; 9869 if (width > 0 && height > 0) { 9870 r.set(0, 0, width, height); 9871 if (globalOffset != null) { 9872 globalOffset.set(-mScrollX, -mScrollY); 9873 } 9874 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 9875 } 9876 return false; 9877 } 9878 9879 public final boolean getGlobalVisibleRect(Rect r) { 9880 return getGlobalVisibleRect(r, null); 9881 } 9882 9883 public final boolean getLocalVisibleRect(Rect r) { 9884 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 9885 if (getGlobalVisibleRect(r, offset)) { 9886 r.offset(-offset.x, -offset.y); // make r local 9887 return true; 9888 } 9889 return false; 9890 } 9891 9892 /** 9893 * Offset this view's vertical location by the specified number of pixels. 9894 * 9895 * @param offset the number of pixels to offset the view by 9896 */ 9897 public void offsetTopAndBottom(int offset) { 9898 if (offset != 0) { 9899 updateMatrix(); 9900 final boolean matrixIsIdentity = mTransformationInfo == null 9901 || mTransformationInfo.mMatrixIsIdentity; 9902 if (matrixIsIdentity) { 9903 if (mDisplayList != null) { 9904 invalidateViewProperty(false, false); 9905 } else { 9906 final ViewParent p = mParent; 9907 if (p != null && mAttachInfo != null) { 9908 final Rect r = mAttachInfo.mTmpInvalRect; 9909 int minTop; 9910 int maxBottom; 9911 int yLoc; 9912 if (offset < 0) { 9913 minTop = mTop + offset; 9914 maxBottom = mBottom; 9915 yLoc = offset; 9916 } else { 9917 minTop = mTop; 9918 maxBottom = mBottom + offset; 9919 yLoc = 0; 9920 } 9921 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 9922 p.invalidateChild(this, r); 9923 } 9924 } 9925 } else { 9926 invalidateViewProperty(false, false); 9927 } 9928 9929 mTop += offset; 9930 mBottom += offset; 9931 if (mDisplayList != null) { 9932 mDisplayList.offsetTopBottom(offset); 9933 invalidateViewProperty(false, false); 9934 } else { 9935 if (!matrixIsIdentity) { 9936 invalidateViewProperty(false, true); 9937 } 9938 invalidateParentIfNeeded(); 9939 } 9940 } 9941 } 9942 9943 /** 9944 * Offset this view's horizontal location by the specified amount of pixels. 9945 * 9946 * @param offset the numer of pixels to offset the view by 9947 */ 9948 public void offsetLeftAndRight(int offset) { 9949 if (offset != 0) { 9950 updateMatrix(); 9951 final boolean matrixIsIdentity = mTransformationInfo == null 9952 || mTransformationInfo.mMatrixIsIdentity; 9953 if (matrixIsIdentity) { 9954 if (mDisplayList != null) { 9955 invalidateViewProperty(false, false); 9956 } else { 9957 final ViewParent p = mParent; 9958 if (p != null && mAttachInfo != null) { 9959 final Rect r = mAttachInfo.mTmpInvalRect; 9960 int minLeft; 9961 int maxRight; 9962 if (offset < 0) { 9963 minLeft = mLeft + offset; 9964 maxRight = mRight; 9965 } else { 9966 minLeft = mLeft; 9967 maxRight = mRight + offset; 9968 } 9969 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 9970 p.invalidateChild(this, r); 9971 } 9972 } 9973 } else { 9974 invalidateViewProperty(false, false); 9975 } 9976 9977 mLeft += offset; 9978 mRight += offset; 9979 if (mDisplayList != null) { 9980 mDisplayList.offsetLeftRight(offset); 9981 invalidateViewProperty(false, false); 9982 } else { 9983 if (!matrixIsIdentity) { 9984 invalidateViewProperty(false, true); 9985 } 9986 invalidateParentIfNeeded(); 9987 } 9988 } 9989 } 9990 9991 /** 9992 * Get the LayoutParams associated with this view. All views should have 9993 * layout parameters. These supply parameters to the <i>parent</i> of this 9994 * view specifying how it should be arranged. There are many subclasses of 9995 * ViewGroup.LayoutParams, and these correspond to the different subclasses 9996 * of ViewGroup that are responsible for arranging their children. 9997 * 9998 * This method may return null if this View is not attached to a parent 9999 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 10000 * was not invoked successfully. When a View is attached to a parent 10001 * ViewGroup, this method must not return null. 10002 * 10003 * @return The LayoutParams associated with this view, or null if no 10004 * parameters have been set yet 10005 */ 10006 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 10007 public ViewGroup.LayoutParams getLayoutParams() { 10008 return mLayoutParams; 10009 } 10010 10011 /** 10012 * Set the layout parameters associated with this view. These supply 10013 * parameters to the <i>parent</i> of this view specifying how it should be 10014 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 10015 * correspond to the different subclasses of ViewGroup that are responsible 10016 * for arranging their children. 10017 * 10018 * @param params The layout parameters for this view, cannot be null 10019 */ 10020 public void setLayoutParams(ViewGroup.LayoutParams params) { 10021 if (params == null) { 10022 throw new NullPointerException("Layout parameters cannot be null"); 10023 } 10024 mLayoutParams = params; 10025 resolveLayoutParams(); 10026 if (mParent instanceof ViewGroup) { 10027 ((ViewGroup) mParent).onSetLayoutParams(this, params); 10028 } 10029 requestLayout(); 10030 } 10031 10032 /** 10033 * Resolve the layout parameters depending on the resolved layout direction 10034 * 10035 * @hide 10036 */ 10037 public void resolveLayoutParams() { 10038 if (mLayoutParams != null) { 10039 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 10040 } 10041 } 10042 10043 /** 10044 * Set the scrolled position of your view. This will cause a call to 10045 * {@link #onScrollChanged(int, int, int, int)} and the view will be 10046 * invalidated. 10047 * @param x the x position to scroll to 10048 * @param y the y position to scroll to 10049 */ 10050 public void scrollTo(int x, int y) { 10051 if (mScrollX != x || mScrollY != y) { 10052 int oldX = mScrollX; 10053 int oldY = mScrollY; 10054 mScrollX = x; 10055 mScrollY = y; 10056 invalidateParentCaches(); 10057 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 10058 if (!awakenScrollBars()) { 10059 postInvalidateOnAnimation(); 10060 } 10061 } 10062 } 10063 10064 /** 10065 * Move the scrolled position of your view. This will cause a call to 10066 * {@link #onScrollChanged(int, int, int, int)} and the view will be 10067 * invalidated. 10068 * @param x the amount of pixels to scroll by horizontally 10069 * @param y the amount of pixels to scroll by vertically 10070 */ 10071 public void scrollBy(int x, int y) { 10072 scrollTo(mScrollX + x, mScrollY + y); 10073 } 10074 10075 /** 10076 * <p>Trigger the scrollbars to draw. When invoked this method starts an 10077 * animation to fade the scrollbars out after a default delay. If a subclass 10078 * provides animated scrolling, the start delay should equal the duration 10079 * of the scrolling animation.</p> 10080 * 10081 * <p>The animation starts only if at least one of the scrollbars is 10082 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 10083 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 10084 * this method returns true, and false otherwise. If the animation is 10085 * started, this method calls {@link #invalidate()}; in that case the 10086 * caller should not call {@link #invalidate()}.</p> 10087 * 10088 * <p>This method should be invoked every time a subclass directly updates 10089 * the scroll parameters.</p> 10090 * 10091 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 10092 * and {@link #scrollTo(int, int)}.</p> 10093 * 10094 * @return true if the animation is played, false otherwise 10095 * 10096 * @see #awakenScrollBars(int) 10097 * @see #scrollBy(int, int) 10098 * @see #scrollTo(int, int) 10099 * @see #isHorizontalScrollBarEnabled() 10100 * @see #isVerticalScrollBarEnabled() 10101 * @see #setHorizontalScrollBarEnabled(boolean) 10102 * @see #setVerticalScrollBarEnabled(boolean) 10103 */ 10104 protected boolean awakenScrollBars() { 10105 return mScrollCache != null && 10106 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 10107 } 10108 10109 /** 10110 * Trigger the scrollbars to draw. 10111 * This method differs from awakenScrollBars() only in its default duration. 10112 * initialAwakenScrollBars() will show the scroll bars for longer than 10113 * usual to give the user more of a chance to notice them. 10114 * 10115 * @return true if the animation is played, false otherwise. 10116 */ 10117 private boolean initialAwakenScrollBars() { 10118 return mScrollCache != null && 10119 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 10120 } 10121 10122 /** 10123 * <p> 10124 * Trigger the scrollbars to draw. When invoked this method starts an 10125 * animation to fade the scrollbars out after a fixed delay. If a subclass 10126 * provides animated scrolling, the start delay should equal the duration of 10127 * the scrolling animation. 10128 * </p> 10129 * 10130 * <p> 10131 * The animation starts only if at least one of the scrollbars is enabled, 10132 * as specified by {@link #isHorizontalScrollBarEnabled()} and 10133 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 10134 * this method returns true, and false otherwise. If the animation is 10135 * started, this method calls {@link #invalidate()}; in that case the caller 10136 * should not call {@link #invalidate()}. 10137 * </p> 10138 * 10139 * <p> 10140 * This method should be invoked everytime a subclass directly updates the 10141 * scroll parameters. 10142 * </p> 10143 * 10144 * @param startDelay the delay, in milliseconds, after which the animation 10145 * should start; when the delay is 0, the animation starts 10146 * immediately 10147 * @return true if the animation is played, false otherwise 10148 * 10149 * @see #scrollBy(int, int) 10150 * @see #scrollTo(int, int) 10151 * @see #isHorizontalScrollBarEnabled() 10152 * @see #isVerticalScrollBarEnabled() 10153 * @see #setHorizontalScrollBarEnabled(boolean) 10154 * @see #setVerticalScrollBarEnabled(boolean) 10155 */ 10156 protected boolean awakenScrollBars(int startDelay) { 10157 return awakenScrollBars(startDelay, true); 10158 } 10159 10160 /** 10161 * <p> 10162 * Trigger the scrollbars to draw. When invoked this method starts an 10163 * animation to fade the scrollbars out after a fixed delay. If a subclass 10164 * provides animated scrolling, the start delay should equal the duration of 10165 * the scrolling animation. 10166 * </p> 10167 * 10168 * <p> 10169 * The animation starts only if at least one of the scrollbars is enabled, 10170 * as specified by {@link #isHorizontalScrollBarEnabled()} and 10171 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 10172 * this method returns true, and false otherwise. If the animation is 10173 * started, this method calls {@link #invalidate()} if the invalidate parameter 10174 * is set to true; in that case the caller 10175 * should not call {@link #invalidate()}. 10176 * </p> 10177 * 10178 * <p> 10179 * This method should be invoked everytime a subclass directly updates the 10180 * scroll parameters. 10181 * </p> 10182 * 10183 * @param startDelay the delay, in milliseconds, after which the animation 10184 * should start; when the delay is 0, the animation starts 10185 * immediately 10186 * 10187 * @param invalidate Wheter this method should call invalidate 10188 * 10189 * @return true if the animation is played, false otherwise 10190 * 10191 * @see #scrollBy(int, int) 10192 * @see #scrollTo(int, int) 10193 * @see #isHorizontalScrollBarEnabled() 10194 * @see #isVerticalScrollBarEnabled() 10195 * @see #setHorizontalScrollBarEnabled(boolean) 10196 * @see #setVerticalScrollBarEnabled(boolean) 10197 */ 10198 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 10199 final ScrollabilityCache scrollCache = mScrollCache; 10200 10201 if (scrollCache == null || !scrollCache.fadeScrollBars) { 10202 return false; 10203 } 10204 10205 if (scrollCache.scrollBar == null) { 10206 scrollCache.scrollBar = new ScrollBarDrawable(); 10207 } 10208 10209 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 10210 10211 if (invalidate) { 10212 // Invalidate to show the scrollbars 10213 postInvalidateOnAnimation(); 10214 } 10215 10216 if (scrollCache.state == ScrollabilityCache.OFF) { 10217 // FIXME: this is copied from WindowManagerService. 10218 // We should get this value from the system when it 10219 // is possible to do so. 10220 final int KEY_REPEAT_FIRST_DELAY = 750; 10221 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 10222 } 10223 10224 // Tell mScrollCache when we should start fading. This may 10225 // extend the fade start time if one was already scheduled 10226 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 10227 scrollCache.fadeStartTime = fadeStartTime; 10228 scrollCache.state = ScrollabilityCache.ON; 10229 10230 // Schedule our fader to run, unscheduling any old ones first 10231 if (mAttachInfo != null) { 10232 mAttachInfo.mHandler.removeCallbacks(scrollCache); 10233 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 10234 } 10235 10236 return true; 10237 } 10238 10239 return false; 10240 } 10241 10242 /** 10243 * Do not invalidate views which are not visible and which are not running an animation. They 10244 * will not get drawn and they should not set dirty flags as if they will be drawn 10245 */ 10246 private boolean skipInvalidate() { 10247 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 10248 (!(mParent instanceof ViewGroup) || 10249 !((ViewGroup) mParent).isViewTransitioning(this)); 10250 } 10251 /** 10252 * Mark the area defined by dirty as needing to be drawn. If the view is 10253 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some point 10254 * in the future. This must be called from a UI thread. To call from a non-UI 10255 * thread, call {@link #postInvalidate()}. 10256 * 10257 * WARNING: This method is destructive to dirty. 10258 * @param dirty the rectangle representing the bounds of the dirty region 10259 */ 10260 public void invalidate(Rect dirty) { 10261 if (skipInvalidate()) { 10262 return; 10263 } 10264 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) || 10265 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID || 10266 (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED) { 10267 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 10268 mPrivateFlags |= PFLAG_INVALIDATED; 10269 mPrivateFlags |= PFLAG_DIRTY; 10270 final ViewParent p = mParent; 10271 final AttachInfo ai = mAttachInfo; 10272 //noinspection PointlessBooleanExpression,ConstantConditions 10273 if (!HardwareRenderer.RENDER_DIRTY_REGIONS) { 10274 if (p != null && ai != null && ai.mHardwareAccelerated) { 10275 // fast-track for GL-enabled applications; just invalidate the whole hierarchy 10276 // with a null dirty rect, which tells the ViewAncestor to redraw everything 10277 p.invalidateChild(this, null); 10278 return; 10279 } 10280 } 10281 if (p != null && ai != null) { 10282 final int scrollX = mScrollX; 10283 final int scrollY = mScrollY; 10284 final Rect r = ai.mTmpInvalRect; 10285 r.set(dirty.left - scrollX, dirty.top - scrollY, 10286 dirty.right - scrollX, dirty.bottom - scrollY); 10287 mParent.invalidateChild(this, r); 10288 } 10289 } 10290 } 10291 10292 /** 10293 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. 10294 * The coordinates of the dirty rect are relative to the view. 10295 * If the view is visible, {@link #onDraw(android.graphics.Canvas)} 10296 * will be called at some point in the future. This must be called from 10297 * a UI thread. To call from a non-UI thread, call {@link #postInvalidate()}. 10298 * @param l the left position of the dirty region 10299 * @param t the top position of the dirty region 10300 * @param r the right position of the dirty region 10301 * @param b the bottom position of the dirty region 10302 */ 10303 public void invalidate(int l, int t, int r, int b) { 10304 if (skipInvalidate()) { 10305 return; 10306 } 10307 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) || 10308 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID || 10309 (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED) { 10310 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 10311 mPrivateFlags |= PFLAG_INVALIDATED; 10312 mPrivateFlags |= PFLAG_DIRTY; 10313 final ViewParent p = mParent; 10314 final AttachInfo ai = mAttachInfo; 10315 //noinspection PointlessBooleanExpression,ConstantConditions 10316 if (!HardwareRenderer.RENDER_DIRTY_REGIONS) { 10317 if (p != null && ai != null && ai.mHardwareAccelerated) { 10318 // fast-track for GL-enabled applications; just invalidate the whole hierarchy 10319 // with a null dirty rect, which tells the ViewAncestor to redraw everything 10320 p.invalidateChild(this, null); 10321 return; 10322 } 10323 } 10324 if (p != null && ai != null && l < r && t < b) { 10325 final int scrollX = mScrollX; 10326 final int scrollY = mScrollY; 10327 final Rect tmpr = ai.mTmpInvalRect; 10328 tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY); 10329 p.invalidateChild(this, tmpr); 10330 } 10331 } 10332 } 10333 10334 /** 10335 * Invalidate the whole view. If the view is visible, 10336 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 10337 * the future. This must be called from a UI thread. To call from a non-UI thread, 10338 * call {@link #postInvalidate()}. 10339 */ 10340 public void invalidate() { 10341 invalidate(true); 10342 } 10343 10344 /** 10345 * This is where the invalidate() work actually happens. A full invalidate() 10346 * causes the drawing cache to be invalidated, but this function can be called with 10347 * invalidateCache set to false to skip that invalidation step for cases that do not 10348 * need it (for example, a component that remains at the same dimensions with the same 10349 * content). 10350 * 10351 * @param invalidateCache Whether the drawing cache for this view should be invalidated as 10352 * well. This is usually true for a full invalidate, but may be set to false if the 10353 * View's contents or dimensions have not changed. 10354 */ 10355 void invalidate(boolean invalidateCache) { 10356 if (skipInvalidate()) { 10357 return; 10358 } 10359 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) || 10360 (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) || 10361 (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || isOpaque() != mLastIsOpaque) { 10362 mLastIsOpaque = isOpaque(); 10363 mPrivateFlags &= ~PFLAG_DRAWN; 10364 mPrivateFlags |= PFLAG_DIRTY; 10365 if (invalidateCache) { 10366 mPrivateFlags |= PFLAG_INVALIDATED; 10367 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 10368 } 10369 final AttachInfo ai = mAttachInfo; 10370 final ViewParent p = mParent; 10371 //noinspection PointlessBooleanExpression,ConstantConditions 10372 if (!HardwareRenderer.RENDER_DIRTY_REGIONS) { 10373 if (p != null && ai != null && ai.mHardwareAccelerated) { 10374 // fast-track for GL-enabled applications; just invalidate the whole hierarchy 10375 // with a null dirty rect, which tells the ViewAncestor to redraw everything 10376 p.invalidateChild(this, null); 10377 return; 10378 } 10379 } 10380 10381 if (p != null && ai != null) { 10382 final Rect r = ai.mTmpInvalRect; 10383 r.set(0, 0, mRight - mLeft, mBottom - mTop); 10384 // Don't call invalidate -- we don't want to internally scroll 10385 // our own bounds 10386 p.invalidateChild(this, r); 10387 } 10388 } 10389 } 10390 10391 /** 10392 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 10393 * set any flags or handle all of the cases handled by the default invalidation methods. 10394 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 10395 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 10396 * walk up the hierarchy, transforming the dirty rect as necessary. 10397 * 10398 * The method also handles normal invalidation logic if display list properties are not 10399 * being used in this view. The invalidateParent and forceRedraw flags are used by that 10400 * backup approach, to handle these cases used in the various property-setting methods. 10401 * 10402 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 10403 * are not being used in this view 10404 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 10405 * list properties are not being used in this view 10406 */ 10407 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 10408 if (mDisplayList == null || (mPrivateFlags & PFLAG_DRAW_ANIMATION) == PFLAG_DRAW_ANIMATION) { 10409 if (invalidateParent) { 10410 invalidateParentCaches(); 10411 } 10412 if (forceRedraw) { 10413 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 10414 } 10415 invalidate(false); 10416 } else { 10417 final AttachInfo ai = mAttachInfo; 10418 final ViewParent p = mParent; 10419 if (p != null && ai != null) { 10420 final Rect r = ai.mTmpInvalRect; 10421 r.set(0, 0, mRight - mLeft, mBottom - mTop); 10422 if (mParent instanceof ViewGroup) { 10423 ((ViewGroup) mParent).invalidateChildFast(this, r); 10424 } else { 10425 mParent.invalidateChild(this, r); 10426 } 10427 } 10428 } 10429 } 10430 10431 /** 10432 * Utility method to transform a given Rect by the current matrix of this view. 10433 */ 10434 void transformRect(final Rect rect) { 10435 if (!getMatrix().isIdentity()) { 10436 RectF boundingRect = mAttachInfo.mTmpTransformRect; 10437 boundingRect.set(rect); 10438 getMatrix().mapRect(boundingRect); 10439 rect.set((int) (boundingRect.left - 0.5f), 10440 (int) (boundingRect.top - 0.5f), 10441 (int) (boundingRect.right + 0.5f), 10442 (int) (boundingRect.bottom + 0.5f)); 10443 } 10444 } 10445 10446 /** 10447 * Used to indicate that the parent of this view should clear its caches. This functionality 10448 * is used to force the parent to rebuild its display list (when hardware-accelerated), 10449 * which is necessary when various parent-managed properties of the view change, such as 10450 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 10451 * clears the parent caches and does not causes an invalidate event. 10452 * 10453 * @hide 10454 */ 10455 protected void invalidateParentCaches() { 10456 if (mParent instanceof View) { 10457 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 10458 } 10459 } 10460 10461 /** 10462 * Used to indicate that the parent of this view should be invalidated. This functionality 10463 * is used to force the parent to rebuild its display list (when hardware-accelerated), 10464 * which is necessary when various parent-managed properties of the view change, such as 10465 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 10466 * an invalidation event to the parent. 10467 * 10468 * @hide 10469 */ 10470 protected void invalidateParentIfNeeded() { 10471 if (isHardwareAccelerated() && mParent instanceof View) { 10472 ((View) mParent).invalidate(true); 10473 } 10474 } 10475 10476 /** 10477 * Indicates whether this View is opaque. An opaque View guarantees that it will 10478 * draw all the pixels overlapping its bounds using a fully opaque color. 10479 * 10480 * Subclasses of View should override this method whenever possible to indicate 10481 * whether an instance is opaque. Opaque Views are treated in a special way by 10482 * the View hierarchy, possibly allowing it to perform optimizations during 10483 * invalidate/draw passes. 10484 * 10485 * @return True if this View is guaranteed to be fully opaque, false otherwise. 10486 */ 10487 @ViewDebug.ExportedProperty(category = "drawing") 10488 public boolean isOpaque() { 10489 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 10490 ((mTransformationInfo != null ? mTransformationInfo.mAlpha : 1.0f) >= 1.0f); 10491 } 10492 10493 /** 10494 * @hide 10495 */ 10496 protected void computeOpaqueFlags() { 10497 // Opaque if: 10498 // - Has a background 10499 // - Background is opaque 10500 // - Doesn't have scrollbars or scrollbars are inside overlay 10501 10502 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 10503 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 10504 } else { 10505 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 10506 } 10507 10508 final int flags = mViewFlags; 10509 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 10510 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY) { 10511 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 10512 } else { 10513 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 10514 } 10515 } 10516 10517 /** 10518 * @hide 10519 */ 10520 protected boolean hasOpaqueScrollbars() { 10521 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 10522 } 10523 10524 /** 10525 * @return A handler associated with the thread running the View. This 10526 * handler can be used to pump events in the UI events queue. 10527 */ 10528 public Handler getHandler() { 10529 if (mAttachInfo != null) { 10530 return mAttachInfo.mHandler; 10531 } 10532 return null; 10533 } 10534 10535 /** 10536 * Gets the view root associated with the View. 10537 * @return The view root, or null if none. 10538 * @hide 10539 */ 10540 public ViewRootImpl getViewRootImpl() { 10541 if (mAttachInfo != null) { 10542 return mAttachInfo.mViewRootImpl; 10543 } 10544 return null; 10545 } 10546 10547 /** 10548 * <p>Causes the Runnable to be added to the message queue. 10549 * The runnable will be run on the user interface thread.</p> 10550 * 10551 * @param action The Runnable that will be executed. 10552 * 10553 * @return Returns true if the Runnable was successfully placed in to the 10554 * message queue. Returns false on failure, usually because the 10555 * looper processing the message queue is exiting. 10556 * 10557 * @see #postDelayed 10558 * @see #removeCallbacks 10559 */ 10560 public boolean post(Runnable action) { 10561 final AttachInfo attachInfo = mAttachInfo; 10562 if (attachInfo != null) { 10563 return attachInfo.mHandler.post(action); 10564 } 10565 // Assume that post will succeed later 10566 ViewRootImpl.getRunQueue().post(action); 10567 return true; 10568 } 10569 10570 /** 10571 * <p>Causes the Runnable to be added to the message queue, to be run 10572 * after the specified amount of time elapses. 10573 * The runnable will be run on the user interface thread.</p> 10574 * 10575 * @param action The Runnable that will be executed. 10576 * @param delayMillis The delay (in milliseconds) until the Runnable 10577 * will be executed. 10578 * 10579 * @return true if the Runnable was successfully placed in to the 10580 * message queue. Returns false on failure, usually because the 10581 * looper processing the message queue is exiting. Note that a 10582 * result of true does not mean the Runnable will be processed -- 10583 * if the looper is quit before the delivery time of the message 10584 * occurs then the message will be dropped. 10585 * 10586 * @see #post 10587 * @see #removeCallbacks 10588 */ 10589 public boolean postDelayed(Runnable action, long delayMillis) { 10590 final AttachInfo attachInfo = mAttachInfo; 10591 if (attachInfo != null) { 10592 return attachInfo.mHandler.postDelayed(action, delayMillis); 10593 } 10594 // Assume that post will succeed later 10595 ViewRootImpl.getRunQueue().postDelayed(action, delayMillis); 10596 return true; 10597 } 10598 10599 /** 10600 * <p>Causes the Runnable to execute on the next animation time step. 10601 * The runnable will be run on the user interface thread.</p> 10602 * 10603 * @param action The Runnable that will be executed. 10604 * 10605 * @see #postOnAnimationDelayed 10606 * @see #removeCallbacks 10607 */ 10608 public void postOnAnimation(Runnable action) { 10609 final AttachInfo attachInfo = mAttachInfo; 10610 if (attachInfo != null) { 10611 attachInfo.mViewRootImpl.mChoreographer.postCallback( 10612 Choreographer.CALLBACK_ANIMATION, action, null); 10613 } else { 10614 // Assume that post will succeed later 10615 ViewRootImpl.getRunQueue().post(action); 10616 } 10617 } 10618 10619 /** 10620 * <p>Causes the Runnable to execute on the next animation time step, 10621 * after the specified amount of time elapses. 10622 * The runnable will be run on the user interface thread.</p> 10623 * 10624 * @param action The Runnable that will be executed. 10625 * @param delayMillis The delay (in milliseconds) until the Runnable 10626 * will be executed. 10627 * 10628 * @see #postOnAnimation 10629 * @see #removeCallbacks 10630 */ 10631 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 10632 final AttachInfo attachInfo = mAttachInfo; 10633 if (attachInfo != null) { 10634 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 10635 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 10636 } else { 10637 // Assume that post will succeed later 10638 ViewRootImpl.getRunQueue().postDelayed(action, delayMillis); 10639 } 10640 } 10641 10642 /** 10643 * <p>Removes the specified Runnable from the message queue.</p> 10644 * 10645 * @param action The Runnable to remove from the message handling queue 10646 * 10647 * @return true if this view could ask the Handler to remove the Runnable, 10648 * false otherwise. When the returned value is true, the Runnable 10649 * may or may not have been actually removed from the message queue 10650 * (for instance, if the Runnable was not in the queue already.) 10651 * 10652 * @see #post 10653 * @see #postDelayed 10654 * @see #postOnAnimation 10655 * @see #postOnAnimationDelayed 10656 */ 10657 public boolean removeCallbacks(Runnable action) { 10658 if (action != null) { 10659 final AttachInfo attachInfo = mAttachInfo; 10660 if (attachInfo != null) { 10661 attachInfo.mHandler.removeCallbacks(action); 10662 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 10663 Choreographer.CALLBACK_ANIMATION, action, null); 10664 } else { 10665 // Assume that post will succeed later 10666 ViewRootImpl.getRunQueue().removeCallbacks(action); 10667 } 10668 } 10669 return true; 10670 } 10671 10672 /** 10673 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 10674 * Use this to invalidate the View from a non-UI thread.</p> 10675 * 10676 * <p>This method can be invoked from outside of the UI thread 10677 * only when this View is attached to a window.</p> 10678 * 10679 * @see #invalidate() 10680 * @see #postInvalidateDelayed(long) 10681 */ 10682 public void postInvalidate() { 10683 postInvalidateDelayed(0); 10684 } 10685 10686 /** 10687 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 10688 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 10689 * 10690 * <p>This method can be invoked from outside of the UI thread 10691 * only when this View is attached to a window.</p> 10692 * 10693 * @param left The left coordinate of the rectangle to invalidate. 10694 * @param top The top coordinate of the rectangle to invalidate. 10695 * @param right The right coordinate of the rectangle to invalidate. 10696 * @param bottom The bottom coordinate of the rectangle to invalidate. 10697 * 10698 * @see #invalidate(int, int, int, int) 10699 * @see #invalidate(Rect) 10700 * @see #postInvalidateDelayed(long, int, int, int, int) 10701 */ 10702 public void postInvalidate(int left, int top, int right, int bottom) { 10703 postInvalidateDelayed(0, left, top, right, bottom); 10704 } 10705 10706 /** 10707 * <p>Cause an invalidate to happen on a subsequent cycle through the event 10708 * loop. Waits for the specified amount of time.</p> 10709 * 10710 * <p>This method can be invoked from outside of the UI thread 10711 * only when this View is attached to a window.</p> 10712 * 10713 * @param delayMilliseconds the duration in milliseconds to delay the 10714 * invalidation by 10715 * 10716 * @see #invalidate() 10717 * @see #postInvalidate() 10718 */ 10719 public void postInvalidateDelayed(long delayMilliseconds) { 10720 // We try only with the AttachInfo because there's no point in invalidating 10721 // if we are not attached to our window 10722 final AttachInfo attachInfo = mAttachInfo; 10723 if (attachInfo != null) { 10724 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 10725 } 10726 } 10727 10728 /** 10729 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 10730 * through the event loop. Waits for the specified amount of time.</p> 10731 * 10732 * <p>This method can be invoked from outside of the UI thread 10733 * only when this View is attached to a window.</p> 10734 * 10735 * @param delayMilliseconds the duration in milliseconds to delay the 10736 * invalidation by 10737 * @param left The left coordinate of the rectangle to invalidate. 10738 * @param top The top coordinate of the rectangle to invalidate. 10739 * @param right The right coordinate of the rectangle to invalidate. 10740 * @param bottom The bottom coordinate of the rectangle to invalidate. 10741 * 10742 * @see #invalidate(int, int, int, int) 10743 * @see #invalidate(Rect) 10744 * @see #postInvalidate(int, int, int, int) 10745 */ 10746 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 10747 int right, int bottom) { 10748 10749 // We try only with the AttachInfo because there's no point in invalidating 10750 // if we are not attached to our window 10751 final AttachInfo attachInfo = mAttachInfo; 10752 if (attachInfo != null) { 10753 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire(); 10754 info.target = this; 10755 info.left = left; 10756 info.top = top; 10757 info.right = right; 10758 info.bottom = bottom; 10759 10760 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 10761 } 10762 } 10763 10764 /** 10765 * <p>Cause an invalidate to happen on the next animation time step, typically the 10766 * next display frame.</p> 10767 * 10768 * <p>This method can be invoked from outside of the UI thread 10769 * only when this View is attached to a window.</p> 10770 * 10771 * @see #invalidate() 10772 */ 10773 public void postInvalidateOnAnimation() { 10774 // We try only with the AttachInfo because there's no point in invalidating 10775 // if we are not attached to our window 10776 final AttachInfo attachInfo = mAttachInfo; 10777 if (attachInfo != null) { 10778 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 10779 } 10780 } 10781 10782 /** 10783 * <p>Cause an invalidate of the specified area to happen on the next animation 10784 * time step, typically the next display frame.</p> 10785 * 10786 * <p>This method can be invoked from outside of the UI thread 10787 * only when this View is attached to a window.</p> 10788 * 10789 * @param left The left coordinate of the rectangle to invalidate. 10790 * @param top The top coordinate of the rectangle to invalidate. 10791 * @param right The right coordinate of the rectangle to invalidate. 10792 * @param bottom The bottom coordinate of the rectangle to invalidate. 10793 * 10794 * @see #invalidate(int, int, int, int) 10795 * @see #invalidate(Rect) 10796 */ 10797 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 10798 // We try only with the AttachInfo because there's no point in invalidating 10799 // if we are not attached to our window 10800 final AttachInfo attachInfo = mAttachInfo; 10801 if (attachInfo != null) { 10802 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire(); 10803 info.target = this; 10804 info.left = left; 10805 info.top = top; 10806 info.right = right; 10807 info.bottom = bottom; 10808 10809 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 10810 } 10811 } 10812 10813 /** 10814 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 10815 * This event is sent at most once every 10816 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 10817 */ 10818 private void postSendViewScrolledAccessibilityEventCallback() { 10819 if (mSendViewScrolledAccessibilityEvent == null) { 10820 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 10821 } 10822 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 10823 mSendViewScrolledAccessibilityEvent.mIsPending = true; 10824 postDelayed(mSendViewScrolledAccessibilityEvent, 10825 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 10826 } 10827 } 10828 10829 /** 10830 * Called by a parent to request that a child update its values for mScrollX 10831 * and mScrollY if necessary. This will typically be done if the child is 10832 * animating a scroll using a {@link android.widget.Scroller Scroller} 10833 * object. 10834 */ 10835 public void computeScroll() { 10836 } 10837 10838 /** 10839 * <p>Indicate whether the horizontal edges are faded when the view is 10840 * scrolled horizontally.</p> 10841 * 10842 * @return true if the horizontal edges should are faded on scroll, false 10843 * otherwise 10844 * 10845 * @see #setHorizontalFadingEdgeEnabled(boolean) 10846 * 10847 * @attr ref android.R.styleable#View_requiresFadingEdge 10848 */ 10849 public boolean isHorizontalFadingEdgeEnabled() { 10850 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 10851 } 10852 10853 /** 10854 * <p>Define whether the horizontal edges should be faded when this view 10855 * is scrolled horizontally.</p> 10856 * 10857 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 10858 * be faded when the view is scrolled 10859 * horizontally 10860 * 10861 * @see #isHorizontalFadingEdgeEnabled() 10862 * 10863 * @attr ref android.R.styleable#View_requiresFadingEdge 10864 */ 10865 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 10866 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 10867 if (horizontalFadingEdgeEnabled) { 10868 initScrollCache(); 10869 } 10870 10871 mViewFlags ^= FADING_EDGE_HORIZONTAL; 10872 } 10873 } 10874 10875 /** 10876 * <p>Indicate whether the vertical edges are faded when the view is 10877 * scrolled horizontally.</p> 10878 * 10879 * @return true if the vertical edges should are faded on scroll, false 10880 * otherwise 10881 * 10882 * @see #setVerticalFadingEdgeEnabled(boolean) 10883 * 10884 * @attr ref android.R.styleable#View_requiresFadingEdge 10885 */ 10886 public boolean isVerticalFadingEdgeEnabled() { 10887 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 10888 } 10889 10890 /** 10891 * <p>Define whether the vertical edges should be faded when this view 10892 * is scrolled vertically.</p> 10893 * 10894 * @param verticalFadingEdgeEnabled true if the vertical edges should 10895 * be faded when the view is scrolled 10896 * vertically 10897 * 10898 * @see #isVerticalFadingEdgeEnabled() 10899 * 10900 * @attr ref android.R.styleable#View_requiresFadingEdge 10901 */ 10902 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 10903 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 10904 if (verticalFadingEdgeEnabled) { 10905 initScrollCache(); 10906 } 10907 10908 mViewFlags ^= FADING_EDGE_VERTICAL; 10909 } 10910 } 10911 10912 /** 10913 * Returns the strength, or intensity, of the top faded edge. The strength is 10914 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 10915 * returns 0.0 or 1.0 but no value in between. 10916 * 10917 * Subclasses should override this method to provide a smoother fade transition 10918 * when scrolling occurs. 10919 * 10920 * @return the intensity of the top fade as a float between 0.0f and 1.0f 10921 */ 10922 protected float getTopFadingEdgeStrength() { 10923 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 10924 } 10925 10926 /** 10927 * Returns the strength, or intensity, of the bottom faded edge. The strength is 10928 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 10929 * returns 0.0 or 1.0 but no value in between. 10930 * 10931 * Subclasses should override this method to provide a smoother fade transition 10932 * when scrolling occurs. 10933 * 10934 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 10935 */ 10936 protected float getBottomFadingEdgeStrength() { 10937 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 10938 computeVerticalScrollRange() ? 1.0f : 0.0f; 10939 } 10940 10941 /** 10942 * Returns the strength, or intensity, of the left faded edge. The strength is 10943 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 10944 * returns 0.0 or 1.0 but no value in between. 10945 * 10946 * Subclasses should override this method to provide a smoother fade transition 10947 * when scrolling occurs. 10948 * 10949 * @return the intensity of the left fade as a float between 0.0f and 1.0f 10950 */ 10951 protected float getLeftFadingEdgeStrength() { 10952 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 10953 } 10954 10955 /** 10956 * Returns the strength, or intensity, of the right faded edge. The strength is 10957 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 10958 * returns 0.0 or 1.0 but no value in between. 10959 * 10960 * Subclasses should override this method to provide a smoother fade transition 10961 * when scrolling occurs. 10962 * 10963 * @return the intensity of the right fade as a float between 0.0f and 1.0f 10964 */ 10965 protected float getRightFadingEdgeStrength() { 10966 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 10967 computeHorizontalScrollRange() ? 1.0f : 0.0f; 10968 } 10969 10970 /** 10971 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 10972 * scrollbar is not drawn by default.</p> 10973 * 10974 * @return true if the horizontal scrollbar should be painted, false 10975 * otherwise 10976 * 10977 * @see #setHorizontalScrollBarEnabled(boolean) 10978 */ 10979 public boolean isHorizontalScrollBarEnabled() { 10980 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 10981 } 10982 10983 /** 10984 * <p>Define whether the horizontal scrollbar should be drawn or not. The 10985 * scrollbar is not drawn by default.</p> 10986 * 10987 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 10988 * be painted 10989 * 10990 * @see #isHorizontalScrollBarEnabled() 10991 */ 10992 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 10993 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 10994 mViewFlags ^= SCROLLBARS_HORIZONTAL; 10995 computeOpaqueFlags(); 10996 resolvePadding(); 10997 } 10998 } 10999 11000 /** 11001 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 11002 * scrollbar is not drawn by default.</p> 11003 * 11004 * @return true if the vertical scrollbar should be painted, false 11005 * otherwise 11006 * 11007 * @see #setVerticalScrollBarEnabled(boolean) 11008 */ 11009 public boolean isVerticalScrollBarEnabled() { 11010 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 11011 } 11012 11013 /** 11014 * <p>Define whether the vertical scrollbar should be drawn or not. The 11015 * scrollbar is not drawn by default.</p> 11016 * 11017 * @param verticalScrollBarEnabled true if the vertical scrollbar should 11018 * be painted 11019 * 11020 * @see #isVerticalScrollBarEnabled() 11021 */ 11022 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 11023 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 11024 mViewFlags ^= SCROLLBARS_VERTICAL; 11025 computeOpaqueFlags(); 11026 resolvePadding(); 11027 } 11028 } 11029 11030 /** 11031 * @hide 11032 */ 11033 protected void recomputePadding() { 11034 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 11035 } 11036 11037 /** 11038 * Define whether scrollbars will fade when the view is not scrolling. 11039 * 11040 * @param fadeScrollbars wheter to enable fading 11041 * 11042 * @attr ref android.R.styleable#View_fadeScrollbars 11043 */ 11044 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 11045 initScrollCache(); 11046 final ScrollabilityCache scrollabilityCache = mScrollCache; 11047 scrollabilityCache.fadeScrollBars = fadeScrollbars; 11048 if (fadeScrollbars) { 11049 scrollabilityCache.state = ScrollabilityCache.OFF; 11050 } else { 11051 scrollabilityCache.state = ScrollabilityCache.ON; 11052 } 11053 } 11054 11055 /** 11056 * 11057 * Returns true if scrollbars will fade when this view is not scrolling 11058 * 11059 * @return true if scrollbar fading is enabled 11060 * 11061 * @attr ref android.R.styleable#View_fadeScrollbars 11062 */ 11063 public boolean isScrollbarFadingEnabled() { 11064 return mScrollCache != null && mScrollCache.fadeScrollBars; 11065 } 11066 11067 /** 11068 * 11069 * Returns the delay before scrollbars fade. 11070 * 11071 * @return the delay before scrollbars fade 11072 * 11073 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 11074 */ 11075 public int getScrollBarDefaultDelayBeforeFade() { 11076 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 11077 mScrollCache.scrollBarDefaultDelayBeforeFade; 11078 } 11079 11080 /** 11081 * Define the delay before scrollbars fade. 11082 * 11083 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 11084 * 11085 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 11086 */ 11087 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 11088 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 11089 } 11090 11091 /** 11092 * 11093 * Returns the scrollbar fade duration. 11094 * 11095 * @return the scrollbar fade duration 11096 * 11097 * @attr ref android.R.styleable#View_scrollbarFadeDuration 11098 */ 11099 public int getScrollBarFadeDuration() { 11100 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 11101 mScrollCache.scrollBarFadeDuration; 11102 } 11103 11104 /** 11105 * Define the scrollbar fade duration. 11106 * 11107 * @param scrollBarFadeDuration - the scrollbar fade duration 11108 * 11109 * @attr ref android.R.styleable#View_scrollbarFadeDuration 11110 */ 11111 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 11112 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 11113 } 11114 11115 /** 11116 * 11117 * Returns the scrollbar size. 11118 * 11119 * @return the scrollbar size 11120 * 11121 * @attr ref android.R.styleable#View_scrollbarSize 11122 */ 11123 public int getScrollBarSize() { 11124 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 11125 mScrollCache.scrollBarSize; 11126 } 11127 11128 /** 11129 * Define the scrollbar size. 11130 * 11131 * @param scrollBarSize - the scrollbar size 11132 * 11133 * @attr ref android.R.styleable#View_scrollbarSize 11134 */ 11135 public void setScrollBarSize(int scrollBarSize) { 11136 getScrollCache().scrollBarSize = scrollBarSize; 11137 } 11138 11139 /** 11140 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 11141 * inset. When inset, they add to the padding of the view. And the scrollbars 11142 * can be drawn inside the padding area or on the edge of the view. For example, 11143 * if a view has a background drawable and you want to draw the scrollbars 11144 * inside the padding specified by the drawable, you can use 11145 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 11146 * appear at the edge of the view, ignoring the padding, then you can use 11147 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 11148 * @param style the style of the scrollbars. Should be one of 11149 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 11150 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 11151 * @see #SCROLLBARS_INSIDE_OVERLAY 11152 * @see #SCROLLBARS_INSIDE_INSET 11153 * @see #SCROLLBARS_OUTSIDE_OVERLAY 11154 * @see #SCROLLBARS_OUTSIDE_INSET 11155 * 11156 * @attr ref android.R.styleable#View_scrollbarStyle 11157 */ 11158 public void setScrollBarStyle(int style) { 11159 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 11160 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 11161 computeOpaqueFlags(); 11162 resolvePadding(); 11163 } 11164 } 11165 11166 /** 11167 * <p>Returns the current scrollbar style.</p> 11168 * @return the current scrollbar style 11169 * @see #SCROLLBARS_INSIDE_OVERLAY 11170 * @see #SCROLLBARS_INSIDE_INSET 11171 * @see #SCROLLBARS_OUTSIDE_OVERLAY 11172 * @see #SCROLLBARS_OUTSIDE_INSET 11173 * 11174 * @attr ref android.R.styleable#View_scrollbarStyle 11175 */ 11176 @ViewDebug.ExportedProperty(mapping = { 11177 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 11178 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 11179 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 11180 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 11181 }) 11182 public int getScrollBarStyle() { 11183 return mViewFlags & SCROLLBARS_STYLE_MASK; 11184 } 11185 11186 /** 11187 * <p>Compute the horizontal range that the horizontal scrollbar 11188 * represents.</p> 11189 * 11190 * <p>The range is expressed in arbitrary units that must be the same as the 11191 * units used by {@link #computeHorizontalScrollExtent()} and 11192 * {@link #computeHorizontalScrollOffset()}.</p> 11193 * 11194 * <p>The default range is the drawing width of this view.</p> 11195 * 11196 * @return the total horizontal range represented by the horizontal 11197 * scrollbar 11198 * 11199 * @see #computeHorizontalScrollExtent() 11200 * @see #computeHorizontalScrollOffset() 11201 * @see android.widget.ScrollBarDrawable 11202 */ 11203 protected int computeHorizontalScrollRange() { 11204 return getWidth(); 11205 } 11206 11207 /** 11208 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 11209 * within the horizontal range. This value is used to compute the position 11210 * of the thumb within the scrollbar's track.</p> 11211 * 11212 * <p>The range is expressed in arbitrary units that must be the same as the 11213 * units used by {@link #computeHorizontalScrollRange()} and 11214 * {@link #computeHorizontalScrollExtent()}.</p> 11215 * 11216 * <p>The default offset is the scroll offset of this view.</p> 11217 * 11218 * @return the horizontal offset of the scrollbar's thumb 11219 * 11220 * @see #computeHorizontalScrollRange() 11221 * @see #computeHorizontalScrollExtent() 11222 * @see android.widget.ScrollBarDrawable 11223 */ 11224 protected int computeHorizontalScrollOffset() { 11225 return mScrollX; 11226 } 11227 11228 /** 11229 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 11230 * within the horizontal range. This value is used to compute the length 11231 * of the thumb within the scrollbar's track.</p> 11232 * 11233 * <p>The range is expressed in arbitrary units that must be the same as the 11234 * units used by {@link #computeHorizontalScrollRange()} and 11235 * {@link #computeHorizontalScrollOffset()}.</p> 11236 * 11237 * <p>The default extent is the drawing width of this view.</p> 11238 * 11239 * @return the horizontal extent of the scrollbar's thumb 11240 * 11241 * @see #computeHorizontalScrollRange() 11242 * @see #computeHorizontalScrollOffset() 11243 * @see android.widget.ScrollBarDrawable 11244 */ 11245 protected int computeHorizontalScrollExtent() { 11246 return getWidth(); 11247 } 11248 11249 /** 11250 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 11251 * 11252 * <p>The range is expressed in arbitrary units that must be the same as the 11253 * units used by {@link #computeVerticalScrollExtent()} and 11254 * {@link #computeVerticalScrollOffset()}.</p> 11255 * 11256 * @return the total vertical range represented by the vertical scrollbar 11257 * 11258 * <p>The default range is the drawing height of this view.</p> 11259 * 11260 * @see #computeVerticalScrollExtent() 11261 * @see #computeVerticalScrollOffset() 11262 * @see android.widget.ScrollBarDrawable 11263 */ 11264 protected int computeVerticalScrollRange() { 11265 return getHeight(); 11266 } 11267 11268 /** 11269 * <p>Compute the vertical offset of the vertical scrollbar's thumb 11270 * within the horizontal range. This value is used to compute the position 11271 * of the thumb within the scrollbar's track.</p> 11272 * 11273 * <p>The range is expressed in arbitrary units that must be the same as the 11274 * units used by {@link #computeVerticalScrollRange()} and 11275 * {@link #computeVerticalScrollExtent()}.</p> 11276 * 11277 * <p>The default offset is the scroll offset of this view.</p> 11278 * 11279 * @return the vertical offset of the scrollbar's thumb 11280 * 11281 * @see #computeVerticalScrollRange() 11282 * @see #computeVerticalScrollExtent() 11283 * @see android.widget.ScrollBarDrawable 11284 */ 11285 protected int computeVerticalScrollOffset() { 11286 return mScrollY; 11287 } 11288 11289 /** 11290 * <p>Compute the vertical extent of the horizontal scrollbar's thumb 11291 * within the vertical range. This value is used to compute the length 11292 * of the thumb within the scrollbar's track.</p> 11293 * 11294 * <p>The range is expressed in arbitrary units that must be the same as the 11295 * units used by {@link #computeVerticalScrollRange()} and 11296 * {@link #computeVerticalScrollOffset()}.</p> 11297 * 11298 * <p>The default extent is the drawing height of this view.</p> 11299 * 11300 * @return the vertical extent of the scrollbar's thumb 11301 * 11302 * @see #computeVerticalScrollRange() 11303 * @see #computeVerticalScrollOffset() 11304 * @see android.widget.ScrollBarDrawable 11305 */ 11306 protected int computeVerticalScrollExtent() { 11307 return getHeight(); 11308 } 11309 11310 /** 11311 * Check if this view can be scrolled horizontally in a certain direction. 11312 * 11313 * @param direction Negative to check scrolling left, positive to check scrolling right. 11314 * @return true if this view can be scrolled in the specified direction, false otherwise. 11315 */ 11316 public boolean canScrollHorizontally(int direction) { 11317 final int offset = computeHorizontalScrollOffset(); 11318 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 11319 if (range == 0) return false; 11320 if (direction < 0) { 11321 return offset > 0; 11322 } else { 11323 return offset < range - 1; 11324 } 11325 } 11326 11327 /** 11328 * Check if this view can be scrolled vertically in a certain direction. 11329 * 11330 * @param direction Negative to check scrolling up, positive to check scrolling down. 11331 * @return true if this view can be scrolled in the specified direction, false otherwise. 11332 */ 11333 public boolean canScrollVertically(int direction) { 11334 final int offset = computeVerticalScrollOffset(); 11335 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 11336 if (range == 0) return false; 11337 if (direction < 0) { 11338 return offset > 0; 11339 } else { 11340 return offset < range - 1; 11341 } 11342 } 11343 11344 /** 11345 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 11346 * scrollbars are painted only if they have been awakened first.</p> 11347 * 11348 * @param canvas the canvas on which to draw the scrollbars 11349 * 11350 * @see #awakenScrollBars(int) 11351 */ 11352 protected final void onDrawScrollBars(Canvas canvas) { 11353 // scrollbars are drawn only when the animation is running 11354 final ScrollabilityCache cache = mScrollCache; 11355 if (cache != null) { 11356 11357 int state = cache.state; 11358 11359 if (state == ScrollabilityCache.OFF) { 11360 return; 11361 } 11362 11363 boolean invalidate = false; 11364 11365 if (state == ScrollabilityCache.FADING) { 11366 // We're fading -- get our fade interpolation 11367 if (cache.interpolatorValues == null) { 11368 cache.interpolatorValues = new float[1]; 11369 } 11370 11371 float[] values = cache.interpolatorValues; 11372 11373 // Stops the animation if we're done 11374 if (cache.scrollBarInterpolator.timeToValues(values) == 11375 Interpolator.Result.FREEZE_END) { 11376 cache.state = ScrollabilityCache.OFF; 11377 } else { 11378 cache.scrollBar.setAlpha(Math.round(values[0])); 11379 } 11380 11381 // This will make the scroll bars inval themselves after 11382 // drawing. We only want this when we're fading so that 11383 // we prevent excessive redraws 11384 invalidate = true; 11385 } else { 11386 // We're just on -- but we may have been fading before so 11387 // reset alpha 11388 cache.scrollBar.setAlpha(255); 11389 } 11390 11391 11392 final int viewFlags = mViewFlags; 11393 11394 final boolean drawHorizontalScrollBar = 11395 (viewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 11396 final boolean drawVerticalScrollBar = 11397 (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL 11398 && !isVerticalScrollBarHidden(); 11399 11400 if (drawVerticalScrollBar || drawHorizontalScrollBar) { 11401 final int width = mRight - mLeft; 11402 final int height = mBottom - mTop; 11403 11404 final ScrollBarDrawable scrollBar = cache.scrollBar; 11405 11406 final int scrollX = mScrollX; 11407 final int scrollY = mScrollY; 11408 final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 11409 11410 int left, top, right, bottom; 11411 11412 if (drawHorizontalScrollBar) { 11413 int size = scrollBar.getSize(false); 11414 if (size <= 0) { 11415 size = cache.scrollBarSize; 11416 } 11417 11418 scrollBar.setParameters(computeHorizontalScrollRange(), 11419 computeHorizontalScrollOffset(), 11420 computeHorizontalScrollExtent(), false); 11421 final int verticalScrollBarGap = drawVerticalScrollBar ? 11422 getVerticalScrollbarWidth() : 0; 11423 top = scrollY + height - size - (mUserPaddingBottom & inside); 11424 left = scrollX + (mPaddingLeft & inside); 11425 right = scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 11426 bottom = top + size; 11427 onDrawHorizontalScrollBar(canvas, scrollBar, left, top, right, bottom); 11428 if (invalidate) { 11429 invalidate(left, top, right, bottom); 11430 } 11431 } 11432 11433 if (drawVerticalScrollBar) { 11434 int size = scrollBar.getSize(true); 11435 if (size <= 0) { 11436 size = cache.scrollBarSize; 11437 } 11438 11439 scrollBar.setParameters(computeVerticalScrollRange(), 11440 computeVerticalScrollOffset(), 11441 computeVerticalScrollExtent(), true); 11442 int verticalScrollbarPosition = mVerticalScrollbarPosition; 11443 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 11444 verticalScrollbarPosition = isLayoutRtl() ? 11445 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 11446 } 11447 switch (verticalScrollbarPosition) { 11448 default: 11449 case SCROLLBAR_POSITION_RIGHT: 11450 left = scrollX + width - size - (mUserPaddingRight & inside); 11451 break; 11452 case SCROLLBAR_POSITION_LEFT: 11453 left = scrollX + (mUserPaddingLeft & inside); 11454 break; 11455 } 11456 top = scrollY + (mPaddingTop & inside); 11457 right = left + size; 11458 bottom = scrollY + height - (mUserPaddingBottom & inside); 11459 onDrawVerticalScrollBar(canvas, scrollBar, left, top, right, bottom); 11460 if (invalidate) { 11461 invalidate(left, top, right, bottom); 11462 } 11463 } 11464 } 11465 } 11466 } 11467 11468 /** 11469 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 11470 * FastScroller is visible. 11471 * @return whether to temporarily hide the vertical scrollbar 11472 * @hide 11473 */ 11474 protected boolean isVerticalScrollBarHidden() { 11475 return false; 11476 } 11477 11478 /** 11479 * <p>Draw the horizontal scrollbar if 11480 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 11481 * 11482 * @param canvas the canvas on which to draw the scrollbar 11483 * @param scrollBar the scrollbar's drawable 11484 * 11485 * @see #isHorizontalScrollBarEnabled() 11486 * @see #computeHorizontalScrollRange() 11487 * @see #computeHorizontalScrollExtent() 11488 * @see #computeHorizontalScrollOffset() 11489 * @see android.widget.ScrollBarDrawable 11490 * @hide 11491 */ 11492 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 11493 int l, int t, int r, int b) { 11494 scrollBar.setBounds(l, t, r, b); 11495 scrollBar.draw(canvas); 11496 } 11497 11498 /** 11499 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 11500 * returns true.</p> 11501 * 11502 * @param canvas the canvas on which to draw the scrollbar 11503 * @param scrollBar the scrollbar's drawable 11504 * 11505 * @see #isVerticalScrollBarEnabled() 11506 * @see #computeVerticalScrollRange() 11507 * @see #computeVerticalScrollExtent() 11508 * @see #computeVerticalScrollOffset() 11509 * @see android.widget.ScrollBarDrawable 11510 * @hide 11511 */ 11512 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 11513 int l, int t, int r, int b) { 11514 scrollBar.setBounds(l, t, r, b); 11515 scrollBar.draw(canvas); 11516 } 11517 11518 /** 11519 * Implement this to do your drawing. 11520 * 11521 * @param canvas the canvas on which the background will be drawn 11522 */ 11523 protected void onDraw(Canvas canvas) { 11524 } 11525 11526 /* 11527 * Caller is responsible for calling requestLayout if necessary. 11528 * (This allows addViewInLayout to not request a new layout.) 11529 */ 11530 void assignParent(ViewParent parent) { 11531 if (mParent == null) { 11532 mParent = parent; 11533 } else if (parent == null) { 11534 mParent = null; 11535 } else { 11536 throw new RuntimeException("view " + this + " being added, but" 11537 + " it already has a parent"); 11538 } 11539 } 11540 11541 /** 11542 * This is called when the view is attached to a window. At this point it 11543 * has a Surface and will start drawing. Note that this function is 11544 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 11545 * however it may be called any time before the first onDraw -- including 11546 * before or after {@link #onMeasure(int, int)}. 11547 * 11548 * @see #onDetachedFromWindow() 11549 */ 11550 protected void onAttachedToWindow() { 11551 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 11552 mParent.requestTransparentRegion(this); 11553 } 11554 11555 if ((mPrivateFlags & PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH) != 0) { 11556 initialAwakenScrollBars(); 11557 mPrivateFlags &= ~PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH; 11558 } 11559 11560 jumpDrawablesToCurrentState(); 11561 11562 clearAccessibilityFocus(); 11563 if (isFocused()) { 11564 InputMethodManager imm = InputMethodManager.peekInstance(); 11565 imm.focusIn(this); 11566 } 11567 11568 if (mAttachInfo != null && mDisplayList != null) { 11569 mAttachInfo.mViewRootImpl.dequeueDisplayList(mDisplayList); 11570 } 11571 } 11572 11573 /** 11574 * Resolve all RTL related properties. 11575 * 11576 * @hide 11577 */ 11578 public void resolveRtlPropertiesIfNeeded() { 11579 if (!needRtlPropertiesResolution()) return; 11580 11581 // Order is important here: LayoutDirection MUST be resolved first 11582 if (!isLayoutDirectionResolved()) { 11583 resolveLayoutDirection(); 11584 resolveLayoutParams(); 11585 } 11586 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 11587 if (!isTextDirectionResolved()) { 11588 resolveTextDirection(); 11589 } 11590 if (!isTextAlignmentResolved()) { 11591 resolveTextAlignment(); 11592 } 11593 if (!isPaddingResolved()) { 11594 resolvePadding(); 11595 } 11596 if (!isDrawablesResolved()) { 11597 resolveDrawables(); 11598 } 11599 onRtlPropertiesChanged(getLayoutDirection()); 11600 } 11601 11602 /** 11603 * Reset resolution of all RTL related properties. 11604 * 11605 * @hide 11606 */ 11607 public void resetRtlProperties() { 11608 resetResolvedLayoutDirection(); 11609 resetResolvedTextDirection(); 11610 resetResolvedTextAlignment(); 11611 resetResolvedPadding(); 11612 resetResolvedDrawables(); 11613 } 11614 11615 /** 11616 * @see #onScreenStateChanged(int) 11617 */ 11618 void dispatchScreenStateChanged(int screenState) { 11619 onScreenStateChanged(screenState); 11620 } 11621 11622 /** 11623 * This method is called whenever the state of the screen this view is 11624 * attached to changes. A state change will usually occurs when the screen 11625 * turns on or off (whether it happens automatically or the user does it 11626 * manually.) 11627 * 11628 * @param screenState The new state of the screen. Can be either 11629 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 11630 */ 11631 public void onScreenStateChanged(int screenState) { 11632 } 11633 11634 /** 11635 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 11636 */ 11637 private boolean hasRtlSupport() { 11638 return mContext.getApplicationInfo().hasRtlSupport(); 11639 } 11640 11641 /** 11642 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 11643 * RTL not supported) 11644 */ 11645 private boolean isRtlCompatibilityMode() { 11646 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 11647 return targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport(); 11648 } 11649 11650 /** 11651 * @return true if RTL properties need resolution. 11652 */ 11653 private boolean needRtlPropertiesResolution() { 11654 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 11655 } 11656 11657 /** 11658 * Called when any RTL property (layout direction or text direction or text alignment) has 11659 * been changed. 11660 * 11661 * Subclasses need to override this method to take care of cached information that depends on the 11662 * resolved layout direction, or to inform child views that inherit their layout direction. 11663 * 11664 * The default implementation does nothing. 11665 * 11666 * @param layoutDirection the direction of the layout 11667 * 11668 * @see #LAYOUT_DIRECTION_LTR 11669 * @see #LAYOUT_DIRECTION_RTL 11670 */ 11671 public void onRtlPropertiesChanged(int layoutDirection) { 11672 } 11673 11674 /** 11675 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 11676 * that the parent directionality can and will be resolved before its children. 11677 * 11678 * @return true if resolution has been done, false otherwise. 11679 * 11680 * @hide 11681 */ 11682 public boolean resolveLayoutDirection() { 11683 // Clear any previous layout direction resolution 11684 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 11685 11686 if (hasRtlSupport()) { 11687 // Set resolved depending on layout direction 11688 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 11689 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 11690 case LAYOUT_DIRECTION_INHERIT: 11691 // We cannot resolve yet. LTR is by default and let the resolution happen again 11692 // later to get the correct resolved value 11693 if (!canResolveLayoutDirection()) return false; 11694 11695 View parent = ((View) mParent); 11696 // Parent has not yet resolved, LTR is still the default 11697 if (!parent.isLayoutDirectionResolved()) return false; 11698 11699 if (parent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 11700 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 11701 } 11702 break; 11703 case LAYOUT_DIRECTION_RTL: 11704 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 11705 break; 11706 case LAYOUT_DIRECTION_LOCALE: 11707 if((LAYOUT_DIRECTION_RTL == 11708 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 11709 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 11710 } 11711 break; 11712 default: 11713 // Nothing to do, LTR by default 11714 } 11715 } 11716 11717 // Set to resolved 11718 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 11719 return true; 11720 } 11721 11722 /** 11723 * Check if layout direction resolution can be done. 11724 * 11725 * @return true if layout direction resolution can be done otherwise return false. 11726 * 11727 * @hide 11728 */ 11729 public boolean canResolveLayoutDirection() { 11730 switch (getRawLayoutDirection()) { 11731 case LAYOUT_DIRECTION_INHERIT: 11732 return (mParent != null) && (mParent instanceof ViewGroup) && 11733 ((ViewGroup) mParent).canResolveLayoutDirection(); 11734 default: 11735 return true; 11736 } 11737 } 11738 11739 /** 11740 * Reset the resolved layout direction. Layout direction will be resolved during a call to 11741 * {@link #onMeasure(int, int)}. 11742 * 11743 * @hide 11744 */ 11745 public void resetResolvedLayoutDirection() { 11746 // Reset the current resolved bits 11747 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 11748 } 11749 11750 /** 11751 * @return true if the layout direction is inherited. 11752 * 11753 * @hide 11754 */ 11755 public boolean isLayoutDirectionInherited() { 11756 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 11757 } 11758 11759 /** 11760 * @return true if layout direction has been resolved. 11761 */ 11762 private boolean isLayoutDirectionResolved() { 11763 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 11764 } 11765 11766 /** 11767 * Return if padding has been resolved 11768 * 11769 * @hide 11770 */ 11771 boolean isPaddingResolved() { 11772 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 11773 } 11774 11775 /** 11776 * Resolve padding depending on layout direction. 11777 * 11778 * @hide 11779 */ 11780 public void resolvePadding() { 11781 if (!isRtlCompatibilityMode()) { 11782 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 11783 // If start / end padding are defined, they will be resolved (hence overriding) to 11784 // left / right or right / left depending on the resolved layout direction. 11785 // If start / end padding are not defined, use the left / right ones. 11786 int resolvedLayoutDirection = getLayoutDirection(); 11787 // Set user padding to initial values ... 11788 mUserPaddingLeft = mUserPaddingLeftInitial; 11789 mUserPaddingRight = mUserPaddingRightInitial; 11790 // ... then resolve it. 11791 switch (resolvedLayoutDirection) { 11792 case LAYOUT_DIRECTION_RTL: 11793 if (mUserPaddingStart != UNDEFINED_PADDING) { 11794 mUserPaddingRight = mUserPaddingStart; 11795 } 11796 if (mUserPaddingEnd != UNDEFINED_PADDING) { 11797 mUserPaddingLeft = mUserPaddingEnd; 11798 } 11799 break; 11800 case LAYOUT_DIRECTION_LTR: 11801 default: 11802 if (mUserPaddingStart != UNDEFINED_PADDING) { 11803 mUserPaddingLeft = mUserPaddingStart; 11804 } 11805 if (mUserPaddingEnd != UNDEFINED_PADDING) { 11806 mUserPaddingRight = mUserPaddingEnd; 11807 } 11808 } 11809 11810 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 11811 11812 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, 11813 mUserPaddingBottom); 11814 onRtlPropertiesChanged(resolvedLayoutDirection); 11815 } 11816 11817 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 11818 } 11819 11820 /** 11821 * Reset the resolved layout direction. 11822 * 11823 * @hide 11824 */ 11825 public void resetResolvedPadding() { 11826 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 11827 } 11828 11829 /** 11830 * This is called when the view is detached from a window. At this point it 11831 * no longer has a surface for drawing. 11832 * 11833 * @see #onAttachedToWindow() 11834 */ 11835 protected void onDetachedFromWindow() { 11836 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 11837 11838 removeUnsetPressCallback(); 11839 removeLongPressCallback(); 11840 removePerformClickCallback(); 11841 removeSendViewScrolledAccessibilityEventCallback(); 11842 11843 destroyDrawingCache(); 11844 11845 destroyLayer(false); 11846 11847 if (mAttachInfo != null) { 11848 if (mDisplayList != null) { 11849 mAttachInfo.mViewRootImpl.enqueueDisplayList(mDisplayList); 11850 } 11851 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 11852 } else { 11853 // Should never happen 11854 clearDisplayList(); 11855 } 11856 11857 mCurrentAnimation = null; 11858 11859 resetAccessibilityStateChanged(); 11860 } 11861 11862 /** 11863 * @return The number of times this view has been attached to a window 11864 */ 11865 protected int getWindowAttachCount() { 11866 return mWindowAttachCount; 11867 } 11868 11869 /** 11870 * Retrieve a unique token identifying the window this view is attached to. 11871 * @return Return the window's token for use in 11872 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 11873 */ 11874 public IBinder getWindowToken() { 11875 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 11876 } 11877 11878 /** 11879 * Retrieve a unique token identifying the top-level "real" window of 11880 * the window that this view is attached to. That is, this is like 11881 * {@link #getWindowToken}, except if the window this view in is a panel 11882 * window (attached to another containing window), then the token of 11883 * the containing window is returned instead. 11884 * 11885 * @return Returns the associated window token, either 11886 * {@link #getWindowToken()} or the containing window's token. 11887 */ 11888 public IBinder getApplicationWindowToken() { 11889 AttachInfo ai = mAttachInfo; 11890 if (ai != null) { 11891 IBinder appWindowToken = ai.mPanelParentWindowToken; 11892 if (appWindowToken == null) { 11893 appWindowToken = ai.mWindowToken; 11894 } 11895 return appWindowToken; 11896 } 11897 return null; 11898 } 11899 11900 /** 11901 * Gets the logical display to which the view's window has been attached. 11902 * 11903 * @return The logical display, or null if the view is not currently attached to a window. 11904 */ 11905 public Display getDisplay() { 11906 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 11907 } 11908 11909 /** 11910 * Retrieve private session object this view hierarchy is using to 11911 * communicate with the window manager. 11912 * @return the session object to communicate with the window manager 11913 */ 11914 /*package*/ IWindowSession getWindowSession() { 11915 return mAttachInfo != null ? mAttachInfo.mSession : null; 11916 } 11917 11918 /** 11919 * @param info the {@link android.view.View.AttachInfo} to associated with 11920 * this view 11921 */ 11922 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 11923 //System.out.println("Attached! " + this); 11924 mAttachInfo = info; 11925 mWindowAttachCount++; 11926 // We will need to evaluate the drawable state at least once. 11927 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 11928 if (mFloatingTreeObserver != null) { 11929 info.mTreeObserver.merge(mFloatingTreeObserver); 11930 mFloatingTreeObserver = null; 11931 } 11932 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 11933 mAttachInfo.mScrollContainers.add(this); 11934 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 11935 } 11936 performCollectViewAttributes(mAttachInfo, visibility); 11937 onAttachedToWindow(); 11938 11939 ListenerInfo li = mListenerInfo; 11940 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 11941 li != null ? li.mOnAttachStateChangeListeners : null; 11942 if (listeners != null && listeners.size() > 0) { 11943 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 11944 // perform the dispatching. The iterator is a safe guard against listeners that 11945 // could mutate the list by calling the various add/remove methods. This prevents 11946 // the array from being modified while we iterate it. 11947 for (OnAttachStateChangeListener listener : listeners) { 11948 listener.onViewAttachedToWindow(this); 11949 } 11950 } 11951 11952 int vis = info.mWindowVisibility; 11953 if (vis != GONE) { 11954 onWindowVisibilityChanged(vis); 11955 } 11956 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 11957 // If nobody has evaluated the drawable state yet, then do it now. 11958 refreshDrawableState(); 11959 } 11960 needGlobalAttributesUpdate(false); 11961 } 11962 11963 void dispatchDetachedFromWindow() { 11964 AttachInfo info = mAttachInfo; 11965 if (info != null) { 11966 int vis = info.mWindowVisibility; 11967 if (vis != GONE) { 11968 onWindowVisibilityChanged(GONE); 11969 } 11970 } 11971 11972 onDetachedFromWindow(); 11973 11974 ListenerInfo li = mListenerInfo; 11975 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 11976 li != null ? li.mOnAttachStateChangeListeners : null; 11977 if (listeners != null && listeners.size() > 0) { 11978 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 11979 // perform the dispatching. The iterator is a safe guard against listeners that 11980 // could mutate the list by calling the various add/remove methods. This prevents 11981 // the array from being modified while we iterate it. 11982 for (OnAttachStateChangeListener listener : listeners) { 11983 listener.onViewDetachedFromWindow(this); 11984 } 11985 } 11986 11987 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 11988 mAttachInfo.mScrollContainers.remove(this); 11989 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 11990 } 11991 11992 mAttachInfo = null; 11993 } 11994 11995 /** 11996 * Store this view hierarchy's frozen state into the given container. 11997 * 11998 * @param container The SparseArray in which to save the view's state. 11999 * 12000 * @see #restoreHierarchyState(android.util.SparseArray) 12001 * @see #dispatchSaveInstanceState(android.util.SparseArray) 12002 * @see #onSaveInstanceState() 12003 */ 12004 public void saveHierarchyState(SparseArray<Parcelable> container) { 12005 dispatchSaveInstanceState(container); 12006 } 12007 12008 /** 12009 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 12010 * this view and its children. May be overridden to modify how freezing happens to a 12011 * view's children; for example, some views may want to not store state for their children. 12012 * 12013 * @param container The SparseArray in which to save the view's state. 12014 * 12015 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 12016 * @see #saveHierarchyState(android.util.SparseArray) 12017 * @see #onSaveInstanceState() 12018 */ 12019 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 12020 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 12021 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 12022 Parcelable state = onSaveInstanceState(); 12023 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 12024 throw new IllegalStateException( 12025 "Derived class did not call super.onSaveInstanceState()"); 12026 } 12027 if (state != null) { 12028 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 12029 // + ": " + state); 12030 container.put(mID, state); 12031 } 12032 } 12033 } 12034 12035 /** 12036 * Hook allowing a view to generate a representation of its internal state 12037 * that can later be used to create a new instance with that same state. 12038 * This state should only contain information that is not persistent or can 12039 * not be reconstructed later. For example, you will never store your 12040 * current position on screen because that will be computed again when a 12041 * new instance of the view is placed in its view hierarchy. 12042 * <p> 12043 * Some examples of things you may store here: the current cursor position 12044 * in a text view (but usually not the text itself since that is stored in a 12045 * content provider or other persistent storage), the currently selected 12046 * item in a list view. 12047 * 12048 * @return Returns a Parcelable object containing the view's current dynamic 12049 * state, or null if there is nothing interesting to save. The 12050 * default implementation returns null. 12051 * @see #onRestoreInstanceState(android.os.Parcelable) 12052 * @see #saveHierarchyState(android.util.SparseArray) 12053 * @see #dispatchSaveInstanceState(android.util.SparseArray) 12054 * @see #setSaveEnabled(boolean) 12055 */ 12056 protected Parcelable onSaveInstanceState() { 12057 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 12058 return BaseSavedState.EMPTY_STATE; 12059 } 12060 12061 /** 12062 * Restore this view hierarchy's frozen state from the given container. 12063 * 12064 * @param container The SparseArray which holds previously frozen states. 12065 * 12066 * @see #saveHierarchyState(android.util.SparseArray) 12067 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 12068 * @see #onRestoreInstanceState(android.os.Parcelable) 12069 */ 12070 public void restoreHierarchyState(SparseArray<Parcelable> container) { 12071 dispatchRestoreInstanceState(container); 12072 } 12073 12074 /** 12075 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 12076 * state for this view and its children. May be overridden to modify how restoring 12077 * happens to a view's children; for example, some views may want to not store state 12078 * for their children. 12079 * 12080 * @param container The SparseArray which holds previously saved state. 12081 * 12082 * @see #dispatchSaveInstanceState(android.util.SparseArray) 12083 * @see #restoreHierarchyState(android.util.SparseArray) 12084 * @see #onRestoreInstanceState(android.os.Parcelable) 12085 */ 12086 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 12087 if (mID != NO_ID) { 12088 Parcelable state = container.get(mID); 12089 if (state != null) { 12090 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 12091 // + ": " + state); 12092 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 12093 onRestoreInstanceState(state); 12094 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 12095 throw new IllegalStateException( 12096 "Derived class did not call super.onRestoreInstanceState()"); 12097 } 12098 } 12099 } 12100 } 12101 12102 /** 12103 * Hook allowing a view to re-apply a representation of its internal state that had previously 12104 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 12105 * null state. 12106 * 12107 * @param state The frozen state that had previously been returned by 12108 * {@link #onSaveInstanceState}. 12109 * 12110 * @see #onSaveInstanceState() 12111 * @see #restoreHierarchyState(android.util.SparseArray) 12112 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 12113 */ 12114 protected void onRestoreInstanceState(Parcelable state) { 12115 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 12116 if (state != BaseSavedState.EMPTY_STATE && state != null) { 12117 throw new IllegalArgumentException("Wrong state class, expecting View State but " 12118 + "received " + state.getClass().toString() + " instead. This usually happens " 12119 + "when two views of different type have the same id in the same hierarchy. " 12120 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 12121 + "other views do not use the same id."); 12122 } 12123 } 12124 12125 /** 12126 * <p>Return the time at which the drawing of the view hierarchy started.</p> 12127 * 12128 * @return the drawing start time in milliseconds 12129 */ 12130 public long getDrawingTime() { 12131 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 12132 } 12133 12134 /** 12135 * <p>Enables or disables the duplication of the parent's state into this view. When 12136 * duplication is enabled, this view gets its drawable state from its parent rather 12137 * than from its own internal properties.</p> 12138 * 12139 * <p>Note: in the current implementation, setting this property to true after the 12140 * view was added to a ViewGroup might have no effect at all. This property should 12141 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 12142 * 12143 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 12144 * property is enabled, an exception will be thrown.</p> 12145 * 12146 * <p>Note: if the child view uses and updates additionnal states which are unknown to the 12147 * parent, these states should not be affected by this method.</p> 12148 * 12149 * @param enabled True to enable duplication of the parent's drawable state, false 12150 * to disable it. 12151 * 12152 * @see #getDrawableState() 12153 * @see #isDuplicateParentStateEnabled() 12154 */ 12155 public void setDuplicateParentStateEnabled(boolean enabled) { 12156 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 12157 } 12158 12159 /** 12160 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 12161 * 12162 * @return True if this view's drawable state is duplicated from the parent, 12163 * false otherwise 12164 * 12165 * @see #getDrawableState() 12166 * @see #setDuplicateParentStateEnabled(boolean) 12167 */ 12168 public boolean isDuplicateParentStateEnabled() { 12169 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 12170 } 12171 12172 /** 12173 * <p>Specifies the type of layer backing this view. The layer can be 12174 * {@link #LAYER_TYPE_NONE disabled}, {@link #LAYER_TYPE_SOFTWARE software} or 12175 * {@link #LAYER_TYPE_HARDWARE hardware}.</p> 12176 * 12177 * <p>A layer is associated with an optional {@link android.graphics.Paint} 12178 * instance that controls how the layer is composed on screen. The following 12179 * properties of the paint are taken into account when composing the layer:</p> 12180 * <ul> 12181 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 12182 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 12183 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 12184 * </ul> 12185 * 12186 * <p>If this view has an alpha value set to < 1.0 by calling 12187 * {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by 12188 * this view's alpha value. Calling {@link #setAlpha(float)} is therefore 12189 * equivalent to setting a hardware layer on this view and providing a paint with 12190 * the desired alpha value.</p> 12191 * 12192 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE disabled}, 12193 * {@link #LAYER_TYPE_SOFTWARE software} and {@link #LAYER_TYPE_HARDWARE hardware} 12194 * for more information on when and how to use layers.</p> 12195 * 12196 * @param layerType The type of layer to use with this view, must be one of 12197 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 12198 * {@link #LAYER_TYPE_HARDWARE} 12199 * @param paint The paint used to compose the layer. This argument is optional 12200 * and can be null. It is ignored when the layer type is 12201 * {@link #LAYER_TYPE_NONE} 12202 * 12203 * @see #getLayerType() 12204 * @see #LAYER_TYPE_NONE 12205 * @see #LAYER_TYPE_SOFTWARE 12206 * @see #LAYER_TYPE_HARDWARE 12207 * @see #setAlpha(float) 12208 * 12209 * @attr ref android.R.styleable#View_layerType 12210 */ 12211 public void setLayerType(int layerType, Paint paint) { 12212 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 12213 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 12214 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 12215 } 12216 12217 if (layerType == mLayerType) { 12218 if (layerType != LAYER_TYPE_NONE && paint != mLayerPaint) { 12219 mLayerPaint = paint == null ? new Paint() : paint; 12220 invalidateParentCaches(); 12221 invalidate(true); 12222 } 12223 return; 12224 } 12225 12226 // Destroy any previous software drawing cache if needed 12227 switch (mLayerType) { 12228 case LAYER_TYPE_HARDWARE: 12229 destroyLayer(false); 12230 // fall through - non-accelerated views may use software layer mechanism instead 12231 case LAYER_TYPE_SOFTWARE: 12232 destroyDrawingCache(); 12233 break; 12234 default: 12235 break; 12236 } 12237 12238 mLayerType = layerType; 12239 final boolean layerDisabled = mLayerType == LAYER_TYPE_NONE; 12240 mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint); 12241 mLocalDirtyRect = layerDisabled ? null : new Rect(); 12242 12243 invalidateParentCaches(); 12244 invalidate(true); 12245 } 12246 12247 /** 12248 * Updates the {@link Paint} object used with the current layer (used only if the current 12249 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 12250 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 12251 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 12252 * ensure that the view gets redrawn immediately. 12253 * 12254 * <p>A layer is associated with an optional {@link android.graphics.Paint} 12255 * instance that controls how the layer is composed on screen. The following 12256 * properties of the paint are taken into account when composing the layer:</p> 12257 * <ul> 12258 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 12259 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 12260 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 12261 * </ul> 12262 * 12263 * <p>If this view has an alpha value set to < 1.0 by calling 12264 * {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by 12265 * this view's alpha value. Calling {@link #setAlpha(float)} is therefore 12266 * equivalent to setting a hardware layer on this view and providing a paint with 12267 * the desired alpha value.</p> 12268 * 12269 * @param paint The paint used to compose the layer. This argument is optional 12270 * and can be null. It is ignored when the layer type is 12271 * {@link #LAYER_TYPE_NONE} 12272 * 12273 * @see #setLayerType(int, android.graphics.Paint) 12274 */ 12275 public void setLayerPaint(Paint paint) { 12276 int layerType = getLayerType(); 12277 if (layerType != LAYER_TYPE_NONE) { 12278 mLayerPaint = paint == null ? new Paint() : paint; 12279 if (layerType == LAYER_TYPE_HARDWARE) { 12280 HardwareLayer layer = getHardwareLayer(); 12281 if (layer != null) { 12282 layer.setLayerPaint(paint); 12283 } 12284 invalidateViewProperty(false, false); 12285 } else { 12286 invalidate(); 12287 } 12288 } 12289 } 12290 12291 /** 12292 * Indicates whether this view has a static layer. A view with layer type 12293 * {@link #LAYER_TYPE_NONE} is a static layer. Other types of layers are 12294 * dynamic. 12295 */ 12296 boolean hasStaticLayer() { 12297 return true; 12298 } 12299 12300 /** 12301 * Indicates what type of layer is currently associated with this view. By default 12302 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 12303 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 12304 * for more information on the different types of layers. 12305 * 12306 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 12307 * {@link #LAYER_TYPE_HARDWARE} 12308 * 12309 * @see #setLayerType(int, android.graphics.Paint) 12310 * @see #buildLayer() 12311 * @see #LAYER_TYPE_NONE 12312 * @see #LAYER_TYPE_SOFTWARE 12313 * @see #LAYER_TYPE_HARDWARE 12314 */ 12315 public int getLayerType() { 12316 return mLayerType; 12317 } 12318 12319 /** 12320 * Forces this view's layer to be created and this view to be rendered 12321 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 12322 * invoking this method will have no effect. 12323 * 12324 * This method can for instance be used to render a view into its layer before 12325 * starting an animation. If this view is complex, rendering into the layer 12326 * before starting the animation will avoid skipping frames. 12327 * 12328 * @throws IllegalStateException If this view is not attached to a window 12329 * 12330 * @see #setLayerType(int, android.graphics.Paint) 12331 */ 12332 public void buildLayer() { 12333 if (mLayerType == LAYER_TYPE_NONE) return; 12334 12335 if (mAttachInfo == null) { 12336 throw new IllegalStateException("This view must be attached to a window first"); 12337 } 12338 12339 switch (mLayerType) { 12340 case LAYER_TYPE_HARDWARE: 12341 if (mAttachInfo.mHardwareRenderer != null && 12342 mAttachInfo.mHardwareRenderer.isEnabled() && 12343 mAttachInfo.mHardwareRenderer.validate()) { 12344 getHardwareLayer(); 12345 } 12346 break; 12347 case LAYER_TYPE_SOFTWARE: 12348 buildDrawingCache(true); 12349 break; 12350 } 12351 } 12352 12353 /** 12354 * <p>Returns a hardware layer that can be used to draw this view again 12355 * without executing its draw method.</p> 12356 * 12357 * @return A HardwareLayer ready to render, or null if an error occurred. 12358 */ 12359 HardwareLayer getHardwareLayer() { 12360 if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null || 12361 !mAttachInfo.mHardwareRenderer.isEnabled()) { 12362 return null; 12363 } 12364 12365 if (!mAttachInfo.mHardwareRenderer.validate()) return null; 12366 12367 final int width = mRight - mLeft; 12368 final int height = mBottom - mTop; 12369 12370 if (width == 0 || height == 0) { 12371 return null; 12372 } 12373 12374 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) { 12375 if (mHardwareLayer == null) { 12376 mHardwareLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer( 12377 width, height, isOpaque()); 12378 mLocalDirtyRect.set(0, 0, width, height); 12379 } else { 12380 if (mHardwareLayer.getWidth() != width || mHardwareLayer.getHeight() != height) { 12381 if (mHardwareLayer.resize(width, height)) { 12382 mLocalDirtyRect.set(0, 0, width, height); 12383 } 12384 } 12385 12386 // This should not be necessary but applications that change 12387 // the parameters of their background drawable without calling 12388 // this.setBackground(Drawable) can leave the view in a bad state 12389 // (for instance isOpaque() returns true, but the background is 12390 // not opaque.) 12391 computeOpaqueFlags(); 12392 12393 final boolean opaque = isOpaque(); 12394 if (mHardwareLayer.isValid() && mHardwareLayer.isOpaque() != opaque) { 12395 mHardwareLayer.setOpaque(opaque); 12396 mLocalDirtyRect.set(0, 0, width, height); 12397 } 12398 } 12399 12400 // The layer is not valid if the underlying GPU resources cannot be allocated 12401 if (!mHardwareLayer.isValid()) { 12402 return null; 12403 } 12404 12405 mHardwareLayer.setLayerPaint(mLayerPaint); 12406 mHardwareLayer.redrawLater(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect); 12407 ViewRootImpl viewRoot = getViewRootImpl(); 12408 if (viewRoot != null) viewRoot.pushHardwareLayerUpdate(mHardwareLayer); 12409 12410 mLocalDirtyRect.setEmpty(); 12411 } 12412 12413 return mHardwareLayer; 12414 } 12415 12416 /** 12417 * Destroys this View's hardware layer if possible. 12418 * 12419 * @return True if the layer was destroyed, false otherwise. 12420 * 12421 * @see #setLayerType(int, android.graphics.Paint) 12422 * @see #LAYER_TYPE_HARDWARE 12423 */ 12424 boolean destroyLayer(boolean valid) { 12425 if (mHardwareLayer != null) { 12426 AttachInfo info = mAttachInfo; 12427 if (info != null && info.mHardwareRenderer != null && 12428 info.mHardwareRenderer.isEnabled() && 12429 (valid || info.mHardwareRenderer.validate())) { 12430 mHardwareLayer.destroy(); 12431 mHardwareLayer = null; 12432 12433 if (mDisplayList != null) { 12434 mDisplayList.reset(); 12435 } 12436 invalidate(true); 12437 invalidateParentCaches(); 12438 } 12439 return true; 12440 } 12441 return false; 12442 } 12443 12444 /** 12445 * Destroys all hardware rendering resources. This method is invoked 12446 * when the system needs to reclaim resources. Upon execution of this 12447 * method, you should free any OpenGL resources created by the view. 12448 * 12449 * Note: you <strong>must</strong> call 12450 * <code>super.destroyHardwareResources()</code> when overriding 12451 * this method. 12452 * 12453 * @hide 12454 */ 12455 protected void destroyHardwareResources() { 12456 destroyLayer(true); 12457 } 12458 12459 /** 12460 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 12461 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 12462 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 12463 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 12464 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 12465 * null.</p> 12466 * 12467 * <p>Enabling the drawing cache is similar to 12468 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 12469 * acceleration is turned off. When hardware acceleration is turned on, enabling the 12470 * drawing cache has no effect on rendering because the system uses a different mechanism 12471 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 12472 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 12473 * for information on how to enable software and hardware layers.</p> 12474 * 12475 * <p>This API can be used to manually generate 12476 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 12477 * {@link #getDrawingCache()}.</p> 12478 * 12479 * @param enabled true to enable the drawing cache, false otherwise 12480 * 12481 * @see #isDrawingCacheEnabled() 12482 * @see #getDrawingCache() 12483 * @see #buildDrawingCache() 12484 * @see #setLayerType(int, android.graphics.Paint) 12485 */ 12486 public void setDrawingCacheEnabled(boolean enabled) { 12487 mCachingFailed = false; 12488 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 12489 } 12490 12491 /** 12492 * <p>Indicates whether the drawing cache is enabled for this view.</p> 12493 * 12494 * @return true if the drawing cache is enabled 12495 * 12496 * @see #setDrawingCacheEnabled(boolean) 12497 * @see #getDrawingCache() 12498 */ 12499 @ViewDebug.ExportedProperty(category = "drawing") 12500 public boolean isDrawingCacheEnabled() { 12501 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 12502 } 12503 12504 /** 12505 * Debugging utility which recursively outputs the dirty state of a view and its 12506 * descendants. 12507 * 12508 * @hide 12509 */ 12510 @SuppressWarnings({"UnusedDeclaration"}) 12511 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 12512 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 12513 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 12514 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 12515 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 12516 if (clear) { 12517 mPrivateFlags &= clearMask; 12518 } 12519 if (this instanceof ViewGroup) { 12520 ViewGroup parent = (ViewGroup) this; 12521 final int count = parent.getChildCount(); 12522 for (int i = 0; i < count; i++) { 12523 final View child = parent.getChildAt(i); 12524 child.outputDirtyFlags(indent + " ", clear, clearMask); 12525 } 12526 } 12527 } 12528 12529 /** 12530 * This method is used by ViewGroup to cause its children to restore or recreate their 12531 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 12532 * to recreate its own display list, which would happen if it went through the normal 12533 * draw/dispatchDraw mechanisms. 12534 * 12535 * @hide 12536 */ 12537 protected void dispatchGetDisplayList() {} 12538 12539 /** 12540 * A view that is not attached or hardware accelerated cannot create a display list. 12541 * This method checks these conditions and returns the appropriate result. 12542 * 12543 * @return true if view has the ability to create a display list, false otherwise. 12544 * 12545 * @hide 12546 */ 12547 public boolean canHaveDisplayList() { 12548 return !(mAttachInfo == null || mAttachInfo.mHardwareRenderer == null); 12549 } 12550 12551 /** 12552 * @return The HardwareRenderer associated with that view or null if hardware rendering 12553 * is not supported or this this has not been attached to a window. 12554 * 12555 * @hide 12556 */ 12557 public HardwareRenderer getHardwareRenderer() { 12558 if (mAttachInfo != null) { 12559 return mAttachInfo.mHardwareRenderer; 12560 } 12561 return null; 12562 } 12563 12564 /** 12565 * Returns a DisplayList. If the incoming displayList is null, one will be created. 12566 * Otherwise, the same display list will be returned (after having been rendered into 12567 * along the way, depending on the invalidation state of the view). 12568 * 12569 * @param displayList The previous version of this displayList, could be null. 12570 * @param isLayer Whether the requester of the display list is a layer. If so, 12571 * the view will avoid creating a layer inside the resulting display list. 12572 * @return A new or reused DisplayList object. 12573 */ 12574 private DisplayList getDisplayList(DisplayList displayList, boolean isLayer) { 12575 if (!canHaveDisplayList()) { 12576 return null; 12577 } 12578 12579 if (((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || 12580 displayList == null || !displayList.isValid() || 12581 (!isLayer && mRecreateDisplayList))) { 12582 // Don't need to recreate the display list, just need to tell our 12583 // children to restore/recreate theirs 12584 if (displayList != null && displayList.isValid() && 12585 !isLayer && !mRecreateDisplayList) { 12586 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 12587 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 12588 dispatchGetDisplayList(); 12589 12590 return displayList; 12591 } 12592 12593 if (!isLayer) { 12594 // If we got here, we're recreating it. Mark it as such to ensure that 12595 // we copy in child display lists into ours in drawChild() 12596 mRecreateDisplayList = true; 12597 } 12598 if (displayList == null) { 12599 final String name = getClass().getSimpleName(); 12600 displayList = mAttachInfo.mHardwareRenderer.createDisplayList(name); 12601 // If we're creating a new display list, make sure our parent gets invalidated 12602 // since they will need to recreate their display list to account for this 12603 // new child display list. 12604 invalidateParentCaches(); 12605 } 12606 12607 boolean caching = false; 12608 final HardwareCanvas canvas = displayList.start(); 12609 int width = mRight - mLeft; 12610 int height = mBottom - mTop; 12611 12612 try { 12613 canvas.setViewport(width, height); 12614 // The dirty rect should always be null for a display list 12615 canvas.onPreDraw(null); 12616 int layerType = getLayerType(); 12617 if (!isLayer && layerType != LAYER_TYPE_NONE) { 12618 if (layerType == LAYER_TYPE_HARDWARE) { 12619 final HardwareLayer layer = getHardwareLayer(); 12620 if (layer != null && layer.isValid()) { 12621 canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint); 12622 } else { 12623 canvas.saveLayer(0, 0, mRight - mLeft, mBottom - mTop, mLayerPaint, 12624 Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | 12625 Canvas.CLIP_TO_LAYER_SAVE_FLAG); 12626 } 12627 caching = true; 12628 } else { 12629 buildDrawingCache(true); 12630 Bitmap cache = getDrawingCache(true); 12631 if (cache != null) { 12632 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 12633 caching = true; 12634 } 12635 } 12636 } else { 12637 12638 computeScroll(); 12639 12640 canvas.translate(-mScrollX, -mScrollY); 12641 if (!isLayer) { 12642 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 12643 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 12644 } 12645 12646 // Fast path for layouts with no backgrounds 12647 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 12648 dispatchDraw(canvas); 12649 } else { 12650 draw(canvas); 12651 } 12652 } 12653 } finally { 12654 canvas.onPostDraw(); 12655 12656 displayList.end(); 12657 displayList.setCaching(caching); 12658 if (isLayer) { 12659 displayList.setLeftTopRightBottom(0, 0, width, height); 12660 } else { 12661 setDisplayListProperties(displayList); 12662 } 12663 } 12664 } else if (!isLayer) { 12665 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 12666 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 12667 } 12668 12669 return displayList; 12670 } 12671 12672 /** 12673 * Get the DisplayList for the HardwareLayer 12674 * 12675 * @param layer The HardwareLayer whose DisplayList we want 12676 * @return A DisplayList fopr the specified HardwareLayer 12677 */ 12678 private DisplayList getHardwareLayerDisplayList(HardwareLayer layer) { 12679 DisplayList displayList = getDisplayList(layer.getDisplayList(), true); 12680 layer.setDisplayList(displayList); 12681 return displayList; 12682 } 12683 12684 12685 /** 12686 * <p>Returns a display list that can be used to draw this view again 12687 * without executing its draw method.</p> 12688 * 12689 * @return A DisplayList ready to replay, or null if caching is not enabled. 12690 * 12691 * @hide 12692 */ 12693 public DisplayList getDisplayList() { 12694 mDisplayList = getDisplayList(mDisplayList, false); 12695 return mDisplayList; 12696 } 12697 12698 private void clearDisplayList() { 12699 if (mDisplayList != null) { 12700 mDisplayList.invalidate(); 12701 mDisplayList.clear(); 12702 } 12703 } 12704 12705 /** 12706 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 12707 * 12708 * @return A non-scaled bitmap representing this view or null if cache is disabled. 12709 * 12710 * @see #getDrawingCache(boolean) 12711 */ 12712 public Bitmap getDrawingCache() { 12713 return getDrawingCache(false); 12714 } 12715 12716 /** 12717 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 12718 * is null when caching is disabled. If caching is enabled and the cache is not ready, 12719 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 12720 * draw from the cache when the cache is enabled. To benefit from the cache, you must 12721 * request the drawing cache by calling this method and draw it on screen if the 12722 * returned bitmap is not null.</p> 12723 * 12724 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 12725 * this method will create a bitmap of the same size as this view. Because this bitmap 12726 * will be drawn scaled by the parent ViewGroup, the result on screen might show 12727 * scaling artifacts. To avoid such artifacts, you should call this method by setting 12728 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 12729 * size than the view. This implies that your application must be able to handle this 12730 * size.</p> 12731 * 12732 * @param autoScale Indicates whether the generated bitmap should be scaled based on 12733 * the current density of the screen when the application is in compatibility 12734 * mode. 12735 * 12736 * @return A bitmap representing this view or null if cache is disabled. 12737 * 12738 * @see #setDrawingCacheEnabled(boolean) 12739 * @see #isDrawingCacheEnabled() 12740 * @see #buildDrawingCache(boolean) 12741 * @see #destroyDrawingCache() 12742 */ 12743 public Bitmap getDrawingCache(boolean autoScale) { 12744 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 12745 return null; 12746 } 12747 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 12748 buildDrawingCache(autoScale); 12749 } 12750 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 12751 } 12752 12753 /** 12754 * <p>Frees the resources used by the drawing cache. If you call 12755 * {@link #buildDrawingCache()} manually without calling 12756 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 12757 * should cleanup the cache with this method afterwards.</p> 12758 * 12759 * @see #setDrawingCacheEnabled(boolean) 12760 * @see #buildDrawingCache() 12761 * @see #getDrawingCache() 12762 */ 12763 public void destroyDrawingCache() { 12764 if (mDrawingCache != null) { 12765 mDrawingCache.recycle(); 12766 mDrawingCache = null; 12767 } 12768 if (mUnscaledDrawingCache != null) { 12769 mUnscaledDrawingCache.recycle(); 12770 mUnscaledDrawingCache = null; 12771 } 12772 } 12773 12774 /** 12775 * Setting a solid background color for the drawing cache's bitmaps will improve 12776 * performance and memory usage. Note, though that this should only be used if this 12777 * view will always be drawn on top of a solid color. 12778 * 12779 * @param color The background color to use for the drawing cache's bitmap 12780 * 12781 * @see #setDrawingCacheEnabled(boolean) 12782 * @see #buildDrawingCache() 12783 * @see #getDrawingCache() 12784 */ 12785 public void setDrawingCacheBackgroundColor(int color) { 12786 if (color != mDrawingCacheBackgroundColor) { 12787 mDrawingCacheBackgroundColor = color; 12788 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12789 } 12790 } 12791 12792 /** 12793 * @see #setDrawingCacheBackgroundColor(int) 12794 * 12795 * @return The background color to used for the drawing cache's bitmap 12796 */ 12797 public int getDrawingCacheBackgroundColor() { 12798 return mDrawingCacheBackgroundColor; 12799 } 12800 12801 /** 12802 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 12803 * 12804 * @see #buildDrawingCache(boolean) 12805 */ 12806 public void buildDrawingCache() { 12807 buildDrawingCache(false); 12808 } 12809 12810 /** 12811 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 12812 * 12813 * <p>If you call {@link #buildDrawingCache()} manually without calling 12814 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 12815 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 12816 * 12817 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 12818 * this method will create a bitmap of the same size as this view. Because this bitmap 12819 * will be drawn scaled by the parent ViewGroup, the result on screen might show 12820 * scaling artifacts. To avoid such artifacts, you should call this method by setting 12821 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 12822 * size than the view. This implies that your application must be able to handle this 12823 * size.</p> 12824 * 12825 * <p>You should avoid calling this method when hardware acceleration is enabled. If 12826 * you do not need the drawing cache bitmap, calling this method will increase memory 12827 * usage and cause the view to be rendered in software once, thus negatively impacting 12828 * performance.</p> 12829 * 12830 * @see #getDrawingCache() 12831 * @see #destroyDrawingCache() 12832 */ 12833 public void buildDrawingCache(boolean autoScale) { 12834 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 12835 mDrawingCache == null : mUnscaledDrawingCache == null)) { 12836 mCachingFailed = false; 12837 12838 int width = mRight - mLeft; 12839 int height = mBottom - mTop; 12840 12841 final AttachInfo attachInfo = mAttachInfo; 12842 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 12843 12844 if (autoScale && scalingRequired) { 12845 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 12846 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 12847 } 12848 12849 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 12850 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 12851 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 12852 12853 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 12854 final long drawingCacheSize = 12855 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 12856 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 12857 if (width > 0 && height > 0) { 12858 Log.w(VIEW_LOG_TAG, "View too large to fit into drawing cache, needs " 12859 + projectedBitmapSize + " bytes, only " 12860 + drawingCacheSize + " available"); 12861 } 12862 destroyDrawingCache(); 12863 mCachingFailed = true; 12864 return; 12865 } 12866 12867 boolean clear = true; 12868 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 12869 12870 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 12871 Bitmap.Config quality; 12872 if (!opaque) { 12873 // Never pick ARGB_4444 because it looks awful 12874 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 12875 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 12876 case DRAWING_CACHE_QUALITY_AUTO: 12877 quality = Bitmap.Config.ARGB_8888; 12878 break; 12879 case DRAWING_CACHE_QUALITY_LOW: 12880 quality = Bitmap.Config.ARGB_8888; 12881 break; 12882 case DRAWING_CACHE_QUALITY_HIGH: 12883 quality = Bitmap.Config.ARGB_8888; 12884 break; 12885 default: 12886 quality = Bitmap.Config.ARGB_8888; 12887 break; 12888 } 12889 } else { 12890 // Optimization for translucent windows 12891 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 12892 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 12893 } 12894 12895 // Try to cleanup memory 12896 if (bitmap != null) bitmap.recycle(); 12897 12898 try { 12899 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 12900 width, height, quality); 12901 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 12902 if (autoScale) { 12903 mDrawingCache = bitmap; 12904 } else { 12905 mUnscaledDrawingCache = bitmap; 12906 } 12907 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 12908 } catch (OutOfMemoryError e) { 12909 // If there is not enough memory to create the bitmap cache, just 12910 // ignore the issue as bitmap caches are not required to draw the 12911 // view hierarchy 12912 if (autoScale) { 12913 mDrawingCache = null; 12914 } else { 12915 mUnscaledDrawingCache = null; 12916 } 12917 mCachingFailed = true; 12918 return; 12919 } 12920 12921 clear = drawingCacheBackgroundColor != 0; 12922 } 12923 12924 Canvas canvas; 12925 if (attachInfo != null) { 12926 canvas = attachInfo.mCanvas; 12927 if (canvas == null) { 12928 canvas = new Canvas(); 12929 } 12930 canvas.setBitmap(bitmap); 12931 // Temporarily clobber the cached Canvas in case one of our children 12932 // is also using a drawing cache. Without this, the children would 12933 // steal the canvas by attaching their own bitmap to it and bad, bad 12934 // thing would happen (invisible views, corrupted drawings, etc.) 12935 attachInfo.mCanvas = null; 12936 } else { 12937 // This case should hopefully never or seldom happen 12938 canvas = new Canvas(bitmap); 12939 } 12940 12941 if (clear) { 12942 bitmap.eraseColor(drawingCacheBackgroundColor); 12943 } 12944 12945 computeScroll(); 12946 final int restoreCount = canvas.save(); 12947 12948 if (autoScale && scalingRequired) { 12949 final float scale = attachInfo.mApplicationScale; 12950 canvas.scale(scale, scale); 12951 } 12952 12953 canvas.translate(-mScrollX, -mScrollY); 12954 12955 mPrivateFlags |= PFLAG_DRAWN; 12956 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 12957 mLayerType != LAYER_TYPE_NONE) { 12958 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 12959 } 12960 12961 // Fast path for layouts with no backgrounds 12962 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 12963 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 12964 dispatchDraw(canvas); 12965 } else { 12966 draw(canvas); 12967 } 12968 12969 canvas.restoreToCount(restoreCount); 12970 canvas.setBitmap(null); 12971 12972 if (attachInfo != null) { 12973 // Restore the cached Canvas for our siblings 12974 attachInfo.mCanvas = canvas; 12975 } 12976 } 12977 } 12978 12979 /** 12980 * Create a snapshot of the view into a bitmap. We should probably make 12981 * some form of this public, but should think about the API. 12982 */ 12983 Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 12984 int width = mRight - mLeft; 12985 int height = mBottom - mTop; 12986 12987 final AttachInfo attachInfo = mAttachInfo; 12988 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 12989 width = (int) ((width * scale) + 0.5f); 12990 height = (int) ((height * scale) + 0.5f); 12991 12992 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 12993 width > 0 ? width : 1, height > 0 ? height : 1, quality); 12994 if (bitmap == null) { 12995 throw new OutOfMemoryError(); 12996 } 12997 12998 Resources resources = getResources(); 12999 if (resources != null) { 13000 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 13001 } 13002 13003 Canvas canvas; 13004 if (attachInfo != null) { 13005 canvas = attachInfo.mCanvas; 13006 if (canvas == null) { 13007 canvas = new Canvas(); 13008 } 13009 canvas.setBitmap(bitmap); 13010 // Temporarily clobber the cached Canvas in case one of our children 13011 // is also using a drawing cache. Without this, the children would 13012 // steal the canvas by attaching their own bitmap to it and bad, bad 13013 // things would happen (invisible views, corrupted drawings, etc.) 13014 attachInfo.mCanvas = null; 13015 } else { 13016 // This case should hopefully never or seldom happen 13017 canvas = new Canvas(bitmap); 13018 } 13019 13020 if ((backgroundColor & 0xff000000) != 0) { 13021 bitmap.eraseColor(backgroundColor); 13022 } 13023 13024 computeScroll(); 13025 final int restoreCount = canvas.save(); 13026 canvas.scale(scale, scale); 13027 canvas.translate(-mScrollX, -mScrollY); 13028 13029 // Temporarily remove the dirty mask 13030 int flags = mPrivateFlags; 13031 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 13032 13033 // Fast path for layouts with no backgrounds 13034 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 13035 dispatchDraw(canvas); 13036 } else { 13037 draw(canvas); 13038 } 13039 13040 mPrivateFlags = flags; 13041 13042 canvas.restoreToCount(restoreCount); 13043 canvas.setBitmap(null); 13044 13045 if (attachInfo != null) { 13046 // Restore the cached Canvas for our siblings 13047 attachInfo.mCanvas = canvas; 13048 } 13049 13050 return bitmap; 13051 } 13052 13053 /** 13054 * Indicates whether this View is currently in edit mode. A View is usually 13055 * in edit mode when displayed within a developer tool. For instance, if 13056 * this View is being drawn by a visual user interface builder, this method 13057 * should return true. 13058 * 13059 * Subclasses should check the return value of this method to provide 13060 * different behaviors if their normal behavior might interfere with the 13061 * host environment. For instance: the class spawns a thread in its 13062 * constructor, the drawing code relies on device-specific features, etc. 13063 * 13064 * This method is usually checked in the drawing code of custom widgets. 13065 * 13066 * @return True if this View is in edit mode, false otherwise. 13067 */ 13068 public boolean isInEditMode() { 13069 return false; 13070 } 13071 13072 /** 13073 * If the View draws content inside its padding and enables fading edges, 13074 * it needs to support padding offsets. Padding offsets are added to the 13075 * fading edges to extend the length of the fade so that it covers pixels 13076 * drawn inside the padding. 13077 * 13078 * Subclasses of this class should override this method if they need 13079 * to draw content inside the padding. 13080 * 13081 * @return True if padding offset must be applied, false otherwise. 13082 * 13083 * @see #getLeftPaddingOffset() 13084 * @see #getRightPaddingOffset() 13085 * @see #getTopPaddingOffset() 13086 * @see #getBottomPaddingOffset() 13087 * 13088 * @since CURRENT 13089 */ 13090 protected boolean isPaddingOffsetRequired() { 13091 return false; 13092 } 13093 13094 /** 13095 * Amount by which to extend the left fading region. Called only when 13096 * {@link #isPaddingOffsetRequired()} returns true. 13097 * 13098 * @return The left padding offset in pixels. 13099 * 13100 * @see #isPaddingOffsetRequired() 13101 * 13102 * @since CURRENT 13103 */ 13104 protected int getLeftPaddingOffset() { 13105 return 0; 13106 } 13107 13108 /** 13109 * Amount by which to extend the right fading region. Called only when 13110 * {@link #isPaddingOffsetRequired()} returns true. 13111 * 13112 * @return The right padding offset in pixels. 13113 * 13114 * @see #isPaddingOffsetRequired() 13115 * 13116 * @since CURRENT 13117 */ 13118 protected int getRightPaddingOffset() { 13119 return 0; 13120 } 13121 13122 /** 13123 * Amount by which to extend the top fading region. Called only when 13124 * {@link #isPaddingOffsetRequired()} returns true. 13125 * 13126 * @return The top padding offset in pixels. 13127 * 13128 * @see #isPaddingOffsetRequired() 13129 * 13130 * @since CURRENT 13131 */ 13132 protected int getTopPaddingOffset() { 13133 return 0; 13134 } 13135 13136 /** 13137 * Amount by which to extend the bottom fading region. Called only when 13138 * {@link #isPaddingOffsetRequired()} returns true. 13139 * 13140 * @return The bottom padding offset in pixels. 13141 * 13142 * @see #isPaddingOffsetRequired() 13143 * 13144 * @since CURRENT 13145 */ 13146 protected int getBottomPaddingOffset() { 13147 return 0; 13148 } 13149 13150 /** 13151 * @hide 13152 * @param offsetRequired 13153 */ 13154 protected int getFadeTop(boolean offsetRequired) { 13155 int top = mPaddingTop; 13156 if (offsetRequired) top += getTopPaddingOffset(); 13157 return top; 13158 } 13159 13160 /** 13161 * @hide 13162 * @param offsetRequired 13163 */ 13164 protected int getFadeHeight(boolean offsetRequired) { 13165 int padding = mPaddingTop; 13166 if (offsetRequired) padding += getTopPaddingOffset(); 13167 return mBottom - mTop - mPaddingBottom - padding; 13168 } 13169 13170 /** 13171 * <p>Indicates whether this view is attached to a hardware accelerated 13172 * window or not.</p> 13173 * 13174 * <p>Even if this method returns true, it does not mean that every call 13175 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 13176 * accelerated {@link android.graphics.Canvas}. For instance, if this view 13177 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 13178 * window is hardware accelerated, 13179 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 13180 * return false, and this method will return true.</p> 13181 * 13182 * @return True if the view is attached to a window and the window is 13183 * hardware accelerated; false in any other case. 13184 */ 13185 public boolean isHardwareAccelerated() { 13186 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 13187 } 13188 13189 /** 13190 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 13191 * case of an active Animation being run on the view. 13192 */ 13193 private boolean drawAnimation(ViewGroup parent, long drawingTime, 13194 Animation a, boolean scalingRequired) { 13195 Transformation invalidationTransform; 13196 final int flags = parent.mGroupFlags; 13197 final boolean initialized = a.isInitialized(); 13198 if (!initialized) { 13199 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 13200 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 13201 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 13202 onAnimationStart(); 13203 } 13204 13205 boolean more = a.getTransformation(drawingTime, parent.mChildTransformation, 1f); 13206 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 13207 if (parent.mInvalidationTransformation == null) { 13208 parent.mInvalidationTransformation = new Transformation(); 13209 } 13210 invalidationTransform = parent.mInvalidationTransformation; 13211 a.getTransformation(drawingTime, invalidationTransform, 1f); 13212 } else { 13213 invalidationTransform = parent.mChildTransformation; 13214 } 13215 13216 if (more) { 13217 if (!a.willChangeBounds()) { 13218 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 13219 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 13220 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 13221 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 13222 // The child need to draw an animation, potentially offscreen, so 13223 // make sure we do not cancel invalidate requests 13224 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 13225 parent.invalidate(mLeft, mTop, mRight, mBottom); 13226 } 13227 } else { 13228 if (parent.mInvalidateRegion == null) { 13229 parent.mInvalidateRegion = new RectF(); 13230 } 13231 final RectF region = parent.mInvalidateRegion; 13232 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 13233 invalidationTransform); 13234 13235 // The child need to draw an animation, potentially offscreen, so 13236 // make sure we do not cancel invalidate requests 13237 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 13238 13239 final int left = mLeft + (int) region.left; 13240 final int top = mTop + (int) region.top; 13241 parent.invalidate(left, top, left + (int) (region.width() + .5f), 13242 top + (int) (region.height() + .5f)); 13243 } 13244 } 13245 return more; 13246 } 13247 13248 /** 13249 * This method is called by getDisplayList() when a display list is created or re-rendered. 13250 * It sets or resets the current value of all properties on that display list (resetting is 13251 * necessary when a display list is being re-created, because we need to make sure that 13252 * previously-set transform values 13253 */ 13254 void setDisplayListProperties(DisplayList displayList) { 13255 if (displayList != null) { 13256 displayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 13257 displayList.setHasOverlappingRendering(hasOverlappingRendering()); 13258 if (mParent instanceof ViewGroup) { 13259 displayList.setClipChildren( 13260 (((ViewGroup)mParent).mGroupFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0); 13261 } 13262 float alpha = 1; 13263 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 13264 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 13265 ViewGroup parentVG = (ViewGroup) mParent; 13266 final boolean hasTransform = 13267 parentVG.getChildStaticTransformation(this, parentVG.mChildTransformation); 13268 if (hasTransform) { 13269 Transformation transform = parentVG.mChildTransformation; 13270 final int transformType = parentVG.mChildTransformation.getTransformationType(); 13271 if (transformType != Transformation.TYPE_IDENTITY) { 13272 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 13273 alpha = transform.getAlpha(); 13274 } 13275 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 13276 displayList.setStaticMatrix(transform.getMatrix()); 13277 } 13278 } 13279 } 13280 } 13281 if (mTransformationInfo != null) { 13282 alpha *= mTransformationInfo.mAlpha; 13283 if (alpha < 1) { 13284 final int multipliedAlpha = (int) (255 * alpha); 13285 if (onSetAlpha(multipliedAlpha)) { 13286 alpha = 1; 13287 } 13288 } 13289 displayList.setTransformationInfo(alpha, 13290 mTransformationInfo.mTranslationX, mTransformationInfo.mTranslationY, 13291 mTransformationInfo.mRotation, mTransformationInfo.mRotationX, 13292 mTransformationInfo.mRotationY, mTransformationInfo.mScaleX, 13293 mTransformationInfo.mScaleY); 13294 if (mTransformationInfo.mCamera == null) { 13295 mTransformationInfo.mCamera = new Camera(); 13296 mTransformationInfo.matrix3D = new Matrix(); 13297 } 13298 displayList.setCameraDistance(mTransformationInfo.mCamera.getLocationZ()); 13299 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == PFLAG_PIVOT_EXPLICITLY_SET) { 13300 displayList.setPivotX(getPivotX()); 13301 displayList.setPivotY(getPivotY()); 13302 } 13303 } else if (alpha < 1) { 13304 displayList.setAlpha(alpha); 13305 } 13306 } 13307 } 13308 13309 /** 13310 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 13311 * This draw() method is an implementation detail and is not intended to be overridden or 13312 * to be called from anywhere else other than ViewGroup.drawChild(). 13313 */ 13314 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 13315 boolean useDisplayListProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 13316 boolean more = false; 13317 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 13318 final int flags = parent.mGroupFlags; 13319 13320 if ((flags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) == ViewGroup.FLAG_CLEAR_TRANSFORMATION) { 13321 parent.mChildTransformation.clear(); 13322 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 13323 } 13324 13325 Transformation transformToApply = null; 13326 boolean concatMatrix = false; 13327 13328 boolean scalingRequired = false; 13329 boolean caching; 13330 int layerType = getLayerType(); 13331 13332 final boolean hardwareAccelerated = canvas.isHardwareAccelerated(); 13333 if ((flags & ViewGroup.FLAG_CHILDREN_DRAWN_WITH_CACHE) != 0 || 13334 (flags & ViewGroup.FLAG_ALWAYS_DRAWN_WITH_CACHE) != 0) { 13335 caching = true; 13336 // Auto-scaled apps are not hw-accelerated, no need to set scaling flag on DisplayList 13337 if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired; 13338 } else { 13339 caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated; 13340 } 13341 13342 final Animation a = getAnimation(); 13343 if (a != null) { 13344 more = drawAnimation(parent, drawingTime, a, scalingRequired); 13345 concatMatrix = a.willChangeTransformationMatrix(); 13346 if (concatMatrix) { 13347 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 13348 } 13349 transformToApply = parent.mChildTransformation; 13350 } else { 13351 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) == PFLAG3_VIEW_IS_ANIMATING_TRANSFORM && 13352 mDisplayList != null) { 13353 // No longer animating: clear out old animation matrix 13354 mDisplayList.setAnimationMatrix(null); 13355 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 13356 } 13357 if (!useDisplayListProperties && 13358 (flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 13359 final boolean hasTransform = 13360 parent.getChildStaticTransformation(this, parent.mChildTransformation); 13361 if (hasTransform) { 13362 final int transformType = parent.mChildTransformation.getTransformationType(); 13363 transformToApply = transformType != Transformation.TYPE_IDENTITY ? 13364 parent.mChildTransformation : null; 13365 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 13366 } 13367 } 13368 } 13369 13370 concatMatrix |= !childHasIdentityMatrix; 13371 13372 // Sets the flag as early as possible to allow draw() implementations 13373 // to call invalidate() successfully when doing animations 13374 mPrivateFlags |= PFLAG_DRAWN; 13375 13376 if (!concatMatrix && 13377 (flags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 13378 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 13379 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 13380 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 13381 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 13382 return more; 13383 } 13384 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 13385 13386 if (hardwareAccelerated) { 13387 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 13388 // retain the flag's value temporarily in the mRecreateDisplayList flag 13389 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) == PFLAG_INVALIDATED; 13390 mPrivateFlags &= ~PFLAG_INVALIDATED; 13391 } 13392 13393 DisplayList displayList = null; 13394 Bitmap cache = null; 13395 boolean hasDisplayList = false; 13396 if (caching) { 13397 if (!hardwareAccelerated) { 13398 if (layerType != LAYER_TYPE_NONE) { 13399 layerType = LAYER_TYPE_SOFTWARE; 13400 buildDrawingCache(true); 13401 } 13402 cache = getDrawingCache(true); 13403 } else { 13404 switch (layerType) { 13405 case LAYER_TYPE_SOFTWARE: 13406 if (useDisplayListProperties) { 13407 hasDisplayList = canHaveDisplayList(); 13408 } else { 13409 buildDrawingCache(true); 13410 cache = getDrawingCache(true); 13411 } 13412 break; 13413 case LAYER_TYPE_HARDWARE: 13414 if (useDisplayListProperties) { 13415 hasDisplayList = canHaveDisplayList(); 13416 } 13417 break; 13418 case LAYER_TYPE_NONE: 13419 // Delay getting the display list until animation-driven alpha values are 13420 // set up and possibly passed on to the view 13421 hasDisplayList = canHaveDisplayList(); 13422 break; 13423 } 13424 } 13425 } 13426 useDisplayListProperties &= hasDisplayList; 13427 if (useDisplayListProperties) { 13428 displayList = getDisplayList(); 13429 if (!displayList.isValid()) { 13430 // Uncommon, but possible. If a view is removed from the hierarchy during the call 13431 // to getDisplayList(), the display list will be marked invalid and we should not 13432 // try to use it again. 13433 displayList = null; 13434 hasDisplayList = false; 13435 useDisplayListProperties = false; 13436 } 13437 } 13438 13439 int sx = 0; 13440 int sy = 0; 13441 if (!hasDisplayList) { 13442 computeScroll(); 13443 sx = mScrollX; 13444 sy = mScrollY; 13445 } 13446 13447 final boolean hasNoCache = cache == null || hasDisplayList; 13448 final boolean offsetForScroll = cache == null && !hasDisplayList && 13449 layerType != LAYER_TYPE_HARDWARE; 13450 13451 int restoreTo = -1; 13452 if (!useDisplayListProperties || transformToApply != null) { 13453 restoreTo = canvas.save(); 13454 } 13455 if (offsetForScroll) { 13456 canvas.translate(mLeft - sx, mTop - sy); 13457 } else { 13458 if (!useDisplayListProperties) { 13459 canvas.translate(mLeft, mTop); 13460 } 13461 if (scalingRequired) { 13462 if (useDisplayListProperties) { 13463 // TODO: Might not need this if we put everything inside the DL 13464 restoreTo = canvas.save(); 13465 } 13466 // mAttachInfo cannot be null, otherwise scalingRequired == false 13467 final float scale = 1.0f / mAttachInfo.mApplicationScale; 13468 canvas.scale(scale, scale); 13469 } 13470 } 13471 13472 float alpha = useDisplayListProperties ? 1 : getAlpha(); 13473 if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() || 13474 (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) { 13475 if (transformToApply != null || !childHasIdentityMatrix) { 13476 int transX = 0; 13477 int transY = 0; 13478 13479 if (offsetForScroll) { 13480 transX = -sx; 13481 transY = -sy; 13482 } 13483 13484 if (transformToApply != null) { 13485 if (concatMatrix) { 13486 if (useDisplayListProperties) { 13487 displayList.setAnimationMatrix(transformToApply.getMatrix()); 13488 } else { 13489 // Undo the scroll translation, apply the transformation matrix, 13490 // then redo the scroll translate to get the correct result. 13491 canvas.translate(-transX, -transY); 13492 canvas.concat(transformToApply.getMatrix()); 13493 canvas.translate(transX, transY); 13494 } 13495 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 13496 } 13497 13498 float transformAlpha = transformToApply.getAlpha(); 13499 if (transformAlpha < 1) { 13500 alpha *= transformAlpha; 13501 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 13502 } 13503 } 13504 13505 if (!childHasIdentityMatrix && !useDisplayListProperties) { 13506 canvas.translate(-transX, -transY); 13507 canvas.concat(getMatrix()); 13508 canvas.translate(transX, transY); 13509 } 13510 } 13511 13512 // Deal with alpha if it is or used to be <1 13513 if (alpha < 1 || 13514 (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) { 13515 if (alpha < 1) { 13516 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 13517 } else { 13518 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 13519 } 13520 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 13521 if (hasNoCache) { 13522 final int multipliedAlpha = (int) (255 * alpha); 13523 if (!onSetAlpha(multipliedAlpha)) { 13524 int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 13525 if ((flags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 || 13526 layerType != LAYER_TYPE_NONE) { 13527 layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG; 13528 } 13529 if (useDisplayListProperties) { 13530 displayList.setAlpha(alpha * getAlpha()); 13531 } else if (layerType == LAYER_TYPE_NONE) { 13532 final int scrollX = hasDisplayList ? 0 : sx; 13533 final int scrollY = hasDisplayList ? 0 : sy; 13534 canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft, 13535 scrollY + mBottom - mTop, multipliedAlpha, layerFlags); 13536 } 13537 } else { 13538 // Alpha is handled by the child directly, clobber the layer's alpha 13539 mPrivateFlags |= PFLAG_ALPHA_SET; 13540 } 13541 } 13542 } 13543 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 13544 onSetAlpha(255); 13545 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13546 } 13547 13548 if ((flags & ViewGroup.FLAG_CLIP_CHILDREN) == ViewGroup.FLAG_CLIP_CHILDREN && 13549 !useDisplayListProperties) { 13550 if (offsetForScroll) { 13551 canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop)); 13552 } else { 13553 if (!scalingRequired || cache == null) { 13554 canvas.clipRect(0, 0, mRight - mLeft, mBottom - mTop); 13555 } else { 13556 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 13557 } 13558 } 13559 } 13560 13561 if (!useDisplayListProperties && hasDisplayList) { 13562 displayList = getDisplayList(); 13563 if (!displayList.isValid()) { 13564 // Uncommon, but possible. If a view is removed from the hierarchy during the call 13565 // to getDisplayList(), the display list will be marked invalid and we should not 13566 // try to use it again. 13567 displayList = null; 13568 hasDisplayList = false; 13569 } 13570 } 13571 13572 if (hasNoCache) { 13573 boolean layerRendered = false; 13574 if (layerType == LAYER_TYPE_HARDWARE && !useDisplayListProperties) { 13575 final HardwareLayer layer = getHardwareLayer(); 13576 if (layer != null && layer.isValid()) { 13577 mLayerPaint.setAlpha((int) (alpha * 255)); 13578 ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint); 13579 layerRendered = true; 13580 } else { 13581 final int scrollX = hasDisplayList ? 0 : sx; 13582 final int scrollY = hasDisplayList ? 0 : sy; 13583 canvas.saveLayer(scrollX, scrollY, 13584 scrollX + mRight - mLeft, scrollY + mBottom - mTop, mLayerPaint, 13585 Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); 13586 } 13587 } 13588 13589 if (!layerRendered) { 13590 if (!hasDisplayList) { 13591 // Fast path for layouts with no backgrounds 13592 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 13593 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 13594 dispatchDraw(canvas); 13595 } else { 13596 draw(canvas); 13597 } 13598 } else { 13599 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 13600 ((HardwareCanvas) canvas).drawDisplayList(displayList, null, flags); 13601 } 13602 } 13603 } else if (cache != null) { 13604 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 13605 Paint cachePaint; 13606 13607 if (layerType == LAYER_TYPE_NONE) { 13608 cachePaint = parent.mCachePaint; 13609 if (cachePaint == null) { 13610 cachePaint = new Paint(); 13611 cachePaint.setDither(false); 13612 parent.mCachePaint = cachePaint; 13613 } 13614 if (alpha < 1) { 13615 cachePaint.setAlpha((int) (alpha * 255)); 13616 parent.mGroupFlags |= ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE; 13617 } else if ((flags & ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE) != 0) { 13618 cachePaint.setAlpha(255); 13619 parent.mGroupFlags &= ~ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE; 13620 } 13621 } else { 13622 cachePaint = mLayerPaint; 13623 cachePaint.setAlpha((int) (alpha * 255)); 13624 } 13625 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 13626 } 13627 13628 if (restoreTo >= 0) { 13629 canvas.restoreToCount(restoreTo); 13630 } 13631 13632 if (a != null && !more) { 13633 if (!hardwareAccelerated && !a.getFillAfter()) { 13634 onSetAlpha(255); 13635 } 13636 parent.finishAnimatingView(this, a); 13637 } 13638 13639 if (more && hardwareAccelerated) { 13640 // invalidation is the trigger to recreate display lists, so if we're using 13641 // display lists to render, force an invalidate to allow the animation to 13642 // continue drawing another frame 13643 parent.invalidate(true); 13644 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 13645 // alpha animations should cause the child to recreate its display list 13646 invalidate(true); 13647 } 13648 } 13649 13650 mRecreateDisplayList = false; 13651 13652 return more; 13653 } 13654 13655 /** 13656 * Manually render this view (and all of its children) to the given Canvas. 13657 * The view must have already done a full layout before this function is 13658 * called. When implementing a view, implement 13659 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 13660 * If you do need to override this method, call the superclass version. 13661 * 13662 * @param canvas The Canvas to which the View is rendered. 13663 */ 13664 public void draw(Canvas canvas) { 13665 final int privateFlags = mPrivateFlags; 13666 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 13667 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 13668 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 13669 13670 /* 13671 * Draw traversal performs several drawing steps which must be executed 13672 * in the appropriate order: 13673 * 13674 * 1. Draw the background 13675 * 2. If necessary, save the canvas' layers to prepare for fading 13676 * 3. Draw view's content 13677 * 4. Draw children 13678 * 5. If necessary, draw the fading edges and restore layers 13679 * 6. Draw decorations (scrollbars for instance) 13680 */ 13681 13682 // Step 1, draw the background, if needed 13683 int saveCount; 13684 13685 if (!dirtyOpaque) { 13686 final Drawable background = mBackground; 13687 if (background != null) { 13688 final int scrollX = mScrollX; 13689 final int scrollY = mScrollY; 13690 13691 if (mBackgroundSizeChanged) { 13692 background.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 13693 mBackgroundSizeChanged = false; 13694 } 13695 13696 if ((scrollX | scrollY) == 0) { 13697 background.draw(canvas); 13698 } else { 13699 canvas.translate(scrollX, scrollY); 13700 background.draw(canvas); 13701 canvas.translate(-scrollX, -scrollY); 13702 } 13703 } 13704 } 13705 13706 // skip step 2 & 5 if possible (common case) 13707 final int viewFlags = mViewFlags; 13708 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 13709 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 13710 if (!verticalEdges && !horizontalEdges) { 13711 // Step 3, draw the content 13712 if (!dirtyOpaque) onDraw(canvas); 13713 13714 // Step 4, draw the children 13715 dispatchDraw(canvas); 13716 13717 // Step 6, draw decorations (scrollbars) 13718 onDrawScrollBars(canvas); 13719 13720 // we're done... 13721 return; 13722 } 13723 13724 /* 13725 * Here we do the full fledged routine... 13726 * (this is an uncommon case where speed matters less, 13727 * this is why we repeat some of the tests that have been 13728 * done above) 13729 */ 13730 13731 boolean drawTop = false; 13732 boolean drawBottom = false; 13733 boolean drawLeft = false; 13734 boolean drawRight = false; 13735 13736 float topFadeStrength = 0.0f; 13737 float bottomFadeStrength = 0.0f; 13738 float leftFadeStrength = 0.0f; 13739 float rightFadeStrength = 0.0f; 13740 13741 // Step 2, save the canvas' layers 13742 int paddingLeft = mPaddingLeft; 13743 13744 final boolean offsetRequired = isPaddingOffsetRequired(); 13745 if (offsetRequired) { 13746 paddingLeft += getLeftPaddingOffset(); 13747 } 13748 13749 int left = mScrollX + paddingLeft; 13750 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 13751 int top = mScrollY + getFadeTop(offsetRequired); 13752 int bottom = top + getFadeHeight(offsetRequired); 13753 13754 if (offsetRequired) { 13755 right += getRightPaddingOffset(); 13756 bottom += getBottomPaddingOffset(); 13757 } 13758 13759 final ScrollabilityCache scrollabilityCache = mScrollCache; 13760 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 13761 int length = (int) fadeHeight; 13762 13763 // clip the fade length if top and bottom fades overlap 13764 // overlapping fades produce odd-looking artifacts 13765 if (verticalEdges && (top + length > bottom - length)) { 13766 length = (bottom - top) / 2; 13767 } 13768 13769 // also clip horizontal fades if necessary 13770 if (horizontalEdges && (left + length > right - length)) { 13771 length = (right - left) / 2; 13772 } 13773 13774 if (verticalEdges) { 13775 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 13776 drawTop = topFadeStrength * fadeHeight > 1.0f; 13777 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 13778 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 13779 } 13780 13781 if (horizontalEdges) { 13782 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 13783 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 13784 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 13785 drawRight = rightFadeStrength * fadeHeight > 1.0f; 13786 } 13787 13788 saveCount = canvas.getSaveCount(); 13789 13790 int solidColor = getSolidColor(); 13791 if (solidColor == 0) { 13792 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 13793 13794 if (drawTop) { 13795 canvas.saveLayer(left, top, right, top + length, null, flags); 13796 } 13797 13798 if (drawBottom) { 13799 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 13800 } 13801 13802 if (drawLeft) { 13803 canvas.saveLayer(left, top, left + length, bottom, null, flags); 13804 } 13805 13806 if (drawRight) { 13807 canvas.saveLayer(right - length, top, right, bottom, null, flags); 13808 } 13809 } else { 13810 scrollabilityCache.setFadeColor(solidColor); 13811 } 13812 13813 // Step 3, draw the content 13814 if (!dirtyOpaque) onDraw(canvas); 13815 13816 // Step 4, draw the children 13817 dispatchDraw(canvas); 13818 13819 // Step 5, draw the fade effect and restore layers 13820 final Paint p = scrollabilityCache.paint; 13821 final Matrix matrix = scrollabilityCache.matrix; 13822 final Shader fade = scrollabilityCache.shader; 13823 13824 if (drawTop) { 13825 matrix.setScale(1, fadeHeight * topFadeStrength); 13826 matrix.postTranslate(left, top); 13827 fade.setLocalMatrix(matrix); 13828 canvas.drawRect(left, top, right, top + length, p); 13829 } 13830 13831 if (drawBottom) { 13832 matrix.setScale(1, fadeHeight * bottomFadeStrength); 13833 matrix.postRotate(180); 13834 matrix.postTranslate(left, bottom); 13835 fade.setLocalMatrix(matrix); 13836 canvas.drawRect(left, bottom - length, right, bottom, p); 13837 } 13838 13839 if (drawLeft) { 13840 matrix.setScale(1, fadeHeight * leftFadeStrength); 13841 matrix.postRotate(-90); 13842 matrix.postTranslate(left, top); 13843 fade.setLocalMatrix(matrix); 13844 canvas.drawRect(left, top, left + length, bottom, p); 13845 } 13846 13847 if (drawRight) { 13848 matrix.setScale(1, fadeHeight * rightFadeStrength); 13849 matrix.postRotate(90); 13850 matrix.postTranslate(right, top); 13851 fade.setLocalMatrix(matrix); 13852 canvas.drawRect(right - length, top, right, bottom, p); 13853 } 13854 13855 canvas.restoreToCount(saveCount); 13856 13857 // Step 6, draw decorations (scrollbars) 13858 onDrawScrollBars(canvas); 13859 } 13860 13861 /** 13862 * Override this if your view is known to always be drawn on top of a solid color background, 13863 * and needs to draw fading edges. Returning a non-zero color enables the view system to 13864 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 13865 * should be set to 0xFF. 13866 * 13867 * @see #setVerticalFadingEdgeEnabled(boolean) 13868 * @see #setHorizontalFadingEdgeEnabled(boolean) 13869 * 13870 * @return The known solid color background for this view, or 0 if the color may vary 13871 */ 13872 @ViewDebug.ExportedProperty(category = "drawing") 13873 public int getSolidColor() { 13874 return 0; 13875 } 13876 13877 /** 13878 * Build a human readable string representation of the specified view flags. 13879 * 13880 * @param flags the view flags to convert to a string 13881 * @return a String representing the supplied flags 13882 */ 13883 private static String printFlags(int flags) { 13884 String output = ""; 13885 int numFlags = 0; 13886 if ((flags & FOCUSABLE_MASK) == FOCUSABLE) { 13887 output += "TAKES_FOCUS"; 13888 numFlags++; 13889 } 13890 13891 switch (flags & VISIBILITY_MASK) { 13892 case INVISIBLE: 13893 if (numFlags > 0) { 13894 output += " "; 13895 } 13896 output += "INVISIBLE"; 13897 // USELESS HERE numFlags++; 13898 break; 13899 case GONE: 13900 if (numFlags > 0) { 13901 output += " "; 13902 } 13903 output += "GONE"; 13904 // USELESS HERE numFlags++; 13905 break; 13906 default: 13907 break; 13908 } 13909 return output; 13910 } 13911 13912 /** 13913 * Build a human readable string representation of the specified private 13914 * view flags. 13915 * 13916 * @param privateFlags the private view flags to convert to a string 13917 * @return a String representing the supplied flags 13918 */ 13919 private static String printPrivateFlags(int privateFlags) { 13920 String output = ""; 13921 int numFlags = 0; 13922 13923 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 13924 output += "WANTS_FOCUS"; 13925 numFlags++; 13926 } 13927 13928 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 13929 if (numFlags > 0) { 13930 output += " "; 13931 } 13932 output += "FOCUSED"; 13933 numFlags++; 13934 } 13935 13936 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 13937 if (numFlags > 0) { 13938 output += " "; 13939 } 13940 output += "SELECTED"; 13941 numFlags++; 13942 } 13943 13944 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 13945 if (numFlags > 0) { 13946 output += " "; 13947 } 13948 output += "IS_ROOT_NAMESPACE"; 13949 numFlags++; 13950 } 13951 13952 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 13953 if (numFlags > 0) { 13954 output += " "; 13955 } 13956 output += "HAS_BOUNDS"; 13957 numFlags++; 13958 } 13959 13960 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 13961 if (numFlags > 0) { 13962 output += " "; 13963 } 13964 output += "DRAWN"; 13965 // USELESS HERE numFlags++; 13966 } 13967 return output; 13968 } 13969 13970 /** 13971 * <p>Indicates whether or not this view's layout will be requested during 13972 * the next hierarchy layout pass.</p> 13973 * 13974 * @return true if the layout will be forced during next layout pass 13975 */ 13976 public boolean isLayoutRequested() { 13977 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 13978 } 13979 13980 /** 13981 * Assign a size and position to a view and all of its 13982 * descendants 13983 * 13984 * <p>This is the second phase of the layout mechanism. 13985 * (The first is measuring). In this phase, each parent calls 13986 * layout on all of its children to position them. 13987 * This is typically done using the child measurements 13988 * that were stored in the measure pass().</p> 13989 * 13990 * <p>Derived classes should not override this method. 13991 * Derived classes with children should override 13992 * onLayout. In that method, they should 13993 * call layout on each of their children.</p> 13994 * 13995 * @param l Left position, relative to parent 13996 * @param t Top position, relative to parent 13997 * @param r Right position, relative to parent 13998 * @param b Bottom position, relative to parent 13999 */ 14000 @SuppressWarnings({"unchecked"}) 14001 public void layout(int l, int t, int r, int b) { 14002 int oldL = mLeft; 14003 int oldT = mTop; 14004 int oldB = mBottom; 14005 int oldR = mRight; 14006 boolean changed = setFrame(l, t, r, b); 14007 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 14008 onLayout(changed, l, t, r, b); 14009 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 14010 14011 ListenerInfo li = mListenerInfo; 14012 if (li != null && li.mOnLayoutChangeListeners != null) { 14013 ArrayList<OnLayoutChangeListener> listenersCopy = 14014 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 14015 int numListeners = listenersCopy.size(); 14016 for (int i = 0; i < numListeners; ++i) { 14017 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 14018 } 14019 } 14020 } 14021 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 14022 } 14023 14024 /** 14025 * Called from layout when this view should 14026 * assign a size and position to each of its children. 14027 * 14028 * Derived classes with children should override 14029 * this method and call layout on each of 14030 * their children. 14031 * @param changed This is a new size or position for this view 14032 * @param left Left position, relative to parent 14033 * @param top Top position, relative to parent 14034 * @param right Right position, relative to parent 14035 * @param bottom Bottom position, relative to parent 14036 */ 14037 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 14038 } 14039 14040 /** 14041 * Assign a size and position to this view. 14042 * 14043 * This is called from layout. 14044 * 14045 * @param left Left position, relative to parent 14046 * @param top Top position, relative to parent 14047 * @param right Right position, relative to parent 14048 * @param bottom Bottom position, relative to parent 14049 * @return true if the new size and position are different than the 14050 * previous ones 14051 * {@hide} 14052 */ 14053 protected boolean setFrame(int left, int top, int right, int bottom) { 14054 boolean changed = false; 14055 14056 if (DBG) { 14057 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 14058 + right + "," + bottom + ")"); 14059 } 14060 14061 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 14062 changed = true; 14063 14064 // Remember our drawn bit 14065 int drawn = mPrivateFlags & PFLAG_DRAWN; 14066 14067 int oldWidth = mRight - mLeft; 14068 int oldHeight = mBottom - mTop; 14069 int newWidth = right - left; 14070 int newHeight = bottom - top; 14071 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 14072 14073 // Invalidate our old position 14074 invalidate(sizeChanged); 14075 14076 mLeft = left; 14077 mTop = top; 14078 mRight = right; 14079 mBottom = bottom; 14080 if (mDisplayList != null) { 14081 mDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 14082 } 14083 14084 mPrivateFlags |= PFLAG_HAS_BOUNDS; 14085 14086 14087 if (sizeChanged) { 14088 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) { 14089 // A change in dimension means an auto-centered pivot point changes, too 14090 if (mTransformationInfo != null) { 14091 mTransformationInfo.mMatrixDirty = true; 14092 } 14093 } 14094 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 14095 } 14096 14097 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE) { 14098 // If we are visible, force the DRAWN bit to on so that 14099 // this invalidate will go through (at least to our parent). 14100 // This is because someone may have invalidated this view 14101 // before this call to setFrame came in, thereby clearing 14102 // the DRAWN bit. 14103 mPrivateFlags |= PFLAG_DRAWN; 14104 invalidate(sizeChanged); 14105 // parent display list may need to be recreated based on a change in the bounds 14106 // of any child 14107 invalidateParentCaches(); 14108 } 14109 14110 // Reset drawn bit to original value (invalidate turns it off) 14111 mPrivateFlags |= drawn; 14112 14113 mBackgroundSizeChanged = true; 14114 } 14115 return changed; 14116 } 14117 14118 /** 14119 * Finalize inflating a view from XML. This is called as the last phase 14120 * of inflation, after all child views have been added. 14121 * 14122 * <p>Even if the subclass overrides onFinishInflate, they should always be 14123 * sure to call the super method, so that we get called. 14124 */ 14125 protected void onFinishInflate() { 14126 } 14127 14128 /** 14129 * Returns the resources associated with this view. 14130 * 14131 * @return Resources object. 14132 */ 14133 public Resources getResources() { 14134 return mResources; 14135 } 14136 14137 /** 14138 * Invalidates the specified Drawable. 14139 * 14140 * @param drawable the drawable to invalidate 14141 */ 14142 public void invalidateDrawable(Drawable drawable) { 14143 if (verifyDrawable(drawable)) { 14144 final Rect dirty = drawable.getBounds(); 14145 final int scrollX = mScrollX; 14146 final int scrollY = mScrollY; 14147 14148 invalidate(dirty.left + scrollX, dirty.top + scrollY, 14149 dirty.right + scrollX, dirty.bottom + scrollY); 14150 } 14151 } 14152 14153 /** 14154 * Schedules an action on a drawable to occur at a specified time. 14155 * 14156 * @param who the recipient of the action 14157 * @param what the action to run on the drawable 14158 * @param when the time at which the action must occur. Uses the 14159 * {@link SystemClock#uptimeMillis} timebase. 14160 */ 14161 public void scheduleDrawable(Drawable who, Runnable what, long when) { 14162 if (verifyDrawable(who) && what != null) { 14163 final long delay = when - SystemClock.uptimeMillis(); 14164 if (mAttachInfo != null) { 14165 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 14166 Choreographer.CALLBACK_ANIMATION, what, who, 14167 Choreographer.subtractFrameDelay(delay)); 14168 } else { 14169 ViewRootImpl.getRunQueue().postDelayed(what, delay); 14170 } 14171 } 14172 } 14173 14174 /** 14175 * Cancels a scheduled action on a drawable. 14176 * 14177 * @param who the recipient of the action 14178 * @param what the action to cancel 14179 */ 14180 public void unscheduleDrawable(Drawable who, Runnable what) { 14181 if (verifyDrawable(who) && what != null) { 14182 if (mAttachInfo != null) { 14183 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 14184 Choreographer.CALLBACK_ANIMATION, what, who); 14185 } else { 14186 ViewRootImpl.getRunQueue().removeCallbacks(what); 14187 } 14188 } 14189 } 14190 14191 /** 14192 * Unschedule any events associated with the given Drawable. This can be 14193 * used when selecting a new Drawable into a view, so that the previous 14194 * one is completely unscheduled. 14195 * 14196 * @param who The Drawable to unschedule. 14197 * 14198 * @see #drawableStateChanged 14199 */ 14200 public void unscheduleDrawable(Drawable who) { 14201 if (mAttachInfo != null && who != null) { 14202 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 14203 Choreographer.CALLBACK_ANIMATION, null, who); 14204 } 14205 } 14206 14207 /** 14208 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 14209 * that the View directionality can and will be resolved before its Drawables. 14210 * 14211 * Will call {@link View#onResolveDrawables} when resolution is done. 14212 * 14213 * @hide 14214 */ 14215 protected void resolveDrawables() { 14216 if (canResolveLayoutDirection()) { 14217 if (mBackground != null) { 14218 mBackground.setLayoutDirection(getLayoutDirection()); 14219 } 14220 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 14221 onResolveDrawables(getLayoutDirection()); 14222 } 14223 } 14224 14225 /** 14226 * Called when layout direction has been resolved. 14227 * 14228 * The default implementation does nothing. 14229 * 14230 * @param layoutDirection The resolved layout direction. 14231 * 14232 * @see #LAYOUT_DIRECTION_LTR 14233 * @see #LAYOUT_DIRECTION_RTL 14234 * 14235 * @hide 14236 */ 14237 public void onResolveDrawables(int layoutDirection) { 14238 } 14239 14240 /** 14241 * @hide 14242 */ 14243 protected void resetResolvedDrawables() { 14244 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 14245 } 14246 14247 private boolean isDrawablesResolved() { 14248 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 14249 } 14250 14251 /** 14252 * If your view subclass is displaying its own Drawable objects, it should 14253 * override this function and return true for any Drawable it is 14254 * displaying. This allows animations for those drawables to be 14255 * scheduled. 14256 * 14257 * <p>Be sure to call through to the super class when overriding this 14258 * function. 14259 * 14260 * @param who The Drawable to verify. Return true if it is one you are 14261 * displaying, else return the result of calling through to the 14262 * super class. 14263 * 14264 * @return boolean If true than the Drawable is being displayed in the 14265 * view; else false and it is not allowed to animate. 14266 * 14267 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 14268 * @see #drawableStateChanged() 14269 */ 14270 protected boolean verifyDrawable(Drawable who) { 14271 return who == mBackground; 14272 } 14273 14274 /** 14275 * This function is called whenever the state of the view changes in such 14276 * a way that it impacts the state of drawables being shown. 14277 * 14278 * <p>Be sure to call through to the superclass when overriding this 14279 * function. 14280 * 14281 * @see Drawable#setState(int[]) 14282 */ 14283 protected void drawableStateChanged() { 14284 Drawable d = mBackground; 14285 if (d != null && d.isStateful()) { 14286 d.setState(getDrawableState()); 14287 } 14288 } 14289 14290 /** 14291 * Call this to force a view to update its drawable state. This will cause 14292 * drawableStateChanged to be called on this view. Views that are interested 14293 * in the new state should call getDrawableState. 14294 * 14295 * @see #drawableStateChanged 14296 * @see #getDrawableState 14297 */ 14298 public void refreshDrawableState() { 14299 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 14300 drawableStateChanged(); 14301 14302 ViewParent parent = mParent; 14303 if (parent != null) { 14304 parent.childDrawableStateChanged(this); 14305 } 14306 } 14307 14308 /** 14309 * Return an array of resource IDs of the drawable states representing the 14310 * current state of the view. 14311 * 14312 * @return The current drawable state 14313 * 14314 * @see Drawable#setState(int[]) 14315 * @see #drawableStateChanged() 14316 * @see #onCreateDrawableState(int) 14317 */ 14318 public final int[] getDrawableState() { 14319 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 14320 return mDrawableState; 14321 } else { 14322 mDrawableState = onCreateDrawableState(0); 14323 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 14324 return mDrawableState; 14325 } 14326 } 14327 14328 /** 14329 * Generate the new {@link android.graphics.drawable.Drawable} state for 14330 * this view. This is called by the view 14331 * system when the cached Drawable state is determined to be invalid. To 14332 * retrieve the current state, you should use {@link #getDrawableState}. 14333 * 14334 * @param extraSpace if non-zero, this is the number of extra entries you 14335 * would like in the returned array in which you can place your own 14336 * states. 14337 * 14338 * @return Returns an array holding the current {@link Drawable} state of 14339 * the view. 14340 * 14341 * @see #mergeDrawableStates(int[], int[]) 14342 */ 14343 protected int[] onCreateDrawableState(int extraSpace) { 14344 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 14345 mParent instanceof View) { 14346 return ((View) mParent).onCreateDrawableState(extraSpace); 14347 } 14348 14349 int[] drawableState; 14350 14351 int privateFlags = mPrivateFlags; 14352 14353 int viewStateIndex = 0; 14354 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= VIEW_STATE_PRESSED; 14355 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= VIEW_STATE_ENABLED; 14356 if (isFocused()) viewStateIndex |= VIEW_STATE_FOCUSED; 14357 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= VIEW_STATE_SELECTED; 14358 if (hasWindowFocus()) viewStateIndex |= VIEW_STATE_WINDOW_FOCUSED; 14359 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= VIEW_STATE_ACTIVATED; 14360 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 14361 HardwareRenderer.isAvailable()) { 14362 // This is set if HW acceleration is requested, even if the current 14363 // process doesn't allow it. This is just to allow app preview 14364 // windows to better match their app. 14365 viewStateIndex |= VIEW_STATE_ACCELERATED; 14366 } 14367 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= VIEW_STATE_HOVERED; 14368 14369 final int privateFlags2 = mPrivateFlags2; 14370 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) viewStateIndex |= VIEW_STATE_DRAG_CAN_ACCEPT; 14371 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) viewStateIndex |= VIEW_STATE_DRAG_HOVERED; 14372 14373 drawableState = VIEW_STATE_SETS[viewStateIndex]; 14374 14375 //noinspection ConstantIfStatement 14376 if (false) { 14377 Log.i("View", "drawableStateIndex=" + viewStateIndex); 14378 Log.i("View", toString() 14379 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 14380 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 14381 + " fo=" + hasFocus() 14382 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 14383 + " wf=" + hasWindowFocus() 14384 + ": " + Arrays.toString(drawableState)); 14385 } 14386 14387 if (extraSpace == 0) { 14388 return drawableState; 14389 } 14390 14391 final int[] fullState; 14392 if (drawableState != null) { 14393 fullState = new int[drawableState.length + extraSpace]; 14394 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 14395 } else { 14396 fullState = new int[extraSpace]; 14397 } 14398 14399 return fullState; 14400 } 14401 14402 /** 14403 * Merge your own state values in <var>additionalState</var> into the base 14404 * state values <var>baseState</var> that were returned by 14405 * {@link #onCreateDrawableState(int)}. 14406 * 14407 * @param baseState The base state values returned by 14408 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 14409 * own additional state values. 14410 * 14411 * @param additionalState The additional state values you would like 14412 * added to <var>baseState</var>; this array is not modified. 14413 * 14414 * @return As a convenience, the <var>baseState</var> array you originally 14415 * passed into the function is returned. 14416 * 14417 * @see #onCreateDrawableState(int) 14418 */ 14419 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 14420 final int N = baseState.length; 14421 int i = N - 1; 14422 while (i >= 0 && baseState[i] == 0) { 14423 i--; 14424 } 14425 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 14426 return baseState; 14427 } 14428 14429 /** 14430 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 14431 * on all Drawable objects associated with this view. 14432 */ 14433 public void jumpDrawablesToCurrentState() { 14434 if (mBackground != null) { 14435 mBackground.jumpToCurrentState(); 14436 } 14437 } 14438 14439 /** 14440 * Sets the background color for this view. 14441 * @param color the color of the background 14442 */ 14443 @RemotableViewMethod 14444 public void setBackgroundColor(int color) { 14445 if (mBackground instanceof ColorDrawable) { 14446 ((ColorDrawable) mBackground.mutate()).setColor(color); 14447 computeOpaqueFlags(); 14448 } else { 14449 setBackground(new ColorDrawable(color)); 14450 } 14451 } 14452 14453 /** 14454 * Set the background to a given resource. The resource should refer to 14455 * a Drawable object or 0 to remove the background. 14456 * @param resid The identifier of the resource. 14457 * 14458 * @attr ref android.R.styleable#View_background 14459 */ 14460 @RemotableViewMethod 14461 public void setBackgroundResource(int resid) { 14462 if (resid != 0 && resid == mBackgroundResource) { 14463 return; 14464 } 14465 14466 Drawable d= null; 14467 if (resid != 0) { 14468 d = mResources.getDrawable(resid); 14469 } 14470 setBackground(d); 14471 14472 mBackgroundResource = resid; 14473 } 14474 14475 /** 14476 * Set the background to a given Drawable, or remove the background. If the 14477 * background has padding, this View's padding is set to the background's 14478 * padding. However, when a background is removed, this View's padding isn't 14479 * touched. If setting the padding is desired, please use 14480 * {@link #setPadding(int, int, int, int)}. 14481 * 14482 * @param background The Drawable to use as the background, or null to remove the 14483 * background 14484 */ 14485 public void setBackground(Drawable background) { 14486 //noinspection deprecation 14487 setBackgroundDrawable(background); 14488 } 14489 14490 /** 14491 * @deprecated use {@link #setBackground(Drawable)} instead 14492 */ 14493 @Deprecated 14494 public void setBackgroundDrawable(Drawable background) { 14495 computeOpaqueFlags(); 14496 14497 if (background == mBackground) { 14498 return; 14499 } 14500 14501 boolean requestLayout = false; 14502 14503 mBackgroundResource = 0; 14504 14505 /* 14506 * Regardless of whether we're setting a new background or not, we want 14507 * to clear the previous drawable. 14508 */ 14509 if (mBackground != null) { 14510 mBackground.setCallback(null); 14511 unscheduleDrawable(mBackground); 14512 } 14513 14514 if (background != null) { 14515 Rect padding = sThreadLocal.get(); 14516 if (padding == null) { 14517 padding = new Rect(); 14518 sThreadLocal.set(padding); 14519 } 14520 resetResolvedDrawables(); 14521 background.setLayoutDirection(getLayoutDirection()); 14522 if (background.getPadding(padding)) { 14523 resetResolvedPadding(); 14524 switch (background.getLayoutDirection()) { 14525 case LAYOUT_DIRECTION_RTL: 14526 mUserPaddingLeftInitial = padding.right; 14527 mUserPaddingRightInitial = padding.left; 14528 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 14529 break; 14530 case LAYOUT_DIRECTION_LTR: 14531 default: 14532 mUserPaddingLeftInitial = padding.left; 14533 mUserPaddingRightInitial = padding.right; 14534 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 14535 } 14536 } 14537 14538 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 14539 // if it has a different minimum size, we should layout again 14540 if (mBackground == null || mBackground.getMinimumHeight() != background.getMinimumHeight() || 14541 mBackground.getMinimumWidth() != background.getMinimumWidth()) { 14542 requestLayout = true; 14543 } 14544 14545 background.setCallback(this); 14546 if (background.isStateful()) { 14547 background.setState(getDrawableState()); 14548 } 14549 background.setVisible(getVisibility() == VISIBLE, false); 14550 mBackground = background; 14551 14552 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 14553 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 14554 mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND; 14555 requestLayout = true; 14556 } 14557 } else { 14558 /* Remove the background */ 14559 mBackground = null; 14560 14561 if ((mPrivateFlags & PFLAG_ONLY_DRAWS_BACKGROUND) != 0) { 14562 /* 14563 * This view ONLY drew the background before and we're removing 14564 * the background, so now it won't draw anything 14565 * (hence we SKIP_DRAW) 14566 */ 14567 mPrivateFlags &= ~PFLAG_ONLY_DRAWS_BACKGROUND; 14568 mPrivateFlags |= PFLAG_SKIP_DRAW; 14569 } 14570 14571 /* 14572 * When the background is set, we try to apply its padding to this 14573 * View. When the background is removed, we don't touch this View's 14574 * padding. This is noted in the Javadocs. Hence, we don't need to 14575 * requestLayout(), the invalidate() below is sufficient. 14576 */ 14577 14578 // The old background's minimum size could have affected this 14579 // View's layout, so let's requestLayout 14580 requestLayout = true; 14581 } 14582 14583 computeOpaqueFlags(); 14584 14585 if (requestLayout) { 14586 requestLayout(); 14587 } 14588 14589 mBackgroundSizeChanged = true; 14590 invalidate(true); 14591 } 14592 14593 /** 14594 * Gets the background drawable 14595 * 14596 * @return The drawable used as the background for this view, if any. 14597 * 14598 * @see #setBackground(Drawable) 14599 * 14600 * @attr ref android.R.styleable#View_background 14601 */ 14602 public Drawable getBackground() { 14603 return mBackground; 14604 } 14605 14606 /** 14607 * Sets the padding. The view may add on the space required to display 14608 * the scrollbars, depending on the style and visibility of the scrollbars. 14609 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 14610 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 14611 * from the values set in this call. 14612 * 14613 * @attr ref android.R.styleable#View_padding 14614 * @attr ref android.R.styleable#View_paddingBottom 14615 * @attr ref android.R.styleable#View_paddingLeft 14616 * @attr ref android.R.styleable#View_paddingRight 14617 * @attr ref android.R.styleable#View_paddingTop 14618 * @param left the left padding in pixels 14619 * @param top the top padding in pixels 14620 * @param right the right padding in pixels 14621 * @param bottom the bottom padding in pixels 14622 */ 14623 public void setPadding(int left, int top, int right, int bottom) { 14624 resetResolvedPadding(); 14625 14626 mUserPaddingStart = UNDEFINED_PADDING; 14627 mUserPaddingEnd = UNDEFINED_PADDING; 14628 14629 mUserPaddingLeftInitial = left; 14630 mUserPaddingRightInitial = right; 14631 14632 internalSetPadding(left, top, right, bottom); 14633 } 14634 14635 /** 14636 * @hide 14637 */ 14638 protected void internalSetPadding(int left, int top, int right, int bottom) { 14639 mUserPaddingLeft = left; 14640 mUserPaddingRight = right; 14641 mUserPaddingBottom = bottom; 14642 14643 final int viewFlags = mViewFlags; 14644 boolean changed = false; 14645 14646 // Common case is there are no scroll bars. 14647 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 14648 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 14649 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 14650 ? 0 : getVerticalScrollbarWidth(); 14651 switch (mVerticalScrollbarPosition) { 14652 case SCROLLBAR_POSITION_DEFAULT: 14653 if (isLayoutRtl()) { 14654 left += offset; 14655 } else { 14656 right += offset; 14657 } 14658 break; 14659 case SCROLLBAR_POSITION_RIGHT: 14660 right += offset; 14661 break; 14662 case SCROLLBAR_POSITION_LEFT: 14663 left += offset; 14664 break; 14665 } 14666 } 14667 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 14668 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 14669 ? 0 : getHorizontalScrollbarHeight(); 14670 } 14671 } 14672 14673 if (mPaddingLeft != left) { 14674 changed = true; 14675 mPaddingLeft = left; 14676 } 14677 if (mPaddingTop != top) { 14678 changed = true; 14679 mPaddingTop = top; 14680 } 14681 if (mPaddingRight != right) { 14682 changed = true; 14683 mPaddingRight = right; 14684 } 14685 if (mPaddingBottom != bottom) { 14686 changed = true; 14687 mPaddingBottom = bottom; 14688 } 14689 14690 if (changed) { 14691 requestLayout(); 14692 } 14693 } 14694 14695 /** 14696 * Sets the relative padding. The view may add on the space required to display 14697 * the scrollbars, depending on the style and visibility of the scrollbars. 14698 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 14699 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 14700 * from the values set in this call. 14701 * 14702 * @attr ref android.R.styleable#View_padding 14703 * @attr ref android.R.styleable#View_paddingBottom 14704 * @attr ref android.R.styleable#View_paddingStart 14705 * @attr ref android.R.styleable#View_paddingEnd 14706 * @attr ref android.R.styleable#View_paddingTop 14707 * @param start the start padding in pixels 14708 * @param top the top padding in pixels 14709 * @param end the end padding in pixels 14710 * @param bottom the bottom padding in pixels 14711 */ 14712 public void setPaddingRelative(int start, int top, int end, int bottom) { 14713 resetResolvedPadding(); 14714 14715 mUserPaddingStart = start; 14716 mUserPaddingEnd = end; 14717 14718 switch(getLayoutDirection()) { 14719 case LAYOUT_DIRECTION_RTL: 14720 mUserPaddingLeftInitial = end; 14721 mUserPaddingRightInitial = start; 14722 internalSetPadding(end, top, start, bottom); 14723 break; 14724 case LAYOUT_DIRECTION_LTR: 14725 default: 14726 mUserPaddingLeftInitial = start; 14727 mUserPaddingRightInitial = end; 14728 internalSetPadding(start, top, end, bottom); 14729 } 14730 } 14731 14732 /** 14733 * Returns the top padding of this view. 14734 * 14735 * @return the top padding in pixels 14736 */ 14737 public int getPaddingTop() { 14738 return mPaddingTop; 14739 } 14740 14741 /** 14742 * Returns the bottom padding of this view. If there are inset and enabled 14743 * scrollbars, this value may include the space required to display the 14744 * scrollbars as well. 14745 * 14746 * @return the bottom padding in pixels 14747 */ 14748 public int getPaddingBottom() { 14749 return mPaddingBottom; 14750 } 14751 14752 /** 14753 * Returns the left padding of this view. If there are inset and enabled 14754 * scrollbars, this value may include the space required to display the 14755 * scrollbars as well. 14756 * 14757 * @return the left padding in pixels 14758 */ 14759 public int getPaddingLeft() { 14760 if (!isPaddingResolved()) { 14761 resolvePadding(); 14762 } 14763 return mPaddingLeft; 14764 } 14765 14766 /** 14767 * Returns the start padding of this view depending on its resolved layout direction. 14768 * If there are inset and enabled scrollbars, this value may include the space 14769 * required to display the scrollbars as well. 14770 * 14771 * @return the start padding in pixels 14772 */ 14773 public int getPaddingStart() { 14774 if (!isPaddingResolved()) { 14775 resolvePadding(); 14776 } 14777 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 14778 mPaddingRight : mPaddingLeft; 14779 } 14780 14781 /** 14782 * Returns the right padding of this view. If there are inset and enabled 14783 * scrollbars, this value may include the space required to display the 14784 * scrollbars as well. 14785 * 14786 * @return the right padding in pixels 14787 */ 14788 public int getPaddingRight() { 14789 if (!isPaddingResolved()) { 14790 resolvePadding(); 14791 } 14792 return mPaddingRight; 14793 } 14794 14795 /** 14796 * Returns the end padding of this view depending on its resolved layout direction. 14797 * If there are inset and enabled scrollbars, this value may include the space 14798 * required to display the scrollbars as well. 14799 * 14800 * @return the end padding in pixels 14801 */ 14802 public int getPaddingEnd() { 14803 if (!isPaddingResolved()) { 14804 resolvePadding(); 14805 } 14806 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 14807 mPaddingLeft : mPaddingRight; 14808 } 14809 14810 /** 14811 * Return if the padding as been set thru relative values 14812 * {@link #setPaddingRelative(int, int, int, int)} or thru 14813 * @attr ref android.R.styleable#View_paddingStart or 14814 * @attr ref android.R.styleable#View_paddingEnd 14815 * 14816 * @return true if the padding is relative or false if it is not. 14817 */ 14818 public boolean isPaddingRelative() { 14819 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 14820 } 14821 14822 /** 14823 * @hide 14824 */ 14825 public void resetPaddingToInitialValues() { 14826 if (isRtlCompatibilityMode()) { 14827 mPaddingLeft = mUserPaddingLeftInitial; 14828 mPaddingRight = mUserPaddingRightInitial; 14829 return; 14830 } 14831 if (isLayoutRtl()) { 14832 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 14833 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 14834 } else { 14835 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 14836 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 14837 } 14838 } 14839 14840 /** 14841 * @hide 14842 */ 14843 public Insets getOpticalInsets() { 14844 if (mLayoutInsets == null) { 14845 mLayoutInsets = (mBackground == null) ? Insets.NONE : mBackground.getLayoutInsets(); 14846 } 14847 return mLayoutInsets; 14848 } 14849 14850 /** 14851 * @hide 14852 */ 14853 public void setLayoutInsets(Insets layoutInsets) { 14854 mLayoutInsets = layoutInsets; 14855 } 14856 14857 /** 14858 * Changes the selection state of this view. A view can be selected or not. 14859 * Note that selection is not the same as focus. Views are typically 14860 * selected in the context of an AdapterView like ListView or GridView; 14861 * the selected view is the view that is highlighted. 14862 * 14863 * @param selected true if the view must be selected, false otherwise 14864 */ 14865 public void setSelected(boolean selected) { 14866 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 14867 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 14868 if (!selected) resetPressedState(); 14869 invalidate(true); 14870 refreshDrawableState(); 14871 dispatchSetSelected(selected); 14872 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 14873 notifyAccessibilityStateChanged(); 14874 } 14875 } 14876 } 14877 14878 /** 14879 * Dispatch setSelected to all of this View's children. 14880 * 14881 * @see #setSelected(boolean) 14882 * 14883 * @param selected The new selected state 14884 */ 14885 protected void dispatchSetSelected(boolean selected) { 14886 } 14887 14888 /** 14889 * Indicates the selection state of this view. 14890 * 14891 * @return true if the view is selected, false otherwise 14892 */ 14893 @ViewDebug.ExportedProperty 14894 public boolean isSelected() { 14895 return (mPrivateFlags & PFLAG_SELECTED) != 0; 14896 } 14897 14898 /** 14899 * Changes the activated state of this view. A view can be activated or not. 14900 * Note that activation is not the same as selection. Selection is 14901 * a transient property, representing the view (hierarchy) the user is 14902 * currently interacting with. Activation is a longer-term state that the 14903 * user can move views in and out of. For example, in a list view with 14904 * single or multiple selection enabled, the views in the current selection 14905 * set are activated. (Um, yeah, we are deeply sorry about the terminology 14906 * here.) The activated state is propagated down to children of the view it 14907 * is set on. 14908 * 14909 * @param activated true if the view must be activated, false otherwise 14910 */ 14911 public void setActivated(boolean activated) { 14912 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 14913 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 14914 invalidate(true); 14915 refreshDrawableState(); 14916 dispatchSetActivated(activated); 14917 } 14918 } 14919 14920 /** 14921 * Dispatch setActivated to all of this View's children. 14922 * 14923 * @see #setActivated(boolean) 14924 * 14925 * @param activated The new activated state 14926 */ 14927 protected void dispatchSetActivated(boolean activated) { 14928 } 14929 14930 /** 14931 * Indicates the activation state of this view. 14932 * 14933 * @return true if the view is activated, false otherwise 14934 */ 14935 @ViewDebug.ExportedProperty 14936 public boolean isActivated() { 14937 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 14938 } 14939 14940 /** 14941 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 14942 * observer can be used to get notifications when global events, like 14943 * layout, happen. 14944 * 14945 * The returned ViewTreeObserver observer is not guaranteed to remain 14946 * valid for the lifetime of this View. If the caller of this method keeps 14947 * a long-lived reference to ViewTreeObserver, it should always check for 14948 * the return value of {@link ViewTreeObserver#isAlive()}. 14949 * 14950 * @return The ViewTreeObserver for this view's hierarchy. 14951 */ 14952 public ViewTreeObserver getViewTreeObserver() { 14953 if (mAttachInfo != null) { 14954 return mAttachInfo.mTreeObserver; 14955 } 14956 if (mFloatingTreeObserver == null) { 14957 mFloatingTreeObserver = new ViewTreeObserver(); 14958 } 14959 return mFloatingTreeObserver; 14960 } 14961 14962 /** 14963 * <p>Finds the topmost view in the current view hierarchy.</p> 14964 * 14965 * @return the topmost view containing this view 14966 */ 14967 public View getRootView() { 14968 if (mAttachInfo != null) { 14969 final View v = mAttachInfo.mRootView; 14970 if (v != null) { 14971 return v; 14972 } 14973 } 14974 14975 View parent = this; 14976 14977 while (parent.mParent != null && parent.mParent instanceof View) { 14978 parent = (View) parent.mParent; 14979 } 14980 14981 return parent; 14982 } 14983 14984 /** 14985 * <p>Computes the coordinates of this view on the screen. The argument 14986 * must be an array of two integers. After the method returns, the array 14987 * contains the x and y location in that order.</p> 14988 * 14989 * @param location an array of two integers in which to hold the coordinates 14990 */ 14991 public void getLocationOnScreen(int[] location) { 14992 getLocationInWindow(location); 14993 14994 final AttachInfo info = mAttachInfo; 14995 if (info != null) { 14996 location[0] += info.mWindowLeft; 14997 location[1] += info.mWindowTop; 14998 } 14999 } 15000 15001 /** 15002 * <p>Computes the coordinates of this view in its window. The argument 15003 * must be an array of two integers. After the method returns, the array 15004 * contains the x and y location in that order.</p> 15005 * 15006 * @param location an array of two integers in which to hold the coordinates 15007 */ 15008 public void getLocationInWindow(int[] location) { 15009 if (location == null || location.length < 2) { 15010 throw new IllegalArgumentException("location must be an array of two integers"); 15011 } 15012 15013 if (mAttachInfo == null) { 15014 // When the view is not attached to a window, this method does not make sense 15015 location[0] = location[1] = 0; 15016 return; 15017 } 15018 15019 float[] position = mAttachInfo.mTmpTransformLocation; 15020 position[0] = position[1] = 0.0f; 15021 15022 if (!hasIdentityMatrix()) { 15023 getMatrix().mapPoints(position); 15024 } 15025 15026 position[0] += mLeft; 15027 position[1] += mTop; 15028 15029 ViewParent viewParent = mParent; 15030 while (viewParent instanceof View) { 15031 final View view = (View) viewParent; 15032 15033 position[0] -= view.mScrollX; 15034 position[1] -= view.mScrollY; 15035 15036 if (!view.hasIdentityMatrix()) { 15037 view.getMatrix().mapPoints(position); 15038 } 15039 15040 position[0] += view.mLeft; 15041 position[1] += view.mTop; 15042 15043 viewParent = view.mParent; 15044 } 15045 15046 if (viewParent instanceof ViewRootImpl) { 15047 // *cough* 15048 final ViewRootImpl vr = (ViewRootImpl) viewParent; 15049 position[1] -= vr.mCurScrollY; 15050 } 15051 15052 location[0] = (int) (position[0] + 0.5f); 15053 location[1] = (int) (position[1] + 0.5f); 15054 } 15055 15056 /** 15057 * {@hide} 15058 * @param id the id of the view to be found 15059 * @return the view of the specified id, null if cannot be found 15060 */ 15061 protected View findViewTraversal(int id) { 15062 if (id == mID) { 15063 return this; 15064 } 15065 return null; 15066 } 15067 15068 /** 15069 * {@hide} 15070 * @param tag the tag of the view to be found 15071 * @return the view of specified tag, null if cannot be found 15072 */ 15073 protected View findViewWithTagTraversal(Object tag) { 15074 if (tag != null && tag.equals(mTag)) { 15075 return this; 15076 } 15077 return null; 15078 } 15079 15080 /** 15081 * {@hide} 15082 * @param predicate The predicate to evaluate. 15083 * @param childToSkip If not null, ignores this child during the recursive traversal. 15084 * @return The first view that matches the predicate or null. 15085 */ 15086 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 15087 if (predicate.apply(this)) { 15088 return this; 15089 } 15090 return null; 15091 } 15092 15093 /** 15094 * Look for a child view with the given id. If this view has the given 15095 * id, return this view. 15096 * 15097 * @param id The id to search for. 15098 * @return The view that has the given id in the hierarchy or null 15099 */ 15100 public final View findViewById(int id) { 15101 if (id < 0) { 15102 return null; 15103 } 15104 return findViewTraversal(id); 15105 } 15106 15107 /** 15108 * Finds a view by its unuque and stable accessibility id. 15109 * 15110 * @param accessibilityId The searched accessibility id. 15111 * @return The found view. 15112 */ 15113 final View findViewByAccessibilityId(int accessibilityId) { 15114 if (accessibilityId < 0) { 15115 return null; 15116 } 15117 return findViewByAccessibilityIdTraversal(accessibilityId); 15118 } 15119 15120 /** 15121 * Performs the traversal to find a view by its unuque and stable accessibility id. 15122 * 15123 * <strong>Note:</strong>This method does not stop at the root namespace 15124 * boundary since the user can touch the screen at an arbitrary location 15125 * potentially crossing the root namespace bounday which will send an 15126 * accessibility event to accessibility services and they should be able 15127 * to obtain the event source. Also accessibility ids are guaranteed to be 15128 * unique in the window. 15129 * 15130 * @param accessibilityId The accessibility id. 15131 * @return The found view. 15132 */ 15133 View findViewByAccessibilityIdTraversal(int accessibilityId) { 15134 if (getAccessibilityViewId() == accessibilityId) { 15135 return this; 15136 } 15137 return null; 15138 } 15139 15140 /** 15141 * Look for a child view with the given tag. If this view has the given 15142 * tag, return this view. 15143 * 15144 * @param tag The tag to search for, using "tag.equals(getTag())". 15145 * @return The View that has the given tag in the hierarchy or null 15146 */ 15147 public final View findViewWithTag(Object tag) { 15148 if (tag == null) { 15149 return null; 15150 } 15151 return findViewWithTagTraversal(tag); 15152 } 15153 15154 /** 15155 * {@hide} 15156 * Look for a child view that matches the specified predicate. 15157 * If this view matches the predicate, return this view. 15158 * 15159 * @param predicate The predicate to evaluate. 15160 * @return The first view that matches the predicate or null. 15161 */ 15162 public final View findViewByPredicate(Predicate<View> predicate) { 15163 return findViewByPredicateTraversal(predicate, null); 15164 } 15165 15166 /** 15167 * {@hide} 15168 * Look for a child view that matches the specified predicate, 15169 * starting with the specified view and its descendents and then 15170 * recusively searching the ancestors and siblings of that view 15171 * until this view is reached. 15172 * 15173 * This method is useful in cases where the predicate does not match 15174 * a single unique view (perhaps multiple views use the same id) 15175 * and we are trying to find the view that is "closest" in scope to the 15176 * starting view. 15177 * 15178 * @param start The view to start from. 15179 * @param predicate The predicate to evaluate. 15180 * @return The first view that matches the predicate or null. 15181 */ 15182 public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) { 15183 View childToSkip = null; 15184 for (;;) { 15185 View view = start.findViewByPredicateTraversal(predicate, childToSkip); 15186 if (view != null || start == this) { 15187 return view; 15188 } 15189 15190 ViewParent parent = start.getParent(); 15191 if (parent == null || !(parent instanceof View)) { 15192 return null; 15193 } 15194 15195 childToSkip = start; 15196 start = (View) parent; 15197 } 15198 } 15199 15200 /** 15201 * Sets the identifier for this view. The identifier does not have to be 15202 * unique in this view's hierarchy. The identifier should be a positive 15203 * number. 15204 * 15205 * @see #NO_ID 15206 * @see #getId() 15207 * @see #findViewById(int) 15208 * 15209 * @param id a number used to identify the view 15210 * 15211 * @attr ref android.R.styleable#View_id 15212 */ 15213 public void setId(int id) { 15214 mID = id; 15215 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 15216 mID = generateViewId(); 15217 } 15218 } 15219 15220 /** 15221 * {@hide} 15222 * 15223 * @param isRoot true if the view belongs to the root namespace, false 15224 * otherwise 15225 */ 15226 public void setIsRootNamespace(boolean isRoot) { 15227 if (isRoot) { 15228 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 15229 } else { 15230 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 15231 } 15232 } 15233 15234 /** 15235 * {@hide} 15236 * 15237 * @return true if the view belongs to the root namespace, false otherwise 15238 */ 15239 public boolean isRootNamespace() { 15240 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 15241 } 15242 15243 /** 15244 * Returns this view's identifier. 15245 * 15246 * @return a positive integer used to identify the view or {@link #NO_ID} 15247 * if the view has no ID 15248 * 15249 * @see #setId(int) 15250 * @see #findViewById(int) 15251 * @attr ref android.R.styleable#View_id 15252 */ 15253 @ViewDebug.CapturedViewProperty 15254 public int getId() { 15255 return mID; 15256 } 15257 15258 /** 15259 * Returns this view's tag. 15260 * 15261 * @return the Object stored in this view as a tag 15262 * 15263 * @see #setTag(Object) 15264 * @see #getTag(int) 15265 */ 15266 @ViewDebug.ExportedProperty 15267 public Object getTag() { 15268 return mTag; 15269 } 15270 15271 /** 15272 * Sets the tag associated with this view. A tag can be used to mark 15273 * a view in its hierarchy and does not have to be unique within the 15274 * hierarchy. Tags can also be used to store data within a view without 15275 * resorting to another data structure. 15276 * 15277 * @param tag an Object to tag the view with 15278 * 15279 * @see #getTag() 15280 * @see #setTag(int, Object) 15281 */ 15282 public void setTag(final Object tag) { 15283 mTag = tag; 15284 } 15285 15286 /** 15287 * Returns the tag associated with this view and the specified key. 15288 * 15289 * @param key The key identifying the tag 15290 * 15291 * @return the Object stored in this view as a tag 15292 * 15293 * @see #setTag(int, Object) 15294 * @see #getTag() 15295 */ 15296 public Object getTag(int key) { 15297 if (mKeyedTags != null) return mKeyedTags.get(key); 15298 return null; 15299 } 15300 15301 /** 15302 * Sets a tag associated with this view and a key. A tag can be used 15303 * to mark a view in its hierarchy and does not have to be unique within 15304 * the hierarchy. Tags can also be used to store data within a view 15305 * without resorting to another data structure. 15306 * 15307 * The specified key should be an id declared in the resources of the 15308 * application to ensure it is unique (see the <a 15309 * href={@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 15310 * Keys identified as belonging to 15311 * the Android framework or not associated with any package will cause 15312 * an {@link IllegalArgumentException} to be thrown. 15313 * 15314 * @param key The key identifying the tag 15315 * @param tag An Object to tag the view with 15316 * 15317 * @throws IllegalArgumentException If they specified key is not valid 15318 * 15319 * @see #setTag(Object) 15320 * @see #getTag(int) 15321 */ 15322 public void setTag(int key, final Object tag) { 15323 // If the package id is 0x00 or 0x01, it's either an undefined package 15324 // or a framework id 15325 if ((key >>> 24) < 2) { 15326 throw new IllegalArgumentException("The key must be an application-specific " 15327 + "resource id."); 15328 } 15329 15330 setKeyedTag(key, tag); 15331 } 15332 15333 /** 15334 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 15335 * framework id. 15336 * 15337 * @hide 15338 */ 15339 public void setTagInternal(int key, Object tag) { 15340 if ((key >>> 24) != 0x1) { 15341 throw new IllegalArgumentException("The key must be a framework-specific " 15342 + "resource id."); 15343 } 15344 15345 setKeyedTag(key, tag); 15346 } 15347 15348 private void setKeyedTag(int key, Object tag) { 15349 if (mKeyedTags == null) { 15350 mKeyedTags = new SparseArray<Object>(); 15351 } 15352 15353 mKeyedTags.put(key, tag); 15354 } 15355 15356 /** 15357 * Prints information about this view in the log output, with the tag 15358 * {@link #VIEW_LOG_TAG}. 15359 * 15360 * @hide 15361 */ 15362 public void debug() { 15363 debug(0); 15364 } 15365 15366 /** 15367 * Prints information about this view in the log output, with the tag 15368 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 15369 * indentation defined by the <code>depth</code>. 15370 * 15371 * @param depth the indentation level 15372 * 15373 * @hide 15374 */ 15375 protected void debug(int depth) { 15376 String output = debugIndent(depth - 1); 15377 15378 output += "+ " + this; 15379 int id = getId(); 15380 if (id != -1) { 15381 output += " (id=" + id + ")"; 15382 } 15383 Object tag = getTag(); 15384 if (tag != null) { 15385 output += " (tag=" + tag + ")"; 15386 } 15387 Log.d(VIEW_LOG_TAG, output); 15388 15389 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 15390 output = debugIndent(depth) + " FOCUSED"; 15391 Log.d(VIEW_LOG_TAG, output); 15392 } 15393 15394 output = debugIndent(depth); 15395 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 15396 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 15397 + "} "; 15398 Log.d(VIEW_LOG_TAG, output); 15399 15400 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 15401 || mPaddingBottom != 0) { 15402 output = debugIndent(depth); 15403 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 15404 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 15405 Log.d(VIEW_LOG_TAG, output); 15406 } 15407 15408 output = debugIndent(depth); 15409 output += "mMeasureWidth=" + mMeasuredWidth + 15410 " mMeasureHeight=" + mMeasuredHeight; 15411 Log.d(VIEW_LOG_TAG, output); 15412 15413 output = debugIndent(depth); 15414 if (mLayoutParams == null) { 15415 output += "BAD! no layout params"; 15416 } else { 15417 output = mLayoutParams.debug(output); 15418 } 15419 Log.d(VIEW_LOG_TAG, output); 15420 15421 output = debugIndent(depth); 15422 output += "flags={"; 15423 output += View.printFlags(mViewFlags); 15424 output += "}"; 15425 Log.d(VIEW_LOG_TAG, output); 15426 15427 output = debugIndent(depth); 15428 output += "privateFlags={"; 15429 output += View.printPrivateFlags(mPrivateFlags); 15430 output += "}"; 15431 Log.d(VIEW_LOG_TAG, output); 15432 } 15433 15434 /** 15435 * Creates a string of whitespaces used for indentation. 15436 * 15437 * @param depth the indentation level 15438 * @return a String containing (depth * 2 + 3) * 2 white spaces 15439 * 15440 * @hide 15441 */ 15442 protected static String debugIndent(int depth) { 15443 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 15444 for (int i = 0; i < (depth * 2) + 3; i++) { 15445 spaces.append(' ').append(' '); 15446 } 15447 return spaces.toString(); 15448 } 15449 15450 /** 15451 * <p>Return the offset of the widget's text baseline from the widget's top 15452 * boundary. If this widget does not support baseline alignment, this 15453 * method returns -1. </p> 15454 * 15455 * @return the offset of the baseline within the widget's bounds or -1 15456 * if baseline alignment is not supported 15457 */ 15458 @ViewDebug.ExportedProperty(category = "layout") 15459 public int getBaseline() { 15460 return -1; 15461 } 15462 15463 /** 15464 * Call this when something has changed which has invalidated the 15465 * layout of this view. This will schedule a layout pass of the view 15466 * tree. 15467 */ 15468 public void requestLayout() { 15469 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 15470 mPrivateFlags |= PFLAG_INVALIDATED; 15471 15472 if (mParent != null && !mParent.isLayoutRequested()) { 15473 mParent.requestLayout(); 15474 } 15475 } 15476 15477 /** 15478 * Forces this view to be laid out during the next layout pass. 15479 * This method does not call requestLayout() or forceLayout() 15480 * on the parent. 15481 */ 15482 public void forceLayout() { 15483 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 15484 mPrivateFlags |= PFLAG_INVALIDATED; 15485 } 15486 15487 /** 15488 * <p> 15489 * This is called to find out how big a view should be. The parent 15490 * supplies constraint information in the width and height parameters. 15491 * </p> 15492 * 15493 * <p> 15494 * The actual measurement work of a view is performed in 15495 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 15496 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 15497 * </p> 15498 * 15499 * 15500 * @param widthMeasureSpec Horizontal space requirements as imposed by the 15501 * parent 15502 * @param heightMeasureSpec Vertical space requirements as imposed by the 15503 * parent 15504 * 15505 * @see #onMeasure(int, int) 15506 */ 15507 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 15508 if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT || 15509 widthMeasureSpec != mOldWidthMeasureSpec || 15510 heightMeasureSpec != mOldHeightMeasureSpec) { 15511 15512 // first clears the measured dimension flag 15513 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 15514 15515 resolveRtlPropertiesIfNeeded(); 15516 15517 // measure ourselves, this should set the measured dimension flag back 15518 onMeasure(widthMeasureSpec, heightMeasureSpec); 15519 15520 // flag not set, setMeasuredDimension() was not invoked, we raise 15521 // an exception to warn the developer 15522 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 15523 throw new IllegalStateException("onMeasure() did not set the" 15524 + " measured dimension by calling" 15525 + " setMeasuredDimension()"); 15526 } 15527 15528 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 15529 } 15530 15531 mOldWidthMeasureSpec = widthMeasureSpec; 15532 mOldHeightMeasureSpec = heightMeasureSpec; 15533 } 15534 15535 /** 15536 * <p> 15537 * Measure the view and its content to determine the measured width and the 15538 * measured height. This method is invoked by {@link #measure(int, int)} and 15539 * should be overriden by subclasses to provide accurate and efficient 15540 * measurement of their contents. 15541 * </p> 15542 * 15543 * <p> 15544 * <strong>CONTRACT:</strong> When overriding this method, you 15545 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 15546 * measured width and height of this view. Failure to do so will trigger an 15547 * <code>IllegalStateException</code>, thrown by 15548 * {@link #measure(int, int)}. Calling the superclass' 15549 * {@link #onMeasure(int, int)} is a valid use. 15550 * </p> 15551 * 15552 * <p> 15553 * The base class implementation of measure defaults to the background size, 15554 * unless a larger size is allowed by the MeasureSpec. Subclasses should 15555 * override {@link #onMeasure(int, int)} to provide better measurements of 15556 * their content. 15557 * </p> 15558 * 15559 * <p> 15560 * If this method is overridden, it is the subclass's responsibility to make 15561 * sure the measured height and width are at least the view's minimum height 15562 * and width ({@link #getSuggestedMinimumHeight()} and 15563 * {@link #getSuggestedMinimumWidth()}). 15564 * </p> 15565 * 15566 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 15567 * The requirements are encoded with 15568 * {@link android.view.View.MeasureSpec}. 15569 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 15570 * The requirements are encoded with 15571 * {@link android.view.View.MeasureSpec}. 15572 * 15573 * @see #getMeasuredWidth() 15574 * @see #getMeasuredHeight() 15575 * @see #setMeasuredDimension(int, int) 15576 * @see #getSuggestedMinimumHeight() 15577 * @see #getSuggestedMinimumWidth() 15578 * @see android.view.View.MeasureSpec#getMode(int) 15579 * @see android.view.View.MeasureSpec#getSize(int) 15580 */ 15581 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 15582 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 15583 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 15584 } 15585 15586 /** 15587 * <p>This mehod must be called by {@link #onMeasure(int, int)} to store the 15588 * measured width and measured height. Failing to do so will trigger an 15589 * exception at measurement time.</p> 15590 * 15591 * @param measuredWidth The measured width of this view. May be a complex 15592 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 15593 * {@link #MEASURED_STATE_TOO_SMALL}. 15594 * @param measuredHeight The measured height of this view. May be a complex 15595 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 15596 * {@link #MEASURED_STATE_TOO_SMALL}. 15597 */ 15598 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 15599 mMeasuredWidth = measuredWidth; 15600 mMeasuredHeight = measuredHeight; 15601 15602 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 15603 } 15604 15605 /** 15606 * Merge two states as returned by {@link #getMeasuredState()}. 15607 * @param curState The current state as returned from a view or the result 15608 * of combining multiple views. 15609 * @param newState The new view state to combine. 15610 * @return Returns a new integer reflecting the combination of the two 15611 * states. 15612 */ 15613 public static int combineMeasuredStates(int curState, int newState) { 15614 return curState | newState; 15615 } 15616 15617 /** 15618 * Version of {@link #resolveSizeAndState(int, int, int)} 15619 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 15620 */ 15621 public static int resolveSize(int size, int measureSpec) { 15622 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 15623 } 15624 15625 /** 15626 * Utility to reconcile a desired size and state, with constraints imposed 15627 * by a MeasureSpec. Will take the desired size, unless a different size 15628 * is imposed by the constraints. The returned value is a compound integer, 15629 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 15630 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the resulting 15631 * size is smaller than the size the view wants to be. 15632 * 15633 * @param size How big the view wants to be 15634 * @param measureSpec Constraints imposed by the parent 15635 * @return Size information bit mask as defined by 15636 * {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 15637 */ 15638 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 15639 int result = size; 15640 int specMode = MeasureSpec.getMode(measureSpec); 15641 int specSize = MeasureSpec.getSize(measureSpec); 15642 switch (specMode) { 15643 case MeasureSpec.UNSPECIFIED: 15644 result = size; 15645 break; 15646 case MeasureSpec.AT_MOST: 15647 if (specSize < size) { 15648 result = specSize | MEASURED_STATE_TOO_SMALL; 15649 } else { 15650 result = size; 15651 } 15652 break; 15653 case MeasureSpec.EXACTLY: 15654 result = specSize; 15655 break; 15656 } 15657 return result | (childMeasuredState&MEASURED_STATE_MASK); 15658 } 15659 15660 /** 15661 * Utility to return a default size. Uses the supplied size if the 15662 * MeasureSpec imposed no constraints. Will get larger if allowed 15663 * by the MeasureSpec. 15664 * 15665 * @param size Default size for this view 15666 * @param measureSpec Constraints imposed by the parent 15667 * @return The size this view should be. 15668 */ 15669 public static int getDefaultSize(int size, int measureSpec) { 15670 int result = size; 15671 int specMode = MeasureSpec.getMode(measureSpec); 15672 int specSize = MeasureSpec.getSize(measureSpec); 15673 15674 switch (specMode) { 15675 case MeasureSpec.UNSPECIFIED: 15676 result = size; 15677 break; 15678 case MeasureSpec.AT_MOST: 15679 case MeasureSpec.EXACTLY: 15680 result = specSize; 15681 break; 15682 } 15683 return result; 15684 } 15685 15686 /** 15687 * Returns the suggested minimum height that the view should use. This 15688 * returns the maximum of the view's minimum height 15689 * and the background's minimum height 15690 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 15691 * <p> 15692 * When being used in {@link #onMeasure(int, int)}, the caller should still 15693 * ensure the returned height is within the requirements of the parent. 15694 * 15695 * @return The suggested minimum height of the view. 15696 */ 15697 protected int getSuggestedMinimumHeight() { 15698 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 15699 15700 } 15701 15702 /** 15703 * Returns the suggested minimum width that the view should use. This 15704 * returns the maximum of the view's minimum width) 15705 * and the background's minimum width 15706 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 15707 * <p> 15708 * When being used in {@link #onMeasure(int, int)}, the caller should still 15709 * ensure the returned width is within the requirements of the parent. 15710 * 15711 * @return The suggested minimum width of the view. 15712 */ 15713 protected int getSuggestedMinimumWidth() { 15714 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 15715 } 15716 15717 /** 15718 * Returns the minimum height of the view. 15719 * 15720 * @return the minimum height the view will try to be. 15721 * 15722 * @see #setMinimumHeight(int) 15723 * 15724 * @attr ref android.R.styleable#View_minHeight 15725 */ 15726 public int getMinimumHeight() { 15727 return mMinHeight; 15728 } 15729 15730 /** 15731 * Sets the minimum height of the view. It is not guaranteed the view will 15732 * be able to achieve this minimum height (for example, if its parent layout 15733 * constrains it with less available height). 15734 * 15735 * @param minHeight The minimum height the view will try to be. 15736 * 15737 * @see #getMinimumHeight() 15738 * 15739 * @attr ref android.R.styleable#View_minHeight 15740 */ 15741 public void setMinimumHeight(int minHeight) { 15742 mMinHeight = minHeight; 15743 requestLayout(); 15744 } 15745 15746 /** 15747 * Returns the minimum width of the view. 15748 * 15749 * @return the minimum width the view will try to be. 15750 * 15751 * @see #setMinimumWidth(int) 15752 * 15753 * @attr ref android.R.styleable#View_minWidth 15754 */ 15755 public int getMinimumWidth() { 15756 return mMinWidth; 15757 } 15758 15759 /** 15760 * Sets the minimum width of the view. It is not guaranteed the view will 15761 * be able to achieve this minimum width (for example, if its parent layout 15762 * constrains it with less available width). 15763 * 15764 * @param minWidth The minimum width the view will try to be. 15765 * 15766 * @see #getMinimumWidth() 15767 * 15768 * @attr ref android.R.styleable#View_minWidth 15769 */ 15770 public void setMinimumWidth(int minWidth) { 15771 mMinWidth = minWidth; 15772 requestLayout(); 15773 15774 } 15775 15776 /** 15777 * Get the animation currently associated with this view. 15778 * 15779 * @return The animation that is currently playing or 15780 * scheduled to play for this view. 15781 */ 15782 public Animation getAnimation() { 15783 return mCurrentAnimation; 15784 } 15785 15786 /** 15787 * Start the specified animation now. 15788 * 15789 * @param animation the animation to start now 15790 */ 15791 public void startAnimation(Animation animation) { 15792 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 15793 setAnimation(animation); 15794 invalidateParentCaches(); 15795 invalidate(true); 15796 } 15797 15798 /** 15799 * Cancels any animations for this view. 15800 */ 15801 public void clearAnimation() { 15802 if (mCurrentAnimation != null) { 15803 mCurrentAnimation.detach(); 15804 } 15805 mCurrentAnimation = null; 15806 invalidateParentIfNeeded(); 15807 } 15808 15809 /** 15810 * Sets the next animation to play for this view. 15811 * If you want the animation to play immediately, use 15812 * {@link #startAnimation(android.view.animation.Animation)} instead. 15813 * This method provides allows fine-grained 15814 * control over the start time and invalidation, but you 15815 * must make sure that 1) the animation has a start time set, and 15816 * 2) the view's parent (which controls animations on its children) 15817 * will be invalidated when the animation is supposed to 15818 * start. 15819 * 15820 * @param animation The next animation, or null. 15821 */ 15822 public void setAnimation(Animation animation) { 15823 mCurrentAnimation = animation; 15824 15825 if (animation != null) { 15826 // If the screen is off assume the animation start time is now instead of 15827 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 15828 // would cause the animation to start when the screen turns back on 15829 if (mAttachInfo != null && !mAttachInfo.mScreenOn && 15830 animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 15831 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 15832 } 15833 animation.reset(); 15834 } 15835 } 15836 15837 /** 15838 * Invoked by a parent ViewGroup to notify the start of the animation 15839 * currently associated with this view. If you override this method, 15840 * always call super.onAnimationStart(); 15841 * 15842 * @see #setAnimation(android.view.animation.Animation) 15843 * @see #getAnimation() 15844 */ 15845 protected void onAnimationStart() { 15846 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 15847 } 15848 15849 /** 15850 * Invoked by a parent ViewGroup to notify the end of the animation 15851 * currently associated with this view. If you override this method, 15852 * always call super.onAnimationEnd(); 15853 * 15854 * @see #setAnimation(android.view.animation.Animation) 15855 * @see #getAnimation() 15856 */ 15857 protected void onAnimationEnd() { 15858 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 15859 } 15860 15861 /** 15862 * Invoked if there is a Transform that involves alpha. Subclass that can 15863 * draw themselves with the specified alpha should return true, and then 15864 * respect that alpha when their onDraw() is called. If this returns false 15865 * then the view may be redirected to draw into an offscreen buffer to 15866 * fulfill the request, which will look fine, but may be slower than if the 15867 * subclass handles it internally. The default implementation returns false. 15868 * 15869 * @param alpha The alpha (0..255) to apply to the view's drawing 15870 * @return true if the view can draw with the specified alpha. 15871 */ 15872 protected boolean onSetAlpha(int alpha) { 15873 return false; 15874 } 15875 15876 /** 15877 * This is used by the RootView to perform an optimization when 15878 * the view hierarchy contains one or several SurfaceView. 15879 * SurfaceView is always considered transparent, but its children are not, 15880 * therefore all View objects remove themselves from the global transparent 15881 * region (passed as a parameter to this function). 15882 * 15883 * @param region The transparent region for this ViewAncestor (window). 15884 * 15885 * @return Returns true if the effective visibility of the view at this 15886 * point is opaque, regardless of the transparent region; returns false 15887 * if it is possible for underlying windows to be seen behind the view. 15888 * 15889 * {@hide} 15890 */ 15891 public boolean gatherTransparentRegion(Region region) { 15892 final AttachInfo attachInfo = mAttachInfo; 15893 if (region != null && attachInfo != null) { 15894 final int pflags = mPrivateFlags; 15895 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 15896 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 15897 // remove it from the transparent region. 15898 final int[] location = attachInfo.mTransparentLocation; 15899 getLocationInWindow(location); 15900 region.op(location[0], location[1], location[0] + mRight - mLeft, 15901 location[1] + mBottom - mTop, Region.Op.DIFFERENCE); 15902 } else if ((pflags & PFLAG_ONLY_DRAWS_BACKGROUND) != 0 && mBackground != null) { 15903 // The ONLY_DRAWS_BACKGROUND flag IS set and the background drawable 15904 // exists, so we remove the background drawable's non-transparent 15905 // parts from this transparent region. 15906 applyDrawableToTransparentRegion(mBackground, region); 15907 } 15908 } 15909 return true; 15910 } 15911 15912 /** 15913 * Play a sound effect for this view. 15914 * 15915 * <p>The framework will play sound effects for some built in actions, such as 15916 * clicking, but you may wish to play these effects in your widget, 15917 * for instance, for internal navigation. 15918 * 15919 * <p>The sound effect will only be played if sound effects are enabled by the user, and 15920 * {@link #isSoundEffectsEnabled()} is true. 15921 * 15922 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 15923 */ 15924 public void playSoundEffect(int soundConstant) { 15925 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 15926 return; 15927 } 15928 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 15929 } 15930 15931 /** 15932 * BZZZTT!!1! 15933 * 15934 * <p>Provide haptic feedback to the user for this view. 15935 * 15936 * <p>The framework will provide haptic feedback for some built in actions, 15937 * such as long presses, but you may wish to provide feedback for your 15938 * own widget. 15939 * 15940 * <p>The feedback will only be performed if 15941 * {@link #isHapticFeedbackEnabled()} is true. 15942 * 15943 * @param feedbackConstant One of the constants defined in 15944 * {@link HapticFeedbackConstants} 15945 */ 15946 public boolean performHapticFeedback(int feedbackConstant) { 15947 return performHapticFeedback(feedbackConstant, 0); 15948 } 15949 15950 /** 15951 * BZZZTT!!1! 15952 * 15953 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 15954 * 15955 * @param feedbackConstant One of the constants defined in 15956 * {@link HapticFeedbackConstants} 15957 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 15958 */ 15959 public boolean performHapticFeedback(int feedbackConstant, int flags) { 15960 if (mAttachInfo == null) { 15961 return false; 15962 } 15963 //noinspection SimplifiableIfStatement 15964 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 15965 && !isHapticFeedbackEnabled()) { 15966 return false; 15967 } 15968 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 15969 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 15970 } 15971 15972 /** 15973 * Request that the visibility of the status bar or other screen/window 15974 * decorations be changed. 15975 * 15976 * <p>This method is used to put the over device UI into temporary modes 15977 * where the user's attention is focused more on the application content, 15978 * by dimming or hiding surrounding system affordances. This is typically 15979 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 15980 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 15981 * to be placed behind the action bar (and with these flags other system 15982 * affordances) so that smooth transitions between hiding and showing them 15983 * can be done. 15984 * 15985 * <p>Two representative examples of the use of system UI visibility is 15986 * implementing a content browsing application (like a magazine reader) 15987 * and a video playing application. 15988 * 15989 * <p>The first code shows a typical implementation of a View in a content 15990 * browsing application. In this implementation, the application goes 15991 * into a content-oriented mode by hiding the status bar and action bar, 15992 * and putting the navigation elements into lights out mode. The user can 15993 * then interact with content while in this mode. Such an application should 15994 * provide an easy way for the user to toggle out of the mode (such as to 15995 * check information in the status bar or access notifications). In the 15996 * implementation here, this is done simply by tapping on the content. 15997 * 15998 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 15999 * content} 16000 * 16001 * <p>This second code sample shows a typical implementation of a View 16002 * in a video playing application. In this situation, while the video is 16003 * playing the application would like to go into a complete full-screen mode, 16004 * to use as much of the display as possible for the video. When in this state 16005 * the user can not interact with the application; the system intercepts 16006 * touching on the screen to pop the UI out of full screen mode. See 16007 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 16008 * 16009 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 16010 * content} 16011 * 16012 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 16013 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 16014 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 16015 * and {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}. 16016 */ 16017 public void setSystemUiVisibility(int visibility) { 16018 if (visibility != mSystemUiVisibility) { 16019 mSystemUiVisibility = visibility; 16020 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 16021 mParent.recomputeViewAttributes(this); 16022 } 16023 } 16024 } 16025 16026 /** 16027 * Returns the last {@link #setSystemUiVisibility(int) that this view has requested. 16028 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 16029 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 16030 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 16031 * and {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}. 16032 */ 16033 public int getSystemUiVisibility() { 16034 return mSystemUiVisibility; 16035 } 16036 16037 /** 16038 * Returns the current system UI visibility that is currently set for 16039 * the entire window. This is the combination of the 16040 * {@link #setSystemUiVisibility(int)} values supplied by all of the 16041 * views in the window. 16042 */ 16043 public int getWindowSystemUiVisibility() { 16044 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 16045 } 16046 16047 /** 16048 * Override to find out when the window's requested system UI visibility 16049 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 16050 * This is different from the callbacks recieved through 16051 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 16052 * in that this is only telling you about the local request of the window, 16053 * not the actual values applied by the system. 16054 */ 16055 public void onWindowSystemUiVisibilityChanged(int visible) { 16056 } 16057 16058 /** 16059 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 16060 * the view hierarchy. 16061 */ 16062 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 16063 onWindowSystemUiVisibilityChanged(visible); 16064 } 16065 16066 /** 16067 * Set a listener to receive callbacks when the visibility of the system bar changes. 16068 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 16069 */ 16070 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 16071 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 16072 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 16073 mParent.recomputeViewAttributes(this); 16074 } 16075 } 16076 16077 /** 16078 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 16079 * the view hierarchy. 16080 */ 16081 public void dispatchSystemUiVisibilityChanged(int visibility) { 16082 ListenerInfo li = mListenerInfo; 16083 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 16084 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 16085 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 16086 } 16087 } 16088 16089 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 16090 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 16091 if (val != mSystemUiVisibility) { 16092 setSystemUiVisibility(val); 16093 return true; 16094 } 16095 return false; 16096 } 16097 16098 /** @hide */ 16099 public void setDisabledSystemUiVisibility(int flags) { 16100 if (mAttachInfo != null) { 16101 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 16102 mAttachInfo.mDisabledSystemUiVisibility = flags; 16103 if (mParent != null) { 16104 mParent.recomputeViewAttributes(this); 16105 } 16106 } 16107 } 16108 } 16109 16110 /** 16111 * Creates an image that the system displays during the drag and drop 16112 * operation. This is called a "drag shadow". The default implementation 16113 * for a DragShadowBuilder based on a View returns an image that has exactly the same 16114 * appearance as the given View. The default also positions the center of the drag shadow 16115 * directly under the touch point. If no View is provided (the constructor with no parameters 16116 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 16117 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overriden, then the 16118 * default is an invisible drag shadow. 16119 * <p> 16120 * You are not required to use the View you provide to the constructor as the basis of the 16121 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 16122 * anything you want as the drag shadow. 16123 * </p> 16124 * <p> 16125 * You pass a DragShadowBuilder object to the system when you start the drag. The system 16126 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 16127 * size and position of the drag shadow. It uses this data to construct a 16128 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 16129 * so that your application can draw the shadow image in the Canvas. 16130 * </p> 16131 * 16132 * <div class="special reference"> 16133 * <h3>Developer Guides</h3> 16134 * <p>For a guide to implementing drag and drop features, read the 16135 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 16136 * </div> 16137 */ 16138 public static class DragShadowBuilder { 16139 private final WeakReference<View> mView; 16140 16141 /** 16142 * Constructs a shadow image builder based on a View. By default, the resulting drag 16143 * shadow will have the same appearance and dimensions as the View, with the touch point 16144 * over the center of the View. 16145 * @param view A View. Any View in scope can be used. 16146 */ 16147 public DragShadowBuilder(View view) { 16148 mView = new WeakReference<View>(view); 16149 } 16150 16151 /** 16152 * Construct a shadow builder object with no associated View. This 16153 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 16154 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 16155 * to supply the drag shadow's dimensions and appearance without 16156 * reference to any View object. If they are not overridden, then the result is an 16157 * invisible drag shadow. 16158 */ 16159 public DragShadowBuilder() { 16160 mView = new WeakReference<View>(null); 16161 } 16162 16163 /** 16164 * Returns the View object that had been passed to the 16165 * {@link #View.DragShadowBuilder(View)} 16166 * constructor. If that View parameter was {@code null} or if the 16167 * {@link #View.DragShadowBuilder()} 16168 * constructor was used to instantiate the builder object, this method will return 16169 * null. 16170 * 16171 * @return The View object associate with this builder object. 16172 */ 16173 @SuppressWarnings({"JavadocReference"}) 16174 final public View getView() { 16175 return mView.get(); 16176 } 16177 16178 /** 16179 * Provides the metrics for the shadow image. These include the dimensions of 16180 * the shadow image, and the point within that shadow that should 16181 * be centered under the touch location while dragging. 16182 * <p> 16183 * The default implementation sets the dimensions of the shadow to be the 16184 * same as the dimensions of the View itself and centers the shadow under 16185 * the touch point. 16186 * </p> 16187 * 16188 * @param shadowSize A {@link android.graphics.Point} containing the width and height 16189 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 16190 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 16191 * image. 16192 * 16193 * @param shadowTouchPoint A {@link android.graphics.Point} for the position within the 16194 * shadow image that should be underneath the touch point during the drag and drop 16195 * operation. Your application must set {@link android.graphics.Point#x} to the 16196 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 16197 */ 16198 public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) { 16199 final View view = mView.get(); 16200 if (view != null) { 16201 shadowSize.set(view.getWidth(), view.getHeight()); 16202 shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2); 16203 } else { 16204 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 16205 } 16206 } 16207 16208 /** 16209 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 16210 * based on the dimensions it received from the 16211 * {@link #onProvideShadowMetrics(Point, Point)} callback. 16212 * 16213 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 16214 */ 16215 public void onDrawShadow(Canvas canvas) { 16216 final View view = mView.get(); 16217 if (view != null) { 16218 view.draw(canvas); 16219 } else { 16220 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 16221 } 16222 } 16223 } 16224 16225 /** 16226 * Starts a drag and drop operation. When your application calls this method, it passes a 16227 * {@link android.view.View.DragShadowBuilder} object to the system. The 16228 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 16229 * to get metrics for the drag shadow, and then calls the object's 16230 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 16231 * <p> 16232 * Once the system has the drag shadow, it begins the drag and drop operation by sending 16233 * drag events to all the View objects in your application that are currently visible. It does 16234 * this either by calling the View object's drag listener (an implementation of 16235 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 16236 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 16237 * Both are passed a {@link android.view.DragEvent} object that has a 16238 * {@link android.view.DragEvent#getAction()} value of 16239 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 16240 * </p> 16241 * <p> 16242 * Your application can invoke startDrag() on any attached View object. The View object does not 16243 * need to be the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to 16244 * be related to the View the user selected for dragging. 16245 * </p> 16246 * @param data A {@link android.content.ClipData} object pointing to the data to be 16247 * transferred by the drag and drop operation. 16248 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 16249 * drag shadow. 16250 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 16251 * drop operation. This Object is put into every DragEvent object sent by the system during the 16252 * current drag. 16253 * <p> 16254 * myLocalState is a lightweight mechanism for the sending information from the dragged View 16255 * to the target Views. For example, it can contain flags that differentiate between a 16256 * a copy operation and a move operation. 16257 * </p> 16258 * @param flags Flags that control the drag and drop operation. No flags are currently defined, 16259 * so the parameter should be set to 0. 16260 * @return {@code true} if the method completes successfully, or 16261 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 16262 * do a drag, and so no drag operation is in progress. 16263 */ 16264 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 16265 Object myLocalState, int flags) { 16266 if (ViewDebug.DEBUG_DRAG) { 16267 Log.d(VIEW_LOG_TAG, "startDrag: data=" + data + " flags=" + flags); 16268 } 16269 boolean okay = false; 16270 16271 Point shadowSize = new Point(); 16272 Point shadowTouchPoint = new Point(); 16273 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 16274 16275 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 16276 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 16277 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 16278 } 16279 16280 if (ViewDebug.DEBUG_DRAG) { 16281 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 16282 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 16283 } 16284 Surface surface = new Surface(); 16285 try { 16286 IBinder token = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 16287 flags, shadowSize.x, shadowSize.y, surface); 16288 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" + token 16289 + " surface=" + surface); 16290 if (token != null) { 16291 Canvas canvas = surface.lockCanvas(null); 16292 try { 16293 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 16294 shadowBuilder.onDrawShadow(canvas); 16295 } finally { 16296 surface.unlockCanvasAndPost(canvas); 16297 } 16298 16299 final ViewRootImpl root = getViewRootImpl(); 16300 16301 // Cache the local state object for delivery with DragEvents 16302 root.setLocalDragState(myLocalState); 16303 16304 // repurpose 'shadowSize' for the last touch point 16305 root.getLastTouchPoint(shadowSize); 16306 16307 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, token, 16308 shadowSize.x, shadowSize.y, 16309 shadowTouchPoint.x, shadowTouchPoint.y, data); 16310 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 16311 16312 // Off and running! Release our local surface instance; the drag 16313 // shadow surface is now managed by the system process. 16314 surface.release(); 16315 } 16316 } catch (Exception e) { 16317 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 16318 surface.destroy(); 16319 } 16320 16321 return okay; 16322 } 16323 16324 /** 16325 * Handles drag events sent by the system following a call to 16326 * {@link android.view.View#startDrag(ClipData,DragShadowBuilder,Object,int) startDrag()}. 16327 *<p> 16328 * When the system calls this method, it passes a 16329 * {@link android.view.DragEvent} object. A call to 16330 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 16331 * in DragEvent. The method uses these to determine what is happening in the drag and drop 16332 * operation. 16333 * @param event The {@link android.view.DragEvent} sent by the system. 16334 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 16335 * in DragEvent, indicating the type of drag event represented by this object. 16336 * @return {@code true} if the method was successful, otherwise {@code false}. 16337 * <p> 16338 * The method should return {@code true} in response to an action type of 16339 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 16340 * operation. 16341 * </p> 16342 * <p> 16343 * The method should also return {@code true} in response to an action type of 16344 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 16345 * {@code false} if it didn't. 16346 * </p> 16347 */ 16348 public boolean onDragEvent(DragEvent event) { 16349 return false; 16350 } 16351 16352 /** 16353 * Detects if this View is enabled and has a drag event listener. 16354 * If both are true, then it calls the drag event listener with the 16355 * {@link android.view.DragEvent} it received. If the drag event listener returns 16356 * {@code true}, then dispatchDragEvent() returns {@code true}. 16357 * <p> 16358 * For all other cases, the method calls the 16359 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 16360 * method and returns its result. 16361 * </p> 16362 * <p> 16363 * This ensures that a drag event is always consumed, even if the View does not have a drag 16364 * event listener. However, if the View has a listener and the listener returns true, then 16365 * onDragEvent() is not called. 16366 * </p> 16367 */ 16368 public boolean dispatchDragEvent(DragEvent event) { 16369 //noinspection SimplifiableIfStatement 16370 ListenerInfo li = mListenerInfo; 16371 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 16372 && li.mOnDragListener.onDrag(this, event)) { 16373 return true; 16374 } 16375 return onDragEvent(event); 16376 } 16377 16378 boolean canAcceptDrag() { 16379 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 16380 } 16381 16382 /** 16383 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 16384 * it is ever exposed at all. 16385 * @hide 16386 */ 16387 public void onCloseSystemDialogs(String reason) { 16388 } 16389 16390 /** 16391 * Given a Drawable whose bounds have been set to draw into this view, 16392 * update a Region being computed for 16393 * {@link #gatherTransparentRegion(android.graphics.Region)} so 16394 * that any non-transparent parts of the Drawable are removed from the 16395 * given transparent region. 16396 * 16397 * @param dr The Drawable whose transparency is to be applied to the region. 16398 * @param region A Region holding the current transparency information, 16399 * where any parts of the region that are set are considered to be 16400 * transparent. On return, this region will be modified to have the 16401 * transparency information reduced by the corresponding parts of the 16402 * Drawable that are not transparent. 16403 * {@hide} 16404 */ 16405 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 16406 if (DBG) { 16407 Log.i("View", "Getting transparent region for: " + this); 16408 } 16409 final Region r = dr.getTransparentRegion(); 16410 final Rect db = dr.getBounds(); 16411 final AttachInfo attachInfo = mAttachInfo; 16412 if (r != null && attachInfo != null) { 16413 final int w = getRight()-getLeft(); 16414 final int h = getBottom()-getTop(); 16415 if (db.left > 0) { 16416 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 16417 r.op(0, 0, db.left, h, Region.Op.UNION); 16418 } 16419 if (db.right < w) { 16420 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 16421 r.op(db.right, 0, w, h, Region.Op.UNION); 16422 } 16423 if (db.top > 0) { 16424 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 16425 r.op(0, 0, w, db.top, Region.Op.UNION); 16426 } 16427 if (db.bottom < h) { 16428 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 16429 r.op(0, db.bottom, w, h, Region.Op.UNION); 16430 } 16431 final int[] location = attachInfo.mTransparentLocation; 16432 getLocationInWindow(location); 16433 r.translate(location[0], location[1]); 16434 region.op(r, Region.Op.INTERSECT); 16435 } else { 16436 region.op(db, Region.Op.DIFFERENCE); 16437 } 16438 } 16439 16440 private void checkForLongClick(int delayOffset) { 16441 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) { 16442 mHasPerformedLongPress = false; 16443 16444 if (mPendingCheckForLongPress == null) { 16445 mPendingCheckForLongPress = new CheckForLongPress(); 16446 } 16447 mPendingCheckForLongPress.rememberWindowAttachCount(); 16448 postDelayed(mPendingCheckForLongPress, 16449 ViewConfiguration.getLongPressTimeout() - delayOffset); 16450 } 16451 } 16452 16453 /** 16454 * Inflate a view from an XML resource. This convenience method wraps the {@link 16455 * LayoutInflater} class, which provides a full range of options for view inflation. 16456 * 16457 * @param context The Context object for your activity or application. 16458 * @param resource The resource ID to inflate 16459 * @param root A view group that will be the parent. Used to properly inflate the 16460 * layout_* parameters. 16461 * @see LayoutInflater 16462 */ 16463 public static View inflate(Context context, int resource, ViewGroup root) { 16464 LayoutInflater factory = LayoutInflater.from(context); 16465 return factory.inflate(resource, root); 16466 } 16467 16468 /** 16469 * Scroll the view with standard behavior for scrolling beyond the normal 16470 * content boundaries. Views that call this method should override 16471 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 16472 * results of an over-scroll operation. 16473 * 16474 * Views can use this method to handle any touch or fling-based scrolling. 16475 * 16476 * @param deltaX Change in X in pixels 16477 * @param deltaY Change in Y in pixels 16478 * @param scrollX Current X scroll value in pixels before applying deltaX 16479 * @param scrollY Current Y scroll value in pixels before applying deltaY 16480 * @param scrollRangeX Maximum content scroll range along the X axis 16481 * @param scrollRangeY Maximum content scroll range along the Y axis 16482 * @param maxOverScrollX Number of pixels to overscroll by in either direction 16483 * along the X axis. 16484 * @param maxOverScrollY Number of pixels to overscroll by in either direction 16485 * along the Y axis. 16486 * @param isTouchEvent true if this scroll operation is the result of a touch event. 16487 * @return true if scrolling was clamped to an over-scroll boundary along either 16488 * axis, false otherwise. 16489 */ 16490 @SuppressWarnings({"UnusedParameters"}) 16491 protected boolean overScrollBy(int deltaX, int deltaY, 16492 int scrollX, int scrollY, 16493 int scrollRangeX, int scrollRangeY, 16494 int maxOverScrollX, int maxOverScrollY, 16495 boolean isTouchEvent) { 16496 final int overScrollMode = mOverScrollMode; 16497 final boolean canScrollHorizontal = 16498 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 16499 final boolean canScrollVertical = 16500 computeVerticalScrollRange() > computeVerticalScrollExtent(); 16501 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 16502 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 16503 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 16504 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 16505 16506 int newScrollX = scrollX + deltaX; 16507 if (!overScrollHorizontal) { 16508 maxOverScrollX = 0; 16509 } 16510 16511 int newScrollY = scrollY + deltaY; 16512 if (!overScrollVertical) { 16513 maxOverScrollY = 0; 16514 } 16515 16516 // Clamp values if at the limits and record 16517 final int left = -maxOverScrollX; 16518 final int right = maxOverScrollX + scrollRangeX; 16519 final int top = -maxOverScrollY; 16520 final int bottom = maxOverScrollY + scrollRangeY; 16521 16522 boolean clampedX = false; 16523 if (newScrollX > right) { 16524 newScrollX = right; 16525 clampedX = true; 16526 } else if (newScrollX < left) { 16527 newScrollX = left; 16528 clampedX = true; 16529 } 16530 16531 boolean clampedY = false; 16532 if (newScrollY > bottom) { 16533 newScrollY = bottom; 16534 clampedY = true; 16535 } else if (newScrollY < top) { 16536 newScrollY = top; 16537 clampedY = true; 16538 } 16539 16540 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 16541 16542 return clampedX || clampedY; 16543 } 16544 16545 /** 16546 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 16547 * respond to the results of an over-scroll operation. 16548 * 16549 * @param scrollX New X scroll value in pixels 16550 * @param scrollY New Y scroll value in pixels 16551 * @param clampedX True if scrollX was clamped to an over-scroll boundary 16552 * @param clampedY True if scrollY was clamped to an over-scroll boundary 16553 */ 16554 protected void onOverScrolled(int scrollX, int scrollY, 16555 boolean clampedX, boolean clampedY) { 16556 // Intentionally empty. 16557 } 16558 16559 /** 16560 * Returns the over-scroll mode for this view. The result will be 16561 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 16562 * (allow over-scrolling only if the view content is larger than the container), 16563 * or {@link #OVER_SCROLL_NEVER}. 16564 * 16565 * @return This view's over-scroll mode. 16566 */ 16567 public int getOverScrollMode() { 16568 return mOverScrollMode; 16569 } 16570 16571 /** 16572 * Set the over-scroll mode for this view. Valid over-scroll modes are 16573 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 16574 * (allow over-scrolling only if the view content is larger than the container), 16575 * or {@link #OVER_SCROLL_NEVER}. 16576 * 16577 * Setting the over-scroll mode of a view will have an effect only if the 16578 * view is capable of scrolling. 16579 * 16580 * @param overScrollMode The new over-scroll mode for this view. 16581 */ 16582 public void setOverScrollMode(int overScrollMode) { 16583 if (overScrollMode != OVER_SCROLL_ALWAYS && 16584 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 16585 overScrollMode != OVER_SCROLL_NEVER) { 16586 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 16587 } 16588 mOverScrollMode = overScrollMode; 16589 } 16590 16591 /** 16592 * Gets a scale factor that determines the distance the view should scroll 16593 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 16594 * @return The vertical scroll scale factor. 16595 * @hide 16596 */ 16597 protected float getVerticalScrollFactor() { 16598 if (mVerticalScrollFactor == 0) { 16599 TypedValue outValue = new TypedValue(); 16600 if (!mContext.getTheme().resolveAttribute( 16601 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 16602 throw new IllegalStateException( 16603 "Expected theme to define listPreferredItemHeight."); 16604 } 16605 mVerticalScrollFactor = outValue.getDimension( 16606 mContext.getResources().getDisplayMetrics()); 16607 } 16608 return mVerticalScrollFactor; 16609 } 16610 16611 /** 16612 * Gets a scale factor that determines the distance the view should scroll 16613 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 16614 * @return The horizontal scroll scale factor. 16615 * @hide 16616 */ 16617 protected float getHorizontalScrollFactor() { 16618 // TODO: Should use something else. 16619 return getVerticalScrollFactor(); 16620 } 16621 16622 /** 16623 * Return the value specifying the text direction or policy that was set with 16624 * {@link #setTextDirection(int)}. 16625 * 16626 * @return the defined text direction. It can be one of: 16627 * 16628 * {@link #TEXT_DIRECTION_INHERIT}, 16629 * {@link #TEXT_DIRECTION_FIRST_STRONG} 16630 * {@link #TEXT_DIRECTION_ANY_RTL}, 16631 * {@link #TEXT_DIRECTION_LTR}, 16632 * {@link #TEXT_DIRECTION_RTL}, 16633 * {@link #TEXT_DIRECTION_LOCALE} 16634 * 16635 * @attr ref android.R.styleable#View_textDirection 16636 * 16637 * @hide 16638 */ 16639 @ViewDebug.ExportedProperty(category = "text", mapping = { 16640 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 16641 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 16642 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 16643 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 16644 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 16645 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE") 16646 }) 16647 public int getRawTextDirection() { 16648 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 16649 } 16650 16651 /** 16652 * Set the text direction. 16653 * 16654 * @param textDirection the direction to set. Should be one of: 16655 * 16656 * {@link #TEXT_DIRECTION_INHERIT}, 16657 * {@link #TEXT_DIRECTION_FIRST_STRONG} 16658 * {@link #TEXT_DIRECTION_ANY_RTL}, 16659 * {@link #TEXT_DIRECTION_LTR}, 16660 * {@link #TEXT_DIRECTION_RTL}, 16661 * {@link #TEXT_DIRECTION_LOCALE} 16662 * 16663 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 16664 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 16665 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 16666 * 16667 * @attr ref android.R.styleable#View_textDirection 16668 */ 16669 public void setTextDirection(int textDirection) { 16670 if (getRawTextDirection() != textDirection) { 16671 // Reset the current text direction and the resolved one 16672 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 16673 resetResolvedTextDirection(); 16674 // Set the new text direction 16675 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 16676 // Do resolution 16677 resolveTextDirection(); 16678 // Notify change 16679 onRtlPropertiesChanged(getLayoutDirection()); 16680 // Refresh 16681 requestLayout(); 16682 invalidate(true); 16683 } 16684 } 16685 16686 /** 16687 * Return the resolved text direction. 16688 * 16689 * @return the resolved text direction. Returns one of: 16690 * 16691 * {@link #TEXT_DIRECTION_FIRST_STRONG} 16692 * {@link #TEXT_DIRECTION_ANY_RTL}, 16693 * {@link #TEXT_DIRECTION_LTR}, 16694 * {@link #TEXT_DIRECTION_RTL}, 16695 * {@link #TEXT_DIRECTION_LOCALE} 16696 * 16697 * @attr ref android.R.styleable#View_textDirection 16698 */ 16699 public int getTextDirection() { 16700 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 16701 } 16702 16703 /** 16704 * Resolve the text direction. 16705 * 16706 * @return true if resolution has been done, false otherwise. 16707 * 16708 * @hide 16709 */ 16710 public boolean resolveTextDirection() { 16711 // Reset any previous text direction resolution 16712 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 16713 16714 if (hasRtlSupport()) { 16715 // Set resolved text direction flag depending on text direction flag 16716 final int textDirection = getRawTextDirection(); 16717 switch(textDirection) { 16718 case TEXT_DIRECTION_INHERIT: 16719 if (!canResolveTextDirection()) { 16720 // We cannot do the resolution if there is no parent, so use the default one 16721 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 16722 // Resolution will need to happen again later 16723 return false; 16724 } 16725 16726 View parent = ((View) mParent); 16727 // Parent has not yet resolved, so we still return the default 16728 if (!parent.isTextDirectionResolved()) { 16729 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 16730 // Resolution will need to happen again later 16731 return false; 16732 } 16733 16734 // Set current resolved direction to the same value as the parent's one 16735 final int parentResolvedDirection = parent.getTextDirection(); 16736 switch (parentResolvedDirection) { 16737 case TEXT_DIRECTION_FIRST_STRONG: 16738 case TEXT_DIRECTION_ANY_RTL: 16739 case TEXT_DIRECTION_LTR: 16740 case TEXT_DIRECTION_RTL: 16741 case TEXT_DIRECTION_LOCALE: 16742 mPrivateFlags2 |= 16743 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 16744 break; 16745 default: 16746 // Default resolved direction is "first strong" heuristic 16747 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 16748 } 16749 break; 16750 case TEXT_DIRECTION_FIRST_STRONG: 16751 case TEXT_DIRECTION_ANY_RTL: 16752 case TEXT_DIRECTION_LTR: 16753 case TEXT_DIRECTION_RTL: 16754 case TEXT_DIRECTION_LOCALE: 16755 // Resolved direction is the same as text direction 16756 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 16757 break; 16758 default: 16759 // Default resolved direction is "first strong" heuristic 16760 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 16761 } 16762 } else { 16763 // Default resolved direction is "first strong" heuristic 16764 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 16765 } 16766 16767 // Set to resolved 16768 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 16769 return true; 16770 } 16771 16772 /** 16773 * Check if text direction resolution can be done. 16774 * 16775 * @return true if text direction resolution can be done otherwise return false. 16776 */ 16777 private boolean canResolveTextDirection() { 16778 switch (getRawTextDirection()) { 16779 case TEXT_DIRECTION_INHERIT: 16780 return (mParent != null) && (mParent instanceof View) && 16781 ((View) mParent).canResolveTextDirection(); 16782 default: 16783 return true; 16784 } 16785 } 16786 16787 /** 16788 * Reset resolved text direction. Text direction will be resolved during a call to 16789 * {@link #onMeasure(int, int)}. 16790 * 16791 * @hide 16792 */ 16793 public void resetResolvedTextDirection() { 16794 // Reset any previous text direction resolution 16795 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 16796 // Set to default value 16797 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 16798 } 16799 16800 /** 16801 * @return true if text direction is inherited. 16802 * 16803 * @hide 16804 */ 16805 public boolean isTextDirectionInherited() { 16806 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 16807 } 16808 16809 /** 16810 * @return true if text direction is resolved. 16811 */ 16812 private boolean isTextDirectionResolved() { 16813 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 16814 } 16815 16816 /** 16817 * Return the value specifying the text alignment or policy that was set with 16818 * {@link #setTextAlignment(int)}. 16819 * 16820 * @return the defined text alignment. It can be one of: 16821 * 16822 * {@link #TEXT_ALIGNMENT_INHERIT}, 16823 * {@link #TEXT_ALIGNMENT_GRAVITY}, 16824 * {@link #TEXT_ALIGNMENT_CENTER}, 16825 * {@link #TEXT_ALIGNMENT_TEXT_START}, 16826 * {@link #TEXT_ALIGNMENT_TEXT_END}, 16827 * {@link #TEXT_ALIGNMENT_VIEW_START}, 16828 * {@link #TEXT_ALIGNMENT_VIEW_END} 16829 * 16830 * @attr ref android.R.styleable#View_textAlignment 16831 * 16832 * @hide 16833 */ 16834 @ViewDebug.ExportedProperty(category = "text", mapping = { 16835 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 16836 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 16837 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 16838 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 16839 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 16840 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 16841 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 16842 }) 16843 public int getRawTextAlignment() { 16844 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 16845 } 16846 16847 /** 16848 * Set the text alignment. 16849 * 16850 * @param textAlignment The text alignment to set. Should be one of 16851 * 16852 * {@link #TEXT_ALIGNMENT_INHERIT}, 16853 * {@link #TEXT_ALIGNMENT_GRAVITY}, 16854 * {@link #TEXT_ALIGNMENT_CENTER}, 16855 * {@link #TEXT_ALIGNMENT_TEXT_START}, 16856 * {@link #TEXT_ALIGNMENT_TEXT_END}, 16857 * {@link #TEXT_ALIGNMENT_VIEW_START}, 16858 * {@link #TEXT_ALIGNMENT_VIEW_END} 16859 * 16860 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 16861 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 16862 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 16863 * 16864 * @attr ref android.R.styleable#View_textAlignment 16865 */ 16866 public void setTextAlignment(int textAlignment) { 16867 if (textAlignment != getRawTextAlignment()) { 16868 // Reset the current and resolved text alignment 16869 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 16870 resetResolvedTextAlignment(); 16871 // Set the new text alignment 16872 mPrivateFlags2 |= 16873 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 16874 // Do resolution 16875 resolveTextAlignment(); 16876 // Notify change 16877 onRtlPropertiesChanged(getLayoutDirection()); 16878 // Refresh 16879 requestLayout(); 16880 invalidate(true); 16881 } 16882 } 16883 16884 /** 16885 * Return the resolved text alignment. 16886 * 16887 * @return the resolved text alignment. Returns one of: 16888 * 16889 * {@link #TEXT_ALIGNMENT_GRAVITY}, 16890 * {@link #TEXT_ALIGNMENT_CENTER}, 16891 * {@link #TEXT_ALIGNMENT_TEXT_START}, 16892 * {@link #TEXT_ALIGNMENT_TEXT_END}, 16893 * {@link #TEXT_ALIGNMENT_VIEW_START}, 16894 * {@link #TEXT_ALIGNMENT_VIEW_END} 16895 * 16896 * @attr ref android.R.styleable#View_textAlignment 16897 */ 16898 @ViewDebug.ExportedProperty(category = "text", mapping = { 16899 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 16900 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 16901 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 16902 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 16903 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 16904 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 16905 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 16906 }) 16907 public int getTextAlignment() { 16908 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 16909 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 16910 } 16911 16912 /** 16913 * Resolve the text alignment. 16914 * 16915 * @return true if resolution has been done, false otherwise. 16916 * 16917 * @hide 16918 */ 16919 public boolean resolveTextAlignment() { 16920 // Reset any previous text alignment resolution 16921 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 16922 16923 if (hasRtlSupport()) { 16924 // Set resolved text alignment flag depending on text alignment flag 16925 final int textAlignment = getRawTextAlignment(); 16926 switch (textAlignment) { 16927 case TEXT_ALIGNMENT_INHERIT: 16928 // Check if we can resolve the text alignment 16929 if (!canResolveTextAlignment()) { 16930 // We cannot do the resolution if there is no parent so use the default 16931 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 16932 // Resolution will need to happen again later 16933 return false; 16934 } 16935 View parent = (View) mParent; 16936 16937 // Parent has not yet resolved, so we still return the default 16938 if (!parent.isTextAlignmentResolved()) { 16939 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 16940 // Resolution will need to happen again later 16941 return false; 16942 } 16943 16944 final int parentResolvedTextAlignment = parent.getTextAlignment(); 16945 switch (parentResolvedTextAlignment) { 16946 case TEXT_ALIGNMENT_GRAVITY: 16947 case TEXT_ALIGNMENT_TEXT_START: 16948 case TEXT_ALIGNMENT_TEXT_END: 16949 case TEXT_ALIGNMENT_CENTER: 16950 case TEXT_ALIGNMENT_VIEW_START: 16951 case TEXT_ALIGNMENT_VIEW_END: 16952 // Resolved text alignment is the same as the parent resolved 16953 // text alignment 16954 mPrivateFlags2 |= 16955 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 16956 break; 16957 default: 16958 // Use default resolved text alignment 16959 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 16960 } 16961 break; 16962 case TEXT_ALIGNMENT_GRAVITY: 16963 case TEXT_ALIGNMENT_TEXT_START: 16964 case TEXT_ALIGNMENT_TEXT_END: 16965 case TEXT_ALIGNMENT_CENTER: 16966 case TEXT_ALIGNMENT_VIEW_START: 16967 case TEXT_ALIGNMENT_VIEW_END: 16968 // Resolved text alignment is the same as text alignment 16969 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 16970 break; 16971 default: 16972 // Use default resolved text alignment 16973 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 16974 } 16975 } else { 16976 // Use default resolved text alignment 16977 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 16978 } 16979 16980 // Set the resolved 16981 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 16982 return true; 16983 } 16984 16985 /** 16986 * Check if text alignment resolution can be done. 16987 * 16988 * @return true if text alignment resolution can be done otherwise return false. 16989 */ 16990 private boolean canResolveTextAlignment() { 16991 switch (getRawTextAlignment()) { 16992 case TEXT_DIRECTION_INHERIT: 16993 return (mParent != null) && (mParent instanceof View) && 16994 ((View) mParent).canResolveTextAlignment(); 16995 default: 16996 return true; 16997 } 16998 } 16999 17000 /** 17001 * Reset resolved text alignment. Text alignment will be resolved during a call to 17002 * {@link #onMeasure(int, int)}. 17003 * 17004 * @hide 17005 */ 17006 public void resetResolvedTextAlignment() { 17007 // Reset any previous text alignment resolution 17008 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 17009 // Set to default 17010 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 17011 } 17012 17013 /** 17014 * @return true if text alignment is inherited. 17015 * 17016 * @hide 17017 */ 17018 public boolean isTextAlignmentInherited() { 17019 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 17020 } 17021 17022 /** 17023 * @return true if text alignment is resolved. 17024 */ 17025 private boolean isTextAlignmentResolved() { 17026 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 17027 } 17028 17029 /** 17030 * Generate a value suitable for use in {@link #setId(int)}. 17031 * This value will not collide with ID values generated at build time by aapt for R.id. 17032 * 17033 * @return a generated ID value 17034 */ 17035 public static int generateViewId() { 17036 for (;;) { 17037 final int result = sNextGeneratedId.get(); 17038 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 17039 int newValue = result + 1; 17040 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 17041 if (sNextGeneratedId.compareAndSet(result, newValue)) { 17042 return result; 17043 } 17044 } 17045 } 17046 17047 // 17048 // Properties 17049 // 17050 /** 17051 * A Property wrapper around the <code>alpha</code> functionality handled by the 17052 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 17053 */ 17054 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 17055 @Override 17056 public void setValue(View object, float value) { 17057 object.setAlpha(value); 17058 } 17059 17060 @Override 17061 public Float get(View object) { 17062 return object.getAlpha(); 17063 } 17064 }; 17065 17066 /** 17067 * A Property wrapper around the <code>translationX</code> functionality handled by the 17068 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 17069 */ 17070 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 17071 @Override 17072 public void setValue(View object, float value) { 17073 object.setTranslationX(value); 17074 } 17075 17076 @Override 17077 public Float get(View object) { 17078 return object.getTranslationX(); 17079 } 17080 }; 17081 17082 /** 17083 * A Property wrapper around the <code>translationY</code> functionality handled by the 17084 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 17085 */ 17086 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 17087 @Override 17088 public void setValue(View object, float value) { 17089 object.setTranslationY(value); 17090 } 17091 17092 @Override 17093 public Float get(View object) { 17094 return object.getTranslationY(); 17095 } 17096 }; 17097 17098 /** 17099 * A Property wrapper around the <code>x</code> functionality handled by the 17100 * {@link View#setX(float)} and {@link View#getX()} methods. 17101 */ 17102 public static final Property<View, Float> X = new FloatProperty<View>("x") { 17103 @Override 17104 public void setValue(View object, float value) { 17105 object.setX(value); 17106 } 17107 17108 @Override 17109 public Float get(View object) { 17110 return object.getX(); 17111 } 17112 }; 17113 17114 /** 17115 * A Property wrapper around the <code>y</code> functionality handled by the 17116 * {@link View#setY(float)} and {@link View#getY()} methods. 17117 */ 17118 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 17119 @Override 17120 public void setValue(View object, float value) { 17121 object.setY(value); 17122 } 17123 17124 @Override 17125 public Float get(View object) { 17126 return object.getY(); 17127 } 17128 }; 17129 17130 /** 17131 * A Property wrapper around the <code>rotation</code> functionality handled by the 17132 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 17133 */ 17134 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 17135 @Override 17136 public void setValue(View object, float value) { 17137 object.setRotation(value); 17138 } 17139 17140 @Override 17141 public Float get(View object) { 17142 return object.getRotation(); 17143 } 17144 }; 17145 17146 /** 17147 * A Property wrapper around the <code>rotationX</code> functionality handled by the 17148 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 17149 */ 17150 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 17151 @Override 17152 public void setValue(View object, float value) { 17153 object.setRotationX(value); 17154 } 17155 17156 @Override 17157 public Float get(View object) { 17158 return object.getRotationX(); 17159 } 17160 }; 17161 17162 /** 17163 * A Property wrapper around the <code>rotationY</code> functionality handled by the 17164 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 17165 */ 17166 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 17167 @Override 17168 public void setValue(View object, float value) { 17169 object.setRotationY(value); 17170 } 17171 17172 @Override 17173 public Float get(View object) { 17174 return object.getRotationY(); 17175 } 17176 }; 17177 17178 /** 17179 * A Property wrapper around the <code>scaleX</code> functionality handled by the 17180 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 17181 */ 17182 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 17183 @Override 17184 public void setValue(View object, float value) { 17185 object.setScaleX(value); 17186 } 17187 17188 @Override 17189 public Float get(View object) { 17190 return object.getScaleX(); 17191 } 17192 }; 17193 17194 /** 17195 * A Property wrapper around the <code>scaleY</code> functionality handled by the 17196 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 17197 */ 17198 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 17199 @Override 17200 public void setValue(View object, float value) { 17201 object.setScaleY(value); 17202 } 17203 17204 @Override 17205 public Float get(View object) { 17206 return object.getScaleY(); 17207 } 17208 }; 17209 17210 /** 17211 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 17212 * Each MeasureSpec represents a requirement for either the width or the height. 17213 * A MeasureSpec is comprised of a size and a mode. There are three possible 17214 * modes: 17215 * <dl> 17216 * <dt>UNSPECIFIED</dt> 17217 * <dd> 17218 * The parent has not imposed any constraint on the child. It can be whatever size 17219 * it wants. 17220 * </dd> 17221 * 17222 * <dt>EXACTLY</dt> 17223 * <dd> 17224 * The parent has determined an exact size for the child. The child is going to be 17225 * given those bounds regardless of how big it wants to be. 17226 * </dd> 17227 * 17228 * <dt>AT_MOST</dt> 17229 * <dd> 17230 * The child can be as large as it wants up to the specified size. 17231 * </dd> 17232 * </dl> 17233 * 17234 * MeasureSpecs are implemented as ints to reduce object allocation. This class 17235 * is provided to pack and unpack the <size, mode> tuple into the int. 17236 */ 17237 public static class MeasureSpec { 17238 private static final int MODE_SHIFT = 30; 17239 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 17240 17241 /** 17242 * Measure specification mode: The parent has not imposed any constraint 17243 * on the child. It can be whatever size it wants. 17244 */ 17245 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 17246 17247 /** 17248 * Measure specification mode: The parent has determined an exact size 17249 * for the child. The child is going to be given those bounds regardless 17250 * of how big it wants to be. 17251 */ 17252 public static final int EXACTLY = 1 << MODE_SHIFT; 17253 17254 /** 17255 * Measure specification mode: The child can be as large as it wants up 17256 * to the specified size. 17257 */ 17258 public static final int AT_MOST = 2 << MODE_SHIFT; 17259 17260 /** 17261 * Creates a measure specification based on the supplied size and mode. 17262 * 17263 * The mode must always be one of the following: 17264 * <ul> 17265 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 17266 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 17267 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 17268 * </ul> 17269 * 17270 * @param size the size of the measure specification 17271 * @param mode the mode of the measure specification 17272 * @return the measure specification based on size and mode 17273 */ 17274 public static int makeMeasureSpec(int size, int mode) { 17275 return size + mode; 17276 } 17277 17278 /** 17279 * Extracts the mode from the supplied measure specification. 17280 * 17281 * @param measureSpec the measure specification to extract the mode from 17282 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 17283 * {@link android.view.View.MeasureSpec#AT_MOST} or 17284 * {@link android.view.View.MeasureSpec#EXACTLY} 17285 */ 17286 public static int getMode(int measureSpec) { 17287 return (measureSpec & MODE_MASK); 17288 } 17289 17290 /** 17291 * Extracts the size from the supplied measure specification. 17292 * 17293 * @param measureSpec the measure specification to extract the size from 17294 * @return the size in pixels defined in the supplied measure specification 17295 */ 17296 public static int getSize(int measureSpec) { 17297 return (measureSpec & ~MODE_MASK); 17298 } 17299 17300 /** 17301 * Returns a String representation of the specified measure 17302 * specification. 17303 * 17304 * @param measureSpec the measure specification to convert to a String 17305 * @return a String with the following format: "MeasureSpec: MODE SIZE" 17306 */ 17307 public static String toString(int measureSpec) { 17308 int mode = getMode(measureSpec); 17309 int size = getSize(measureSpec); 17310 17311 StringBuilder sb = new StringBuilder("MeasureSpec: "); 17312 17313 if (mode == UNSPECIFIED) 17314 sb.append("UNSPECIFIED "); 17315 else if (mode == EXACTLY) 17316 sb.append("EXACTLY "); 17317 else if (mode == AT_MOST) 17318 sb.append("AT_MOST "); 17319 else 17320 sb.append(mode).append(" "); 17321 17322 sb.append(size); 17323 return sb.toString(); 17324 } 17325 } 17326 17327 class CheckForLongPress implements Runnable { 17328 17329 private int mOriginalWindowAttachCount; 17330 17331 public void run() { 17332 if (isPressed() && (mParent != null) 17333 && mOriginalWindowAttachCount == mWindowAttachCount) { 17334 if (performLongClick()) { 17335 mHasPerformedLongPress = true; 17336 } 17337 } 17338 } 17339 17340 public void rememberWindowAttachCount() { 17341 mOriginalWindowAttachCount = mWindowAttachCount; 17342 } 17343 } 17344 17345 private final class CheckForTap implements Runnable { 17346 public void run() { 17347 mPrivateFlags &= ~PFLAG_PREPRESSED; 17348 setPressed(true); 17349 checkForLongClick(ViewConfiguration.getTapTimeout()); 17350 } 17351 } 17352 17353 private final class PerformClick implements Runnable { 17354 public void run() { 17355 performClick(); 17356 } 17357 } 17358 17359 /** @hide */ 17360 public void hackTurnOffWindowResizeAnim(boolean off) { 17361 mAttachInfo.mTurnOffWindowResizeAnim = off; 17362 } 17363 17364 /** 17365 * This method returns a ViewPropertyAnimator object, which can be used to animate 17366 * specific properties on this View. 17367 * 17368 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 17369 */ 17370 public ViewPropertyAnimator animate() { 17371 if (mAnimator == null) { 17372 mAnimator = new ViewPropertyAnimator(this); 17373 } 17374 return mAnimator; 17375 } 17376 17377 /** 17378 * Interface definition for a callback to be invoked when a hardware key event is 17379 * dispatched to this view. The callback will be invoked before the key event is 17380 * given to the view. This is only useful for hardware keyboards; a software input 17381 * method has no obligation to trigger this listener. 17382 */ 17383 public interface OnKeyListener { 17384 /** 17385 * Called when a hardware key is dispatched to a view. This allows listeners to 17386 * get a chance to respond before the target view. 17387 * <p>Key presses in software keyboards will generally NOT trigger this method, 17388 * although some may elect to do so in some situations. Do not assume a 17389 * software input method has to be key-based; even if it is, it may use key presses 17390 * in a different way than you expect, so there is no way to reliably catch soft 17391 * input key presses. 17392 * 17393 * @param v The view the key has been dispatched to. 17394 * @param keyCode The code for the physical key that was pressed 17395 * @param event The KeyEvent object containing full information about 17396 * the event. 17397 * @return True if the listener has consumed the event, false otherwise. 17398 */ 17399 boolean onKey(View v, int keyCode, KeyEvent event); 17400 } 17401 17402 /** 17403 * Interface definition for a callback to be invoked when a touch event is 17404 * dispatched to this view. The callback will be invoked before the touch 17405 * event is given to the view. 17406 */ 17407 public interface OnTouchListener { 17408 /** 17409 * Called when a touch event is dispatched to a view. This allows listeners to 17410 * get a chance to respond before the target view. 17411 * 17412 * @param v The view the touch event has been dispatched to. 17413 * @param event The MotionEvent object containing full information about 17414 * the event. 17415 * @return True if the listener has consumed the event, false otherwise. 17416 */ 17417 boolean onTouch(View v, MotionEvent event); 17418 } 17419 17420 /** 17421 * Interface definition for a callback to be invoked when a hover event is 17422 * dispatched to this view. The callback will be invoked before the hover 17423 * event is given to the view. 17424 */ 17425 public interface OnHoverListener { 17426 /** 17427 * Called when a hover event is dispatched to a view. This allows listeners to 17428 * get a chance to respond before the target view. 17429 * 17430 * @param v The view the hover event has been dispatched to. 17431 * @param event The MotionEvent object containing full information about 17432 * the event. 17433 * @return True if the listener has consumed the event, false otherwise. 17434 */ 17435 boolean onHover(View v, MotionEvent event); 17436 } 17437 17438 /** 17439 * Interface definition for a callback to be invoked when a generic motion event is 17440 * dispatched to this view. The callback will be invoked before the generic motion 17441 * event is given to the view. 17442 */ 17443 public interface OnGenericMotionListener { 17444 /** 17445 * Called when a generic motion event is dispatched to a view. This allows listeners to 17446 * get a chance to respond before the target view. 17447 * 17448 * @param v The view the generic motion event has been dispatched to. 17449 * @param event The MotionEvent object containing full information about 17450 * the event. 17451 * @return True if the listener has consumed the event, false otherwise. 17452 */ 17453 boolean onGenericMotion(View v, MotionEvent event); 17454 } 17455 17456 /** 17457 * Interface definition for a callback to be invoked when a view has been clicked and held. 17458 */ 17459 public interface OnLongClickListener { 17460 /** 17461 * Called when a view has been clicked and held. 17462 * 17463 * @param v The view that was clicked and held. 17464 * 17465 * @return true if the callback consumed the long click, false otherwise. 17466 */ 17467 boolean onLongClick(View v); 17468 } 17469 17470 /** 17471 * Interface definition for a callback to be invoked when a drag is being dispatched 17472 * to this view. The callback will be invoked before the hosting view's own 17473 * onDrag(event) method. If the listener wants to fall back to the hosting view's 17474 * onDrag(event) behavior, it should return 'false' from this callback. 17475 * 17476 * <div class="special reference"> 17477 * <h3>Developer Guides</h3> 17478 * <p>For a guide to implementing drag and drop features, read the 17479 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 17480 * </div> 17481 */ 17482 public interface OnDragListener { 17483 /** 17484 * Called when a drag event is dispatched to a view. This allows listeners 17485 * to get a chance to override base View behavior. 17486 * 17487 * @param v The View that received the drag event. 17488 * @param event The {@link android.view.DragEvent} object for the drag event. 17489 * @return {@code true} if the drag event was handled successfully, or {@code false} 17490 * if the drag event was not handled. Note that {@code false} will trigger the View 17491 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 17492 */ 17493 boolean onDrag(View v, DragEvent event); 17494 } 17495 17496 /** 17497 * Interface definition for a callback to be invoked when the focus state of 17498 * a view changed. 17499 */ 17500 public interface OnFocusChangeListener { 17501 /** 17502 * Called when the focus state of a view has changed. 17503 * 17504 * @param v The view whose state has changed. 17505 * @param hasFocus The new focus state of v. 17506 */ 17507 void onFocusChange(View v, boolean hasFocus); 17508 } 17509 17510 /** 17511 * Interface definition for a callback to be invoked when a view is clicked. 17512 */ 17513 public interface OnClickListener { 17514 /** 17515 * Called when a view has been clicked. 17516 * 17517 * @param v The view that was clicked. 17518 */ 17519 void onClick(View v); 17520 } 17521 17522 /** 17523 * Interface definition for a callback to be invoked when the context menu 17524 * for this view is being built. 17525 */ 17526 public interface OnCreateContextMenuListener { 17527 /** 17528 * Called when the context menu for this view is being built. It is not 17529 * safe to hold onto the menu after this method returns. 17530 * 17531 * @param menu The context menu that is being built 17532 * @param v The view for which the context menu is being built 17533 * @param menuInfo Extra information about the item for which the 17534 * context menu should be shown. This information will vary 17535 * depending on the class of v. 17536 */ 17537 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 17538 } 17539 17540 /** 17541 * Interface definition for a callback to be invoked when the status bar changes 17542 * visibility. This reports <strong>global</strong> changes to the system UI 17543 * state, not what the application is requesting. 17544 * 17545 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 17546 */ 17547 public interface OnSystemUiVisibilityChangeListener { 17548 /** 17549 * Called when the status bar changes visibility because of a call to 17550 * {@link View#setSystemUiVisibility(int)}. 17551 * 17552 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 17553 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 17554 * This tells you the <strong>global</strong> state of these UI visibility 17555 * flags, not what your app is currently applying. 17556 */ 17557 public void onSystemUiVisibilityChange(int visibility); 17558 } 17559 17560 /** 17561 * Interface definition for a callback to be invoked when this view is attached 17562 * or detached from its window. 17563 */ 17564 public interface OnAttachStateChangeListener { 17565 /** 17566 * Called when the view is attached to a window. 17567 * @param v The view that was attached 17568 */ 17569 public void onViewAttachedToWindow(View v); 17570 /** 17571 * Called when the view is detached from a window. 17572 * @param v The view that was detached 17573 */ 17574 public void onViewDetachedFromWindow(View v); 17575 } 17576 17577 private final class UnsetPressedState implements Runnable { 17578 public void run() { 17579 setPressed(false); 17580 } 17581 } 17582 17583 /** 17584 * Base class for derived classes that want to save and restore their own 17585 * state in {@link android.view.View#onSaveInstanceState()}. 17586 */ 17587 public static class BaseSavedState extends AbsSavedState { 17588 /** 17589 * Constructor used when reading from a parcel. Reads the state of the superclass. 17590 * 17591 * @param source 17592 */ 17593 public BaseSavedState(Parcel source) { 17594 super(source); 17595 } 17596 17597 /** 17598 * Constructor called by derived classes when creating their SavedState objects 17599 * 17600 * @param superState The state of the superclass of this view 17601 */ 17602 public BaseSavedState(Parcelable superState) { 17603 super(superState); 17604 } 17605 17606 public static final Parcelable.Creator<BaseSavedState> CREATOR = 17607 new Parcelable.Creator<BaseSavedState>() { 17608 public BaseSavedState createFromParcel(Parcel in) { 17609 return new BaseSavedState(in); 17610 } 17611 17612 public BaseSavedState[] newArray(int size) { 17613 return new BaseSavedState[size]; 17614 } 17615 }; 17616 } 17617 17618 /** 17619 * A set of information given to a view when it is attached to its parent 17620 * window. 17621 */ 17622 static class AttachInfo { 17623 interface Callbacks { 17624 void playSoundEffect(int effectId); 17625 boolean performHapticFeedback(int effectId, boolean always); 17626 } 17627 17628 /** 17629 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 17630 * to a Handler. This class contains the target (View) to invalidate and 17631 * the coordinates of the dirty rectangle. 17632 * 17633 * For performance purposes, this class also implements a pool of up to 17634 * POOL_LIMIT objects that get reused. This reduces memory allocations 17635 * whenever possible. 17636 */ 17637 static class InvalidateInfo implements Poolable<InvalidateInfo> { 17638 private static final int POOL_LIMIT = 10; 17639 private static final Pool<InvalidateInfo> sPool = Pools.synchronizedPool( 17640 Pools.finitePool(new PoolableManager<InvalidateInfo>() { 17641 public InvalidateInfo newInstance() { 17642 return new InvalidateInfo(); 17643 } 17644 17645 public void onAcquired(InvalidateInfo element) { 17646 } 17647 17648 public void onReleased(InvalidateInfo element) { 17649 element.target = null; 17650 } 17651 }, POOL_LIMIT) 17652 ); 17653 17654 private InvalidateInfo mNext; 17655 private boolean mIsPooled; 17656 17657 View target; 17658 17659 int left; 17660 int top; 17661 int right; 17662 int bottom; 17663 17664 public void setNextPoolable(InvalidateInfo element) { 17665 mNext = element; 17666 } 17667 17668 public InvalidateInfo getNextPoolable() { 17669 return mNext; 17670 } 17671 17672 static InvalidateInfo acquire() { 17673 return sPool.acquire(); 17674 } 17675 17676 void release() { 17677 sPool.release(this); 17678 } 17679 17680 public boolean isPooled() { 17681 return mIsPooled; 17682 } 17683 17684 public void setPooled(boolean isPooled) { 17685 mIsPooled = isPooled; 17686 } 17687 } 17688 17689 final IWindowSession mSession; 17690 17691 final IWindow mWindow; 17692 17693 final IBinder mWindowToken; 17694 17695 final Display mDisplay; 17696 17697 final Callbacks mRootCallbacks; 17698 17699 HardwareCanvas mHardwareCanvas; 17700 17701 /** 17702 * The top view of the hierarchy. 17703 */ 17704 View mRootView; 17705 17706 IBinder mPanelParentWindowToken; 17707 Surface mSurface; 17708 17709 boolean mHardwareAccelerated; 17710 boolean mHardwareAccelerationRequested; 17711 HardwareRenderer mHardwareRenderer; 17712 17713 boolean mScreenOn; 17714 17715 /** 17716 * Scale factor used by the compatibility mode 17717 */ 17718 float mApplicationScale; 17719 17720 /** 17721 * Indicates whether the application is in compatibility mode 17722 */ 17723 boolean mScalingRequired; 17724 17725 /** 17726 * If set, ViewRootImpl doesn't use its lame animation for when the window resizes. 17727 */ 17728 boolean mTurnOffWindowResizeAnim; 17729 17730 /** 17731 * Left position of this view's window 17732 */ 17733 int mWindowLeft; 17734 17735 /** 17736 * Top position of this view's window 17737 */ 17738 int mWindowTop; 17739 17740 /** 17741 * Indicates whether views need to use 32-bit drawing caches 17742 */ 17743 boolean mUse32BitDrawingCache; 17744 17745 /** 17746 * For windows that are full-screen but using insets to layout inside 17747 * of the screen decorations, these are the current insets for the 17748 * content of the window. 17749 */ 17750 final Rect mContentInsets = new Rect(); 17751 17752 /** 17753 * For windows that are full-screen but using insets to layout inside 17754 * of the screen decorations, these are the current insets for the 17755 * actual visible parts of the window. 17756 */ 17757 final Rect mVisibleInsets = new Rect(); 17758 17759 /** 17760 * The internal insets given by this window. This value is 17761 * supplied by the client (through 17762 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 17763 * be given to the window manager when changed to be used in laying 17764 * out windows behind it. 17765 */ 17766 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 17767 = new ViewTreeObserver.InternalInsetsInfo(); 17768 17769 /** 17770 * All views in the window's hierarchy that serve as scroll containers, 17771 * used to determine if the window can be resized or must be panned 17772 * to adjust for a soft input area. 17773 */ 17774 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 17775 17776 final KeyEvent.DispatcherState mKeyDispatchState 17777 = new KeyEvent.DispatcherState(); 17778 17779 /** 17780 * Indicates whether the view's window currently has the focus. 17781 */ 17782 boolean mHasWindowFocus; 17783 17784 /** 17785 * The current visibility of the window. 17786 */ 17787 int mWindowVisibility; 17788 17789 /** 17790 * Indicates the time at which drawing started to occur. 17791 */ 17792 long mDrawingTime; 17793 17794 /** 17795 * Indicates whether or not ignoring the DIRTY_MASK flags. 17796 */ 17797 boolean mIgnoreDirtyState; 17798 17799 /** 17800 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 17801 * to avoid clearing that flag prematurely. 17802 */ 17803 boolean mSetIgnoreDirtyState = false; 17804 17805 /** 17806 * Indicates whether the view's window is currently in touch mode. 17807 */ 17808 boolean mInTouchMode; 17809 17810 /** 17811 * Indicates that ViewAncestor should trigger a global layout change 17812 * the next time it performs a traversal 17813 */ 17814 boolean mRecomputeGlobalAttributes; 17815 17816 /** 17817 * Always report new attributes at next traversal. 17818 */ 17819 boolean mForceReportNewAttributes; 17820 17821 /** 17822 * Set during a traveral if any views want to keep the screen on. 17823 */ 17824 boolean mKeepScreenOn; 17825 17826 /** 17827 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 17828 */ 17829 int mSystemUiVisibility; 17830 17831 /** 17832 * Hack to force certain system UI visibility flags to be cleared. 17833 */ 17834 int mDisabledSystemUiVisibility; 17835 17836 /** 17837 * Last global system UI visibility reported by the window manager. 17838 */ 17839 int mGlobalSystemUiVisibility; 17840 17841 /** 17842 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 17843 * attached. 17844 */ 17845 boolean mHasSystemUiListeners; 17846 17847 /** 17848 * Set if the visibility of any views has changed. 17849 */ 17850 boolean mViewVisibilityChanged; 17851 17852 /** 17853 * Set to true if a view has been scrolled. 17854 */ 17855 boolean mViewScrollChanged; 17856 17857 /** 17858 * Global to the view hierarchy used as a temporary for dealing with 17859 * x/y points in the transparent region computations. 17860 */ 17861 final int[] mTransparentLocation = new int[2]; 17862 17863 /** 17864 * Global to the view hierarchy used as a temporary for dealing with 17865 * x/y points in the ViewGroup.invalidateChild implementation. 17866 */ 17867 final int[] mInvalidateChildLocation = new int[2]; 17868 17869 17870 /** 17871 * Global to the view hierarchy used as a temporary for dealing with 17872 * x/y location when view is transformed. 17873 */ 17874 final float[] mTmpTransformLocation = new float[2]; 17875 17876 /** 17877 * The view tree observer used to dispatch global events like 17878 * layout, pre-draw, touch mode change, etc. 17879 */ 17880 final ViewTreeObserver mTreeObserver = new ViewTreeObserver(); 17881 17882 /** 17883 * A Canvas used by the view hierarchy to perform bitmap caching. 17884 */ 17885 Canvas mCanvas; 17886 17887 /** 17888 * The view root impl. 17889 */ 17890 final ViewRootImpl mViewRootImpl; 17891 17892 /** 17893 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 17894 * handler can be used to pump events in the UI events queue. 17895 */ 17896 final Handler mHandler; 17897 17898 /** 17899 * Temporary for use in computing invalidate rectangles while 17900 * calling up the hierarchy. 17901 */ 17902 final Rect mTmpInvalRect = new Rect(); 17903 17904 /** 17905 * Temporary for use in computing hit areas with transformed views 17906 */ 17907 final RectF mTmpTransformRect = new RectF(); 17908 17909 /** 17910 * Temporary for use in transforming invalidation rect 17911 */ 17912 final Matrix mTmpMatrix = new Matrix(); 17913 17914 /** 17915 * Temporary for use in transforming invalidation rect 17916 */ 17917 final Transformation mTmpTransformation = new Transformation(); 17918 17919 /** 17920 * Temporary list for use in collecting focusable descendents of a view. 17921 */ 17922 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 17923 17924 /** 17925 * The id of the window for accessibility purposes. 17926 */ 17927 int mAccessibilityWindowId = View.NO_ID; 17928 17929 /** 17930 * Whether to ingore not exposed for accessibility Views when 17931 * reporting the view tree to accessibility services. 17932 */ 17933 boolean mIncludeNotImportantViews; 17934 17935 /** 17936 * The drawable for highlighting accessibility focus. 17937 */ 17938 Drawable mAccessibilityFocusDrawable; 17939 17940 /** 17941 * Show where the margins, bounds and layout bounds are for each view. 17942 */ 17943 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 17944 17945 /** 17946 * Point used to compute visible regions. 17947 */ 17948 final Point mPoint = new Point(); 17949 17950 /** 17951 * Creates a new set of attachment information with the specified 17952 * events handler and thread. 17953 * 17954 * @param handler the events handler the view must use 17955 */ 17956 AttachInfo(IWindowSession session, IWindow window, Display display, 17957 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) { 17958 mSession = session; 17959 mWindow = window; 17960 mWindowToken = window.asBinder(); 17961 mDisplay = display; 17962 mViewRootImpl = viewRootImpl; 17963 mHandler = handler; 17964 mRootCallbacks = effectPlayer; 17965 } 17966 } 17967 17968 /** 17969 * <p>ScrollabilityCache holds various fields used by a View when scrolling 17970 * is supported. This avoids keeping too many unused fields in most 17971 * instances of View.</p> 17972 */ 17973 private static class ScrollabilityCache implements Runnable { 17974 17975 /** 17976 * Scrollbars are not visible 17977 */ 17978 public static final int OFF = 0; 17979 17980 /** 17981 * Scrollbars are visible 17982 */ 17983 public static final int ON = 1; 17984 17985 /** 17986 * Scrollbars are fading away 17987 */ 17988 public static final int FADING = 2; 17989 17990 public boolean fadeScrollBars; 17991 17992 public int fadingEdgeLength; 17993 public int scrollBarDefaultDelayBeforeFade; 17994 public int scrollBarFadeDuration; 17995 17996 public int scrollBarSize; 17997 public ScrollBarDrawable scrollBar; 17998 public float[] interpolatorValues; 17999 public View host; 18000 18001 public final Paint paint; 18002 public final Matrix matrix; 18003 public Shader shader; 18004 18005 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 18006 18007 private static final float[] OPAQUE = { 255 }; 18008 private static final float[] TRANSPARENT = { 0.0f }; 18009 18010 /** 18011 * When fading should start. This time moves into the future every time 18012 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 18013 */ 18014 public long fadeStartTime; 18015 18016 18017 /** 18018 * The current state of the scrollbars: ON, OFF, or FADING 18019 */ 18020 public int state = OFF; 18021 18022 private int mLastColor; 18023 18024 public ScrollabilityCache(ViewConfiguration configuration, View host) { 18025 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 18026 scrollBarSize = configuration.getScaledScrollBarSize(); 18027 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 18028 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 18029 18030 paint = new Paint(); 18031 matrix = new Matrix(); 18032 // use use a height of 1, and then wack the matrix each time we 18033 // actually use it. 18034 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 18035 paint.setShader(shader); 18036 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 18037 18038 this.host = host; 18039 } 18040 18041 public void setFadeColor(int color) { 18042 if (color != mLastColor) { 18043 mLastColor = color; 18044 18045 if (color != 0) { 18046 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 18047 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 18048 paint.setShader(shader); 18049 // Restore the default transfer mode (src_over) 18050 paint.setXfermode(null); 18051 } else { 18052 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 18053 paint.setShader(shader); 18054 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 18055 } 18056 } 18057 } 18058 18059 public void run() { 18060 long now = AnimationUtils.currentAnimationTimeMillis(); 18061 if (now >= fadeStartTime) { 18062 18063 // the animation fades the scrollbars out by changing 18064 // the opacity (alpha) from fully opaque to fully 18065 // transparent 18066 int nextFrame = (int) now; 18067 int framesCount = 0; 18068 18069 Interpolator interpolator = scrollBarInterpolator; 18070 18071 // Start opaque 18072 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 18073 18074 // End transparent 18075 nextFrame += scrollBarFadeDuration; 18076 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 18077 18078 state = FADING; 18079 18080 // Kick off the fade animation 18081 host.invalidate(true); 18082 } 18083 } 18084 } 18085 18086 /** 18087 * Resuable callback for sending 18088 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 18089 */ 18090 private class SendViewScrolledAccessibilityEvent implements Runnable { 18091 public volatile boolean mIsPending; 18092 18093 public void run() { 18094 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 18095 mIsPending = false; 18096 } 18097 } 18098 18099 /** 18100 * <p> 18101 * This class represents a delegate that can be registered in a {@link View} 18102 * to enhance accessibility support via composition rather via inheritance. 18103 * It is specifically targeted to widget developers that extend basic View 18104 * classes i.e. classes in package android.view, that would like their 18105 * applications to be backwards compatible. 18106 * </p> 18107 * <div class="special reference"> 18108 * <h3>Developer Guides</h3> 18109 * <p>For more information about making applications accessible, read the 18110 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 18111 * developer guide.</p> 18112 * </div> 18113 * <p> 18114 * A scenario in which a developer would like to use an accessibility delegate 18115 * is overriding a method introduced in a later API version then the minimal API 18116 * version supported by the application. For example, the method 18117 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 18118 * in API version 4 when the accessibility APIs were first introduced. If a 18119 * developer would like his application to run on API version 4 devices (assuming 18120 * all other APIs used by the application are version 4 or lower) and take advantage 18121 * of this method, instead of overriding the method which would break the application's 18122 * backwards compatibility, he can override the corresponding method in this 18123 * delegate and register the delegate in the target View if the API version of 18124 * the system is high enough i.e. the API version is same or higher to the API 18125 * version that introduced 18126 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 18127 * </p> 18128 * <p> 18129 * Here is an example implementation: 18130 * </p> 18131 * <code><pre><p> 18132 * if (Build.VERSION.SDK_INT >= 14) { 18133 * // If the API version is equal of higher than the version in 18134 * // which onInitializeAccessibilityNodeInfo was introduced we 18135 * // register a delegate with a customized implementation. 18136 * View view = findViewById(R.id.view_id); 18137 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 18138 * public void onInitializeAccessibilityNodeInfo(View host, 18139 * AccessibilityNodeInfo info) { 18140 * // Let the default implementation populate the info. 18141 * super.onInitializeAccessibilityNodeInfo(host, info); 18142 * // Set some other information. 18143 * info.setEnabled(host.isEnabled()); 18144 * } 18145 * }); 18146 * } 18147 * </code></pre></p> 18148 * <p> 18149 * This delegate contains methods that correspond to the accessibility methods 18150 * in View. If a delegate has been specified the implementation in View hands 18151 * off handling to the corresponding method in this delegate. The default 18152 * implementation the delegate methods behaves exactly as the corresponding 18153 * method in View for the case of no accessibility delegate been set. Hence, 18154 * to customize the behavior of a View method, clients can override only the 18155 * corresponding delegate method without altering the behavior of the rest 18156 * accessibility related methods of the host view. 18157 * </p> 18158 */ 18159 public static class AccessibilityDelegate { 18160 18161 /** 18162 * Sends an accessibility event of the given type. If accessibility is not 18163 * enabled this method has no effect. 18164 * <p> 18165 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 18166 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 18167 * been set. 18168 * </p> 18169 * 18170 * @param host The View hosting the delegate. 18171 * @param eventType The type of the event to send. 18172 * 18173 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 18174 */ 18175 public void sendAccessibilityEvent(View host, int eventType) { 18176 host.sendAccessibilityEventInternal(eventType); 18177 } 18178 18179 /** 18180 * Performs the specified accessibility action on the view. For 18181 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 18182 * <p> 18183 * The default implementation behaves as 18184 * {@link View#performAccessibilityAction(int, Bundle) 18185 * View#performAccessibilityAction(int, Bundle)} for the case of 18186 * no accessibility delegate been set. 18187 * </p> 18188 * 18189 * @param action The action to perform. 18190 * @return Whether the action was performed. 18191 * 18192 * @see View#performAccessibilityAction(int, Bundle) 18193 * View#performAccessibilityAction(int, Bundle) 18194 */ 18195 public boolean performAccessibilityAction(View host, int action, Bundle args) { 18196 return host.performAccessibilityActionInternal(action, args); 18197 } 18198 18199 /** 18200 * Sends an accessibility event. This method behaves exactly as 18201 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 18202 * empty {@link AccessibilityEvent} and does not perform a check whether 18203 * accessibility is enabled. 18204 * <p> 18205 * The default implementation behaves as 18206 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 18207 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 18208 * the case of no accessibility delegate been set. 18209 * </p> 18210 * 18211 * @param host The View hosting the delegate. 18212 * @param event The event to send. 18213 * 18214 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 18215 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 18216 */ 18217 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 18218 host.sendAccessibilityEventUncheckedInternal(event); 18219 } 18220 18221 /** 18222 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 18223 * to its children for adding their text content to the event. 18224 * <p> 18225 * The default implementation behaves as 18226 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 18227 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 18228 * the case of no accessibility delegate been set. 18229 * </p> 18230 * 18231 * @param host The View hosting the delegate. 18232 * @param event The event. 18233 * @return True if the event population was completed. 18234 * 18235 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 18236 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 18237 */ 18238 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 18239 return host.dispatchPopulateAccessibilityEventInternal(event); 18240 } 18241 18242 /** 18243 * Gives a chance to the host View to populate the accessibility event with its 18244 * text content. 18245 * <p> 18246 * The default implementation behaves as 18247 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 18248 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 18249 * the case of no accessibility delegate been set. 18250 * </p> 18251 * 18252 * @param host The View hosting the delegate. 18253 * @param event The accessibility event which to populate. 18254 * 18255 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 18256 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 18257 */ 18258 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 18259 host.onPopulateAccessibilityEventInternal(event); 18260 } 18261 18262 /** 18263 * Initializes an {@link AccessibilityEvent} with information about the 18264 * the host View which is the event source. 18265 * <p> 18266 * The default implementation behaves as 18267 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 18268 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 18269 * the case of no accessibility delegate been set. 18270 * </p> 18271 * 18272 * @param host The View hosting the delegate. 18273 * @param event The event to initialize. 18274 * 18275 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 18276 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 18277 */ 18278 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 18279 host.onInitializeAccessibilityEventInternal(event); 18280 } 18281 18282 /** 18283 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 18284 * <p> 18285 * The default implementation behaves as 18286 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 18287 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 18288 * the case of no accessibility delegate been set. 18289 * </p> 18290 * 18291 * @param host The View hosting the delegate. 18292 * @param info The instance to initialize. 18293 * 18294 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 18295 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 18296 */ 18297 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 18298 host.onInitializeAccessibilityNodeInfoInternal(info); 18299 } 18300 18301 /** 18302 * Called when a child of the host View has requested sending an 18303 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 18304 * to augment the event. 18305 * <p> 18306 * The default implementation behaves as 18307 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 18308 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 18309 * the case of no accessibility delegate been set. 18310 * </p> 18311 * 18312 * @param host The View hosting the delegate. 18313 * @param child The child which requests sending the event. 18314 * @param event The event to be sent. 18315 * @return True if the event should be sent 18316 * 18317 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 18318 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 18319 */ 18320 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 18321 AccessibilityEvent event) { 18322 return host.onRequestSendAccessibilityEventInternal(child, event); 18323 } 18324 18325 /** 18326 * Gets the provider for managing a virtual view hierarchy rooted at this View 18327 * and reported to {@link android.accessibilityservice.AccessibilityService}s 18328 * that explore the window content. 18329 * <p> 18330 * The default implementation behaves as 18331 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 18332 * the case of no accessibility delegate been set. 18333 * </p> 18334 * 18335 * @return The provider. 18336 * 18337 * @see AccessibilityNodeProvider 18338 */ 18339 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 18340 return null; 18341 } 18342 } 18343 18344 private class MatchIdPredicate implements Predicate<View> { 18345 public int mId; 18346 18347 @Override 18348 public boolean apply(View view) { 18349 return (view.mID == mId); 18350 } 18351 } 18352 18353 private class MatchLabelForPredicate implements Predicate<View> { 18354 private int mLabeledId; 18355 18356 @Override 18357 public boolean apply(View view) { 18358 return (view.mLabelForId == mLabeledId); 18359 } 18360 } 18361 18362 /** 18363 * Dump all private flags in readable format, useful for documentation and 18364 * sanity checking. 18365 */ 18366 private static void dumpFlags() { 18367 final HashMap<String, String> found = Maps.newHashMap(); 18368 try { 18369 for (Field field : View.class.getDeclaredFields()) { 18370 final int modifiers = field.getModifiers(); 18371 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 18372 if (field.getType().equals(int.class)) { 18373 final int value = field.getInt(null); 18374 dumpFlag(found, field.getName(), value); 18375 } else if (field.getType().equals(int[].class)) { 18376 final int[] values = (int[]) field.get(null); 18377 for (int i = 0; i < values.length; i++) { 18378 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 18379 } 18380 } 18381 } 18382 } 18383 } catch (IllegalAccessException e) { 18384 throw new RuntimeException(e); 18385 } 18386 18387 final ArrayList<String> keys = Lists.newArrayList(); 18388 keys.addAll(found.keySet()); 18389 Collections.sort(keys); 18390 for (String key : keys) { 18391 Log.d(VIEW_LOG_TAG, found.get(key)); 18392 } 18393 } 18394 18395 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 18396 // Sort flags by prefix, then by bits, always keeping unique keys 18397 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 18398 final int prefix = name.indexOf('_'); 18399 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 18400 final String output = bits + " " + name; 18401 found.put(key, output); 18402 } 18403 } 18404