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 com.android.internal.R; 20 import com.android.internal.view.menu.MenuBuilder; 21 22 import android.content.Context; 23 import android.content.res.Configuration; 24 import android.content.res.Resources; 25 import android.content.res.TypedArray; 26 import android.graphics.Bitmap; 27 import android.graphics.Canvas; 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.Region; 38 import android.graphics.Shader; 39 import android.graphics.drawable.ColorDrawable; 40 import android.graphics.drawable.Drawable; 41 import android.os.Handler; 42 import android.os.IBinder; 43 import android.os.Message; 44 import android.os.Parcel; 45 import android.os.Parcelable; 46 import android.os.RemoteException; 47 import android.os.SystemClock; 48 import android.os.SystemProperties; 49 import android.util.AttributeSet; 50 import android.util.Config; 51 import android.util.EventLog; 52 import android.util.Log; 53 import android.util.Pool; 54 import android.util.Poolable; 55 import android.util.PoolableManager; 56 import android.util.Pools; 57 import android.util.SparseArray; 58 import android.view.ContextMenu.ContextMenuInfo; 59 import android.view.accessibility.AccessibilityEvent; 60 import android.view.accessibility.AccessibilityEventSource; 61 import android.view.accessibility.AccessibilityManager; 62 import android.view.animation.Animation; 63 import android.view.animation.AnimationUtils; 64 import android.view.inputmethod.EditorInfo; 65 import android.view.inputmethod.InputConnection; 66 import android.view.inputmethod.InputMethodManager; 67 import android.widget.ScrollBarDrawable; 68 69 import java.lang.ref.SoftReference; 70 import java.lang.reflect.InvocationTargetException; 71 import java.lang.reflect.Method; 72 import java.util.ArrayList; 73 import java.util.Arrays; 74 import java.util.WeakHashMap; 75 76 /** 77 * <p> 78 * This class represents the basic building block for user interface components. A View 79 * occupies a rectangular area on the screen and is responsible for drawing and 80 * event handling. View is the base class for <em>widgets</em>, which are 81 * used to create interactive UI components (buttons, text fields, etc.). The 82 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 83 * are invisible containers that hold other Views (or other ViewGroups) and define 84 * their layout properties. 85 * </p> 86 * 87 * <div class="special"> 88 * <p>For an introduction to using this class to develop your 89 * application's user interface, read the Developer Guide documentation on 90 * <strong><a href="{@docRoot}guide/topics/ui/index.html">User Interface</a></strong>. Special topics 91 * include: 92 * <br/><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a> 93 * <br/><a href="{@docRoot}guide/topics/ui/menus.html">Creating Menus</a> 94 * <br/><a href="{@docRoot}guide/topics/ui/layout-objects.html">Common Layout Objects</a> 95 * <br/><a href="{@docRoot}guide/topics/ui/binding.html">Binding to Data with AdapterView</a> 96 * <br/><a href="{@docRoot}guide/topics/ui/ui-events.html">Handling UI Events</a> 97 * <br/><a href="{@docRoot}guide/topics/ui/themes.html">Applying Styles and Themes</a> 98 * <br/><a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a> 99 * <br/><a href="{@docRoot}guide/topics/ui/how-android-draws.html">How Android Draws Views</a>. 100 * </p> 101 * </div> 102 * 103 * <a name="Using"></a> 104 * <h3>Using Views</h3> 105 * <p> 106 * All of the views in a window are arranged in a single tree. You can add views 107 * either from code or by specifying a tree of views in one or more XML layout 108 * files. There are many specialized subclasses of views that act as controls or 109 * are capable of displaying text, images, or other content. 110 * </p> 111 * <p> 112 * Once you have created a tree of views, there are typically a few types of 113 * common operations you may wish to perform: 114 * <ul> 115 * <li><strong>Set properties:</strong> for example setting the text of a 116 * {@link android.widget.TextView}. The available properties and the methods 117 * that set them will vary among the different subclasses of views. Note that 118 * properties that are known at build time can be set in the XML layout 119 * files.</li> 120 * <li><strong>Set focus:</strong> The framework will handled moving focus in 121 * response to user input. To force focus to a specific view, call 122 * {@link #requestFocus}.</li> 123 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 124 * that will be notified when something interesting happens to the view. For 125 * example, all views will let you set a listener to be notified when the view 126 * gains or loses focus. You can register such a listener using 127 * {@link #setOnFocusChangeListener}. Other view subclasses offer more 128 * specialized listeners. For example, a Button exposes a listener to notify 129 * clients when the button is clicked.</li> 130 * <li><strong>Set visibility:</strong> You can hide or show views using 131 * {@link #setVisibility}.</li> 132 * </ul> 133 * </p> 134 * <p><em> 135 * Note: The Android framework is responsible for measuring, laying out and 136 * drawing views. You should not call methods that perform these actions on 137 * views yourself unless you are actually implementing a 138 * {@link android.view.ViewGroup}. 139 * </em></p> 140 * 141 * <a name="Lifecycle"></a> 142 * <h3>Implementing a Custom View</h3> 143 * 144 * <p> 145 * To implement a custom view, you will usually begin by providing overrides for 146 * some of the standard methods that the framework calls on all views. You do 147 * not need to override all of these methods. In fact, you can start by just 148 * overriding {@link #onDraw(android.graphics.Canvas)}. 149 * <table border="2" width="85%" align="center" cellpadding="5"> 150 * <thead> 151 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 152 * </thead> 153 * 154 * <tbody> 155 * <tr> 156 * <td rowspan="2">Creation</td> 157 * <td>Constructors</td> 158 * <td>There is a form of the constructor that are called when the view 159 * is created from code and a form that is called when the view is 160 * inflated from a layout file. The second form should parse and apply 161 * any attributes defined in the layout file. 162 * </td> 163 * </tr> 164 * <tr> 165 * <td><code>{@link #onFinishInflate()}</code></td> 166 * <td>Called after a view and all of its children has been inflated 167 * from XML.</td> 168 * </tr> 169 * 170 * <tr> 171 * <td rowspan="3">Layout</td> 172 * <td><code>{@link #onMeasure}</code></td> 173 * <td>Called to determine the size requirements for this view and all 174 * of its children. 175 * </td> 176 * </tr> 177 * <tr> 178 * <td><code>{@link #onLayout}</code></td> 179 * <td>Called when this view should assign a size and position to all 180 * of its children. 181 * </td> 182 * </tr> 183 * <tr> 184 * <td><code>{@link #onSizeChanged}</code></td> 185 * <td>Called when the size of this view has changed. 186 * </td> 187 * </tr> 188 * 189 * <tr> 190 * <td>Drawing</td> 191 * <td><code>{@link #onDraw}</code></td> 192 * <td>Called when the view should render its content. 193 * </td> 194 * </tr> 195 * 196 * <tr> 197 * <td rowspan="4">Event processing</td> 198 * <td><code>{@link #onKeyDown}</code></td> 199 * <td>Called when a new key event occurs. 200 * </td> 201 * </tr> 202 * <tr> 203 * <td><code>{@link #onKeyUp}</code></td> 204 * <td>Called when a key up event occurs. 205 * </td> 206 * </tr> 207 * <tr> 208 * <td><code>{@link #onTrackballEvent}</code></td> 209 * <td>Called when a trackball motion event occurs. 210 * </td> 211 * </tr> 212 * <tr> 213 * <td><code>{@link #onTouchEvent}</code></td> 214 * <td>Called when a touch screen motion event occurs. 215 * </td> 216 * </tr> 217 * 218 * <tr> 219 * <td rowspan="2">Focus</td> 220 * <td><code>{@link #onFocusChanged}</code></td> 221 * <td>Called when the view gains or loses focus. 222 * </td> 223 * </tr> 224 * 225 * <tr> 226 * <td><code>{@link #onWindowFocusChanged}</code></td> 227 * <td>Called when the window containing the view gains or loses focus. 228 * </td> 229 * </tr> 230 * 231 * <tr> 232 * <td rowspan="3">Attaching</td> 233 * <td><code>{@link #onAttachedToWindow()}</code></td> 234 * <td>Called when the view is attached to a window. 235 * </td> 236 * </tr> 237 * 238 * <tr> 239 * <td><code>{@link #onDetachedFromWindow}</code></td> 240 * <td>Called when the view is detached from its window. 241 * </td> 242 * </tr> 243 * 244 * <tr> 245 * <td><code>{@link #onWindowVisibilityChanged}</code></td> 246 * <td>Called when the visibility of the window containing the view 247 * has changed. 248 * </td> 249 * </tr> 250 * </tbody> 251 * 252 * </table> 253 * </p> 254 * 255 * <a name="IDs"></a> 256 * <h3>IDs</h3> 257 * Views may have an integer id associated with them. These ids are typically 258 * assigned in the layout XML files, and are used to find specific views within 259 * the view tree. A common pattern is to: 260 * <ul> 261 * <li>Define a Button in the layout file and assign it a unique ID. 262 * <pre> 263 * <Button id="@+id/my_button" 264 * android:layout_width="wrap_content" 265 * android:layout_height="wrap_content" 266 * android:text="@string/my_button_text"/> 267 * </pre></li> 268 * <li>From the onCreate method of an Activity, find the Button 269 * <pre class="prettyprint"> 270 * Button myButton = (Button) findViewById(R.id.my_button); 271 * </pre></li> 272 * </ul> 273 * <p> 274 * View IDs need not be unique throughout the tree, but it is good practice to 275 * ensure that they are at least unique within the part of the tree you are 276 * searching. 277 * </p> 278 * 279 * <a name="Position"></a> 280 * <h3>Position</h3> 281 * <p> 282 * The geometry of a view is that of a rectangle. A view has a location, 283 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 284 * two dimensions, expressed as a width and a height. The unit for location 285 * and dimensions is the pixel. 286 * </p> 287 * 288 * <p> 289 * It is possible to retrieve the location of a view by invoking the methods 290 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 291 * coordinate of the rectangle representing the view. The latter returns the 292 * top, or Y, coordinate of the rectangle representing the view. These methods 293 * both return the location of the view relative to its parent. For instance, 294 * when getLeft() returns 20, that means the view is located 20 pixels to the 295 * right of the left edge of its direct parent. 296 * </p> 297 * 298 * <p> 299 * In addition, several convenience methods are offered to avoid unnecessary 300 * computations, namely {@link #getRight()} and {@link #getBottom()}. 301 * These methods return the coordinates of the right and bottom edges of the 302 * rectangle representing the view. For instance, calling {@link #getRight()} 303 * is similar to the following computation: <code>getLeft() + getWidth()</code> 304 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 305 * </p> 306 * 307 * <a name="SizePaddingMargins"></a> 308 * <h3>Size, padding and margins</h3> 309 * <p> 310 * The size of a view is expressed with a width and a height. A view actually 311 * possess two pairs of width and height values. 312 * </p> 313 * 314 * <p> 315 * The first pair is known as <em>measured width</em> and 316 * <em>measured height</em>. These dimensions define how big a view wants to be 317 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 318 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 319 * and {@link #getMeasuredHeight()}. 320 * </p> 321 * 322 * <p> 323 * The second pair is simply known as <em>width</em> and <em>height</em>, or 324 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 325 * dimensions define the actual size of the view on screen, at drawing time and 326 * after layout. These values may, but do not have to, be different from the 327 * measured width and height. The width and height can be obtained by calling 328 * {@link #getWidth()} and {@link #getHeight()}. 329 * </p> 330 * 331 * <p> 332 * To measure its dimensions, a view takes into account its padding. The padding 333 * is expressed in pixels for the left, top, right and bottom parts of the view. 334 * Padding can be used to offset the content of the view by a specific amount of 335 * pixels. For instance, a left padding of 2 will push the view's content by 336 * 2 pixels to the right of the left edge. Padding can be set using the 337 * {@link #setPadding(int, int, int, int)} method and queried by calling 338 * {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 339 * {@link #getPaddingRight()} and {@link #getPaddingBottom()}. 340 * </p> 341 * 342 * <p> 343 * Even though a view can define a padding, it does not provide any support for 344 * margins. However, view groups provide such a support. Refer to 345 * {@link android.view.ViewGroup} and 346 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 347 * </p> 348 * 349 * <a name="Layout"></a> 350 * <h3>Layout</h3> 351 * <p> 352 * Layout is a two pass process: a measure pass and a layout pass. The measuring 353 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 354 * of the view tree. Each view pushes dimension specifications down the tree 355 * during the recursion. At the end of the measure pass, every view has stored 356 * its measurements. The second pass happens in 357 * {@link #layout(int,int,int,int)} and is also top-down. During 358 * this pass each parent is responsible for positioning all of its children 359 * using the sizes computed in the measure pass. 360 * </p> 361 * 362 * <p> 363 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 364 * {@link #getMeasuredHeight()} values must be set, along with those for all of 365 * that view's descendants. A view's measured width and measured height values 366 * must respect the constraints imposed by the view's parents. This guarantees 367 * that at the end of the measure pass, all parents accept all of their 368 * children's measurements. A parent view may call measure() more than once on 369 * its children. For example, the parent may measure each child once with 370 * unspecified dimensions to find out how big they want to be, then call 371 * measure() on them again with actual numbers if the sum of all the children's 372 * unconstrained sizes is too big or too small. 373 * </p> 374 * 375 * <p> 376 * The measure pass uses two classes to communicate dimensions. The 377 * {@link MeasureSpec} class is used by views to tell their parents how they 378 * want to be measured and positioned. The base LayoutParams class just 379 * describes how big the view wants to be for both width and height. For each 380 * dimension, it can specify one of: 381 * <ul> 382 * <li> an exact number 383 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 384 * (minus padding) 385 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 386 * enclose its content (plus padding). 387 * </ul> 388 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 389 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 390 * an X and Y value. 391 * </p> 392 * 393 * <p> 394 * MeasureSpecs are used to push requirements down the tree from parent to 395 * child. A MeasureSpec can be in one of three modes: 396 * <ul> 397 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 398 * of a child view. For example, a LinearLayout may call measure() on its child 399 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 400 * tall the child view wants to be given a width of 240 pixels. 401 * <li>EXACTLY: This is used by the parent to impose an exact size on the 402 * child. The child must use this size, and guarantee that all of its 403 * descendants will fit within this size. 404 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 405 * child. The child must gurantee that it and all of its descendants will fit 406 * within this size. 407 * </ul> 408 * </p> 409 * 410 * <p> 411 * To intiate a layout, call {@link #requestLayout}. This method is typically 412 * called by a view on itself when it believes that is can no longer fit within 413 * its current bounds. 414 * </p> 415 * 416 * <a name="Drawing"></a> 417 * <h3>Drawing</h3> 418 * <p> 419 * Drawing is handled by walking the tree and rendering each view that 420 * intersects the the invalid region. Because the tree is traversed in-order, 421 * this means that parents will draw before (i.e., behind) their children, with 422 * siblings drawn in the order they appear in the tree. 423 * If you set a background drawable for a View, then the View will draw it for you 424 * before calling back to its <code>onDraw()</code> method. 425 * </p> 426 * 427 * <p> 428 * Note that the framework will not draw views that are not in the invalid region. 429 * </p> 430 * 431 * <p> 432 * To force a view to draw, call {@link #invalidate()}. 433 * </p> 434 * 435 * <a name="EventHandlingThreading"></a> 436 * <h3>Event Handling and Threading</h3> 437 * <p> 438 * The basic cycle of a view is as follows: 439 * <ol> 440 * <li>An event comes in and is dispatched to the appropriate view. The view 441 * handles the event and notifies any listeners.</li> 442 * <li>If in the course of processing the event, the view's bounds may need 443 * to be changed, the view will call {@link #requestLayout()}.</li> 444 * <li>Similarly, if in the course of processing the event the view's appearance 445 * may need to be changed, the view will call {@link #invalidate()}.</li> 446 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 447 * the framework will take care of measuring, laying out, and drawing the tree 448 * as appropriate.</li> 449 * </ol> 450 * </p> 451 * 452 * <p><em>Note: The entire view tree is single threaded. You must always be on 453 * the UI thread when calling any method on any view.</em> 454 * If you are doing work on other threads and want to update the state of a view 455 * from that thread, you should use a {@link Handler}. 456 * </p> 457 * 458 * <a name="FocusHandling"></a> 459 * <h3>Focus Handling</h3> 460 * <p> 461 * The framework will handle routine focus movement in response to user input. 462 * This includes changing the focus as views are removed or hidden, or as new 463 * views become available. Views indicate their willingness to take focus 464 * through the {@link #isFocusable} method. To change whether a view can take 465 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 466 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 467 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 468 * </p> 469 * <p> 470 * Focus movement is based on an algorithm which finds the nearest neighbor in a 471 * given direction. In rare cases, the default algorithm may not match the 472 * intended behavior of the developer. In these situations, you can provide 473 * explicit overrides by using these XML attributes in the layout file: 474 * <pre> 475 * nextFocusDown 476 * nextFocusLeft 477 * nextFocusRight 478 * nextFocusUp 479 * </pre> 480 * </p> 481 * 482 * 483 * <p> 484 * To get a particular view to take focus, call {@link #requestFocus()}. 485 * </p> 486 * 487 * <a name="TouchMode"></a> 488 * <h3>Touch Mode</h3> 489 * <p> 490 * When a user is navigating a user interface via directional keys such as a D-pad, it is 491 * necessary to give focus to actionable items such as buttons so the user can see 492 * what will take input. If the device has touch capabilities, however, and the user 493 * begins interacting with the interface by touching it, it is no longer necessary to 494 * always highlight, or give focus to, a particular view. This motivates a mode 495 * for interaction named 'touch mode'. 496 * </p> 497 * <p> 498 * For a touch capable device, once the user touches the screen, the device 499 * will enter touch mode. From this point onward, only views for which 500 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 501 * Other views that are touchable, like buttons, will not take focus when touched; they will 502 * only fire the on click listeners. 503 * </p> 504 * <p> 505 * Any time a user hits a directional key, such as a D-pad direction, the view device will 506 * exit touch mode, and find a view to take focus, so that the user may resume interacting 507 * with the user interface without touching the screen again. 508 * </p> 509 * <p> 510 * The touch mode state is maintained across {@link android.app.Activity}s. Call 511 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 512 * </p> 513 * 514 * <a name="Scrolling"></a> 515 * <h3>Scrolling</h3> 516 * <p> 517 * The framework provides basic support for views that wish to internally 518 * scroll their content. This includes keeping track of the X and Y scroll 519 * offset as well as mechanisms for drawing scrollbars. See 520 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 521 * {@link #awakenScrollBars()} for more details. 522 * </p> 523 * 524 * <a name="Tags"></a> 525 * <h3>Tags</h3> 526 * <p> 527 * Unlike IDs, tags are not used to identify views. Tags are essentially an 528 * extra piece of information that can be associated with a view. They are most 529 * often used as a convenience to store data related to views in the views 530 * themselves rather than by putting them in a separate structure. 531 * </p> 532 * 533 * <a name="Animation"></a> 534 * <h3>Animation</h3> 535 * <p> 536 * You can attach an {@link Animation} object to a view using 537 * {@link #setAnimation(Animation)} or 538 * {@link #startAnimation(Animation)}. The animation can alter the scale, 539 * rotation, translation and alpha of a view over time. If the animation is 540 * attached to a view that has children, the animation will affect the entire 541 * subtree rooted by that node. When an animation is started, the framework will 542 * take care of redrawing the appropriate views until the animation completes. 543 * </p> 544 * 545 * <a name="Security"></a> 546 * <h3>Security</h3> 547 * <p> 548 * Sometimes it is essential that an application be able to verify that an action 549 * is being performed with the full knowledge and consent of the user, such as 550 * granting a permission request, making a purchase or clicking on an advertisement. 551 * Unfortunately, a malicious application could try to spoof the user into 552 * performing these actions, unaware, by concealing the intended purpose of the view. 553 * As a remedy, the framework offers a touch filtering mechanism that can be used to 554 * improve the security of views that provide access to sensitive functionality. 555 * </p><p> 556 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured} or set the 557 * andoird:filterTouchesWhenObscured attribute to true. When enabled, the framework 558 * will discard touches that are received whenever the view's window is obscured by 559 * another visible window. As a result, the view will not receive touches whenever a 560 * toast, dialog or other window appears above the view's window. 561 * </p><p> 562 * For more fine-grained control over security, consider overriding the 563 * {@link #onFilterTouchEventForSecurity} method to implement your own security policy. 564 * See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 565 * </p> 566 * 567 * @attr ref android.R.styleable#View_background 568 * @attr ref android.R.styleable#View_clickable 569 * @attr ref android.R.styleable#View_contentDescription 570 * @attr ref android.R.styleable#View_drawingCacheQuality 571 * @attr ref android.R.styleable#View_duplicateParentState 572 * @attr ref android.R.styleable#View_id 573 * @attr ref android.R.styleable#View_fadingEdge 574 * @attr ref android.R.styleable#View_fadingEdgeLength 575 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 576 * @attr ref android.R.styleable#View_fitsSystemWindows 577 * @attr ref android.R.styleable#View_isScrollContainer 578 * @attr ref android.R.styleable#View_focusable 579 * @attr ref android.R.styleable#View_focusableInTouchMode 580 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 581 * @attr ref android.R.styleable#View_keepScreenOn 582 * @attr ref android.R.styleable#View_longClickable 583 * @attr ref android.R.styleable#View_minHeight 584 * @attr ref android.R.styleable#View_minWidth 585 * @attr ref android.R.styleable#View_nextFocusDown 586 * @attr ref android.R.styleable#View_nextFocusLeft 587 * @attr ref android.R.styleable#View_nextFocusRight 588 * @attr ref android.R.styleable#View_nextFocusUp 589 * @attr ref android.R.styleable#View_onClick 590 * @attr ref android.R.styleable#View_padding 591 * @attr ref android.R.styleable#View_paddingBottom 592 * @attr ref android.R.styleable#View_paddingLeft 593 * @attr ref android.R.styleable#View_paddingRight 594 * @attr ref android.R.styleable#View_paddingTop 595 * @attr ref android.R.styleable#View_saveEnabled 596 * @attr ref android.R.styleable#View_scrollX 597 * @attr ref android.R.styleable#View_scrollY 598 * @attr ref android.R.styleable#View_scrollbarSize 599 * @attr ref android.R.styleable#View_scrollbarStyle 600 * @attr ref android.R.styleable#View_scrollbars 601 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 602 * @attr ref android.R.styleable#View_scrollbarFadeDuration 603 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 604 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 605 * @attr ref android.R.styleable#View_scrollbarThumbVertical 606 * @attr ref android.R.styleable#View_scrollbarTrackVertical 607 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 608 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 609 * @attr ref android.R.styleable#View_soundEffectsEnabled 610 * @attr ref android.R.styleable#View_tag 611 * @attr ref android.R.styleable#View_visibility 612 * 613 * @see android.view.ViewGroup 614 */ 615 public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { 616 private static final boolean DBG = false; 617 618 /** 619 * The logging tag used by this class with android.util.Log. 620 */ 621 protected static final String VIEW_LOG_TAG = "View"; 622 623 /** 624 * Used to mark a View that has no ID. 625 */ 626 public static final int NO_ID = -1; 627 628 /** 629 * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when 630 * calling setFlags. 631 */ 632 private static final int NOT_FOCUSABLE = 0x00000000; 633 634 /** 635 * This view wants keystrokes. Use with TAKES_FOCUS_MASK when calling 636 * setFlags. 637 */ 638 private static final int FOCUSABLE = 0x00000001; 639 640 /** 641 * Mask for use with setFlags indicating bits used for focus. 642 */ 643 private static final int FOCUSABLE_MASK = 0x00000001; 644 645 /** 646 * This view will adjust its padding to fit sytem windows (e.g. status bar) 647 */ 648 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 649 650 /** 651 * This view is visible. Use with {@link #setVisibility}. 652 */ 653 public static final int VISIBLE = 0x00000000; 654 655 /** 656 * This view is invisible, but it still takes up space for layout purposes. 657 * Use with {@link #setVisibility}. 658 */ 659 public static final int INVISIBLE = 0x00000004; 660 661 /** 662 * This view is invisible, and it doesn't take any space for layout 663 * purposes. Use with {@link #setVisibility}. 664 */ 665 public static final int GONE = 0x00000008; 666 667 /** 668 * Mask for use with setFlags indicating bits used for visibility. 669 * {@hide} 670 */ 671 static final int VISIBILITY_MASK = 0x0000000C; 672 673 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 674 675 /** 676 * This view is enabled. Intrepretation varies by subclass. 677 * Use with ENABLED_MASK when calling setFlags. 678 * {@hide} 679 */ 680 static final int ENABLED = 0x00000000; 681 682 /** 683 * This view is disabled. Intrepretation varies by subclass. 684 * Use with ENABLED_MASK when calling setFlags. 685 * {@hide} 686 */ 687 static final int DISABLED = 0x00000020; 688 689 /** 690 * Mask for use with setFlags indicating bits used for indicating whether 691 * this view is enabled 692 * {@hide} 693 */ 694 static final int ENABLED_MASK = 0x00000020; 695 696 /** 697 * This view won't draw. {@link #onDraw} won't be called and further 698 * optimizations 699 * will be performed. It is okay to have this flag set and a background. 700 * Use with DRAW_MASK when calling setFlags. 701 * {@hide} 702 */ 703 static final int WILL_NOT_DRAW = 0x00000080; 704 705 /** 706 * Mask for use with setFlags indicating bits used for indicating whether 707 * this view is will draw 708 * {@hide} 709 */ 710 static final int DRAW_MASK = 0x00000080; 711 712 /** 713 * <p>This view doesn't show scrollbars.</p> 714 * {@hide} 715 */ 716 static final int SCROLLBARS_NONE = 0x00000000; 717 718 /** 719 * <p>This view shows horizontal scrollbars.</p> 720 * {@hide} 721 */ 722 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 723 724 /** 725 * <p>This view shows vertical scrollbars.</p> 726 * {@hide} 727 */ 728 static final int SCROLLBARS_VERTICAL = 0x00000200; 729 730 /** 731 * <p>Mask for use with setFlags indicating bits used for indicating which 732 * scrollbars are enabled.</p> 733 * {@hide} 734 */ 735 static final int SCROLLBARS_MASK = 0x00000300; 736 737 /** 738 * Indicates that the view should filter touches when its window is obscured. 739 * Refer to the class comments for more information about this security feature. 740 * {@hide} 741 */ 742 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 743 744 // note flag value 0x00000800 is now available for next flags... 745 746 /** 747 * <p>This view doesn't show fading edges.</p> 748 * {@hide} 749 */ 750 static final int FADING_EDGE_NONE = 0x00000000; 751 752 /** 753 * <p>This view shows horizontal fading edges.</p> 754 * {@hide} 755 */ 756 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 757 758 /** 759 * <p>This view shows vertical fading edges.</p> 760 * {@hide} 761 */ 762 static final int FADING_EDGE_VERTICAL = 0x00002000; 763 764 /** 765 * <p>Mask for use with setFlags indicating bits used for indicating which 766 * fading edges are enabled.</p> 767 * {@hide} 768 */ 769 static final int FADING_EDGE_MASK = 0x00003000; 770 771 /** 772 * <p>Indicates this view can be clicked. When clickable, a View reacts 773 * to clicks by notifying the OnClickListener.<p> 774 * {@hide} 775 */ 776 static final int CLICKABLE = 0x00004000; 777 778 /** 779 * <p>Indicates this view is caching its drawing into a bitmap.</p> 780 * {@hide} 781 */ 782 static final int DRAWING_CACHE_ENABLED = 0x00008000; 783 784 /** 785 * <p>Indicates that no icicle should be saved for this view.<p> 786 * {@hide} 787 */ 788 static final int SAVE_DISABLED = 0x000010000; 789 790 /** 791 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 792 * property.</p> 793 * {@hide} 794 */ 795 static final int SAVE_DISABLED_MASK = 0x000010000; 796 797 /** 798 * <p>Indicates that no drawing cache should ever be created for this view.<p> 799 * {@hide} 800 */ 801 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 802 803 /** 804 * <p>Indicates this view can take / keep focus when int touch mode.</p> 805 * {@hide} 806 */ 807 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 808 809 /** 810 * <p>Enables low quality mode for the drawing cache.</p> 811 */ 812 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 813 814 /** 815 * <p>Enables high quality mode for the drawing cache.</p> 816 */ 817 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 818 819 /** 820 * <p>Enables automatic quality mode for the drawing cache.</p> 821 */ 822 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 823 824 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 825 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 826 }; 827 828 /** 829 * <p>Mask for use with setFlags indicating bits used for the cache 830 * quality property.</p> 831 * {@hide} 832 */ 833 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 834 835 /** 836 * <p> 837 * Indicates this view can be long clicked. When long clickable, a View 838 * reacts to long clicks by notifying the OnLongClickListener or showing a 839 * context menu. 840 * </p> 841 * {@hide} 842 */ 843 static final int LONG_CLICKABLE = 0x00200000; 844 845 /** 846 * <p>Indicates that this view gets its drawable states from its direct parent 847 * and ignores its original internal states.</p> 848 * 849 * @hide 850 */ 851 static final int DUPLICATE_PARENT_STATE = 0x00400000; 852 853 /** 854 * The scrollbar style to display the scrollbars inside the content area, 855 * without increasing the padding. The scrollbars will be overlaid with 856 * translucency on the view's content. 857 */ 858 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 859 860 /** 861 * The scrollbar style to display the scrollbars inside the padded area, 862 * increasing the padding of the view. The scrollbars will not overlap the 863 * content area of the view. 864 */ 865 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 866 867 /** 868 * The scrollbar style to display the scrollbars at the edge of the view, 869 * without increasing the padding. The scrollbars will be overlaid with 870 * translucency. 871 */ 872 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 873 874 /** 875 * The scrollbar style to display the scrollbars at the edge of the view, 876 * increasing the padding of the view. The scrollbars will only overlap the 877 * background, if any. 878 */ 879 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 880 881 /** 882 * Mask to check if the scrollbar style is overlay or inset. 883 * {@hide} 884 */ 885 static final int SCROLLBARS_INSET_MASK = 0x01000000; 886 887 /** 888 * Mask to check if the scrollbar style is inside or outside. 889 * {@hide} 890 */ 891 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 892 893 /** 894 * Mask for scrollbar style. 895 * {@hide} 896 */ 897 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 898 899 /** 900 * View flag indicating that the screen should remain on while the 901 * window containing this view is visible to the user. This effectively 902 * takes care of automatically setting the WindowManager's 903 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 904 */ 905 public static final int KEEP_SCREEN_ON = 0x04000000; 906 907 /** 908 * View flag indicating whether this view should have sound effects enabled 909 * for events such as clicking and touching. 910 */ 911 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 912 913 /** 914 * View flag indicating whether this view should have haptic feedback 915 * enabled for events such as long presses. 916 */ 917 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 918 919 /** 920 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 921 * should add all focusable Views regardless if they are focusable in touch mode. 922 */ 923 public static final int FOCUSABLES_ALL = 0x00000000; 924 925 /** 926 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 927 * should add only Views focusable in touch mode. 928 */ 929 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 930 931 /** 932 * Use with {@link #focusSearch}. Move focus to the previous selectable 933 * item. 934 */ 935 public static final int FOCUS_BACKWARD = 0x00000001; 936 937 /** 938 * Use with {@link #focusSearch}. Move focus to the next selectable 939 * item. 940 */ 941 public static final int FOCUS_FORWARD = 0x00000002; 942 943 /** 944 * Use with {@link #focusSearch}. Move focus to the left. 945 */ 946 public static final int FOCUS_LEFT = 0x00000011; 947 948 /** 949 * Use with {@link #focusSearch}. Move focus up. 950 */ 951 public static final int FOCUS_UP = 0x00000021; 952 953 /** 954 * Use with {@link #focusSearch}. Move focus to the right. 955 */ 956 public static final int FOCUS_RIGHT = 0x00000042; 957 958 /** 959 * Use with {@link #focusSearch}. Move focus down. 960 */ 961 public static final int FOCUS_DOWN = 0x00000082; 962 963 /** 964 * Base View state sets 965 */ 966 // Singles 967 /** 968 * Indicates the view has no states set. States are used with 969 * {@link android.graphics.drawable.Drawable} to change the drawing of the 970 * view depending on its state. 971 * 972 * @see android.graphics.drawable.Drawable 973 * @see #getDrawableState() 974 */ 975 protected static final int[] EMPTY_STATE_SET = {}; 976 /** 977 * Indicates the view is enabled. States are used with 978 * {@link android.graphics.drawable.Drawable} to change the drawing of the 979 * view depending on its state. 980 * 981 * @see android.graphics.drawable.Drawable 982 * @see #getDrawableState() 983 */ 984 protected static final int[] ENABLED_STATE_SET = {R.attr.state_enabled}; 985 /** 986 * Indicates the view is focused. States are used with 987 * {@link android.graphics.drawable.Drawable} to change the drawing of the 988 * view depending on its state. 989 * 990 * @see android.graphics.drawable.Drawable 991 * @see #getDrawableState() 992 */ 993 protected static final int[] FOCUSED_STATE_SET = {R.attr.state_focused}; 994 /** 995 * Indicates the view is selected. States are used with 996 * {@link android.graphics.drawable.Drawable} to change the drawing of the 997 * view depending on its state. 998 * 999 * @see android.graphics.drawable.Drawable 1000 * @see #getDrawableState() 1001 */ 1002 protected static final int[] SELECTED_STATE_SET = {R.attr.state_selected}; 1003 /** 1004 * Indicates the view is pressed. States are used with 1005 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1006 * view depending on its state. 1007 * 1008 * @see android.graphics.drawable.Drawable 1009 * @see #getDrawableState() 1010 * @hide 1011 */ 1012 protected static final int[] PRESSED_STATE_SET = {R.attr.state_pressed}; 1013 /** 1014 * Indicates the view's window has focus. States are used with 1015 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1016 * view depending on its state. 1017 * 1018 * @see android.graphics.drawable.Drawable 1019 * @see #getDrawableState() 1020 */ 1021 protected static final int[] WINDOW_FOCUSED_STATE_SET = 1022 {R.attr.state_window_focused}; 1023 // Doubles 1024 /** 1025 * Indicates the view is enabled and has the focus. 1026 * 1027 * @see #ENABLED_STATE_SET 1028 * @see #FOCUSED_STATE_SET 1029 */ 1030 protected static final int[] ENABLED_FOCUSED_STATE_SET = 1031 stateSetUnion(ENABLED_STATE_SET, FOCUSED_STATE_SET); 1032 /** 1033 * Indicates the view is enabled and selected. 1034 * 1035 * @see #ENABLED_STATE_SET 1036 * @see #SELECTED_STATE_SET 1037 */ 1038 protected static final int[] ENABLED_SELECTED_STATE_SET = 1039 stateSetUnion(ENABLED_STATE_SET, SELECTED_STATE_SET); 1040 /** 1041 * Indicates the view is enabled and that its window has focus. 1042 * 1043 * @see #ENABLED_STATE_SET 1044 * @see #WINDOW_FOCUSED_STATE_SET 1045 */ 1046 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET = 1047 stateSetUnion(ENABLED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1048 /** 1049 * Indicates the view is focused and selected. 1050 * 1051 * @see #FOCUSED_STATE_SET 1052 * @see #SELECTED_STATE_SET 1053 */ 1054 protected static final int[] FOCUSED_SELECTED_STATE_SET = 1055 stateSetUnion(FOCUSED_STATE_SET, SELECTED_STATE_SET); 1056 /** 1057 * Indicates the view has the focus and that its window has the focus. 1058 * 1059 * @see #FOCUSED_STATE_SET 1060 * @see #WINDOW_FOCUSED_STATE_SET 1061 */ 1062 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET = 1063 stateSetUnion(FOCUSED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1064 /** 1065 * Indicates the view is selected and that its window has the focus. 1066 * 1067 * @see #SELECTED_STATE_SET 1068 * @see #WINDOW_FOCUSED_STATE_SET 1069 */ 1070 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET = 1071 stateSetUnion(SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1072 // Triples 1073 /** 1074 * Indicates the view is enabled, focused and selected. 1075 * 1076 * @see #ENABLED_STATE_SET 1077 * @see #FOCUSED_STATE_SET 1078 * @see #SELECTED_STATE_SET 1079 */ 1080 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET = 1081 stateSetUnion(ENABLED_FOCUSED_STATE_SET, SELECTED_STATE_SET); 1082 /** 1083 * Indicates the view is enabled, focused and its window has the focus. 1084 * 1085 * @see #ENABLED_STATE_SET 1086 * @see #FOCUSED_STATE_SET 1087 * @see #WINDOW_FOCUSED_STATE_SET 1088 */ 1089 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = 1090 stateSetUnion(ENABLED_FOCUSED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1091 /** 1092 * Indicates the view is enabled, selected and its window has the focus. 1093 * 1094 * @see #ENABLED_STATE_SET 1095 * @see #SELECTED_STATE_SET 1096 * @see #WINDOW_FOCUSED_STATE_SET 1097 */ 1098 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = 1099 stateSetUnion(ENABLED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1100 /** 1101 * Indicates the view is focused, selected and its window has the focus. 1102 * 1103 * @see #FOCUSED_STATE_SET 1104 * @see #SELECTED_STATE_SET 1105 * @see #WINDOW_FOCUSED_STATE_SET 1106 */ 1107 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = 1108 stateSetUnion(FOCUSED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1109 /** 1110 * Indicates the view is enabled, focused, selected and its window 1111 * has the focus. 1112 * 1113 * @see #ENABLED_STATE_SET 1114 * @see #FOCUSED_STATE_SET 1115 * @see #SELECTED_STATE_SET 1116 * @see #WINDOW_FOCUSED_STATE_SET 1117 */ 1118 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = 1119 stateSetUnion(ENABLED_FOCUSED_SELECTED_STATE_SET, 1120 WINDOW_FOCUSED_STATE_SET); 1121 1122 /** 1123 * Indicates the view is pressed and its window has the focus. 1124 * 1125 * @see #PRESSED_STATE_SET 1126 * @see #WINDOW_FOCUSED_STATE_SET 1127 */ 1128 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET = 1129 stateSetUnion(PRESSED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1130 1131 /** 1132 * Indicates the view is pressed and selected. 1133 * 1134 * @see #PRESSED_STATE_SET 1135 * @see #SELECTED_STATE_SET 1136 */ 1137 protected static final int[] PRESSED_SELECTED_STATE_SET = 1138 stateSetUnion(PRESSED_STATE_SET, SELECTED_STATE_SET); 1139 1140 /** 1141 * Indicates the view is pressed, selected and its window has the focus. 1142 * 1143 * @see #PRESSED_STATE_SET 1144 * @see #SELECTED_STATE_SET 1145 * @see #WINDOW_FOCUSED_STATE_SET 1146 */ 1147 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = 1148 stateSetUnion(PRESSED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1149 1150 /** 1151 * Indicates the view is pressed and focused. 1152 * 1153 * @see #PRESSED_STATE_SET 1154 * @see #FOCUSED_STATE_SET 1155 */ 1156 protected static final int[] PRESSED_FOCUSED_STATE_SET = 1157 stateSetUnion(PRESSED_STATE_SET, FOCUSED_STATE_SET); 1158 1159 /** 1160 * Indicates the view is pressed, focused and its window has the focus. 1161 * 1162 * @see #PRESSED_STATE_SET 1163 * @see #FOCUSED_STATE_SET 1164 * @see #WINDOW_FOCUSED_STATE_SET 1165 */ 1166 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = 1167 stateSetUnion(PRESSED_FOCUSED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1168 1169 /** 1170 * Indicates the view is pressed, focused and selected. 1171 * 1172 * @see #PRESSED_STATE_SET 1173 * @see #SELECTED_STATE_SET 1174 * @see #FOCUSED_STATE_SET 1175 */ 1176 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET = 1177 stateSetUnion(PRESSED_FOCUSED_STATE_SET, SELECTED_STATE_SET); 1178 1179 /** 1180 * Indicates the view is pressed, focused, selected and its window has the focus. 1181 * 1182 * @see #PRESSED_STATE_SET 1183 * @see #FOCUSED_STATE_SET 1184 * @see #SELECTED_STATE_SET 1185 * @see #WINDOW_FOCUSED_STATE_SET 1186 */ 1187 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = 1188 stateSetUnion(PRESSED_FOCUSED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1189 1190 /** 1191 * Indicates the view is pressed and enabled. 1192 * 1193 * @see #PRESSED_STATE_SET 1194 * @see #ENABLED_STATE_SET 1195 */ 1196 protected static final int[] PRESSED_ENABLED_STATE_SET = 1197 stateSetUnion(PRESSED_STATE_SET, ENABLED_STATE_SET); 1198 1199 /** 1200 * Indicates the view is pressed, enabled and its window has the focus. 1201 * 1202 * @see #PRESSED_STATE_SET 1203 * @see #ENABLED_STATE_SET 1204 * @see #WINDOW_FOCUSED_STATE_SET 1205 */ 1206 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = 1207 stateSetUnion(PRESSED_ENABLED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1208 1209 /** 1210 * Indicates the view is pressed, enabled and selected. 1211 * 1212 * @see #PRESSED_STATE_SET 1213 * @see #ENABLED_STATE_SET 1214 * @see #SELECTED_STATE_SET 1215 */ 1216 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET = 1217 stateSetUnion(PRESSED_ENABLED_STATE_SET, SELECTED_STATE_SET); 1218 1219 /** 1220 * Indicates the view is pressed, enabled, selected and its window has the 1221 * focus. 1222 * 1223 * @see #PRESSED_STATE_SET 1224 * @see #ENABLED_STATE_SET 1225 * @see #SELECTED_STATE_SET 1226 * @see #WINDOW_FOCUSED_STATE_SET 1227 */ 1228 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = 1229 stateSetUnion(PRESSED_ENABLED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1230 1231 /** 1232 * Indicates the view is pressed, enabled and focused. 1233 * 1234 * @see #PRESSED_STATE_SET 1235 * @see #ENABLED_STATE_SET 1236 * @see #FOCUSED_STATE_SET 1237 */ 1238 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET = 1239 stateSetUnion(PRESSED_ENABLED_STATE_SET, FOCUSED_STATE_SET); 1240 1241 /** 1242 * Indicates the view is pressed, enabled, focused and its window has the 1243 * focus. 1244 * 1245 * @see #PRESSED_STATE_SET 1246 * @see #ENABLED_STATE_SET 1247 * @see #FOCUSED_STATE_SET 1248 * @see #WINDOW_FOCUSED_STATE_SET 1249 */ 1250 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = 1251 stateSetUnion(PRESSED_ENABLED_FOCUSED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1252 1253 /** 1254 * Indicates the view is pressed, enabled, focused and selected. 1255 * 1256 * @see #PRESSED_STATE_SET 1257 * @see #ENABLED_STATE_SET 1258 * @see #SELECTED_STATE_SET 1259 * @see #FOCUSED_STATE_SET 1260 */ 1261 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = 1262 stateSetUnion(PRESSED_ENABLED_FOCUSED_STATE_SET, SELECTED_STATE_SET); 1263 1264 /** 1265 * Indicates the view is pressed, enabled, focused, selected and its window 1266 * has the focus. 1267 * 1268 * @see #PRESSED_STATE_SET 1269 * @see #ENABLED_STATE_SET 1270 * @see #SELECTED_STATE_SET 1271 * @see #FOCUSED_STATE_SET 1272 * @see #WINDOW_FOCUSED_STATE_SET 1273 */ 1274 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = 1275 stateSetUnion(PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET); 1276 1277 /** 1278 * The order here is very important to {@link #getDrawableState()} 1279 */ 1280 private static final int[][] VIEW_STATE_SETS = { 1281 EMPTY_STATE_SET, // 0 0 0 0 0 1282 WINDOW_FOCUSED_STATE_SET, // 0 0 0 0 1 1283 SELECTED_STATE_SET, // 0 0 0 1 0 1284 SELECTED_WINDOW_FOCUSED_STATE_SET, // 0 0 0 1 1 1285 FOCUSED_STATE_SET, // 0 0 1 0 0 1286 FOCUSED_WINDOW_FOCUSED_STATE_SET, // 0 0 1 0 1 1287 FOCUSED_SELECTED_STATE_SET, // 0 0 1 1 0 1288 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 0 0 1 1 1 1289 ENABLED_STATE_SET, // 0 1 0 0 0 1290 ENABLED_WINDOW_FOCUSED_STATE_SET, // 0 1 0 0 1 1291 ENABLED_SELECTED_STATE_SET, // 0 1 0 1 0 1292 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 0 1 0 1 1 1293 ENABLED_FOCUSED_STATE_SET, // 0 1 1 0 0 1294 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET, // 0 1 1 0 1 1295 ENABLED_FOCUSED_SELECTED_STATE_SET, // 0 1 1 1 0 1296 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 0 1 1 1 1 1297 PRESSED_STATE_SET, // 1 0 0 0 0 1298 PRESSED_WINDOW_FOCUSED_STATE_SET, // 1 0 0 0 1 1299 PRESSED_SELECTED_STATE_SET, // 1 0 0 1 0 1300 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 1 0 0 1 1 1301 PRESSED_FOCUSED_STATE_SET, // 1 0 1 0 0 1302 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET, // 1 0 1 0 1 1303 PRESSED_FOCUSED_SELECTED_STATE_SET, // 1 0 1 1 0 1304 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 1 0 1 1 1 1305 PRESSED_ENABLED_STATE_SET, // 1 1 0 0 0 1306 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET, // 1 1 0 0 1 1307 PRESSED_ENABLED_SELECTED_STATE_SET, // 1 1 0 1 0 1308 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 1 1 0 1 1 1309 PRESSED_ENABLED_FOCUSED_STATE_SET, // 1 1 1 0 0 1310 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET, // 1 1 1 0 1 1311 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET, // 1 1 1 1 0 1312 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 1 1 1 1 1 1313 }; 1314 1315 /** 1316 * Used by views that contain lists of items. This state indicates that 1317 * the view is showing the last item. 1318 * @hide 1319 */ 1320 protected static final int[] LAST_STATE_SET = {R.attr.state_last}; 1321 /** 1322 * Used by views that contain lists of items. This state indicates that 1323 * the view is showing the first item. 1324 * @hide 1325 */ 1326 protected static final int[] FIRST_STATE_SET = {R.attr.state_first}; 1327 /** 1328 * Used by views that contain lists of items. This state indicates that 1329 * the view is showing the middle item. 1330 * @hide 1331 */ 1332 protected static final int[] MIDDLE_STATE_SET = {R.attr.state_middle}; 1333 /** 1334 * Used by views that contain lists of items. This state indicates that 1335 * the view is showing only one item. 1336 * @hide 1337 */ 1338 protected static final int[] SINGLE_STATE_SET = {R.attr.state_single}; 1339 /** 1340 * Used by views that contain lists of items. This state indicates that 1341 * the view is pressed and showing the last item. 1342 * @hide 1343 */ 1344 protected static final int[] PRESSED_LAST_STATE_SET = {R.attr.state_last, R.attr.state_pressed}; 1345 /** 1346 * Used by views that contain lists of items. This state indicates that 1347 * the view is pressed and showing the first item. 1348 * @hide 1349 */ 1350 protected static final int[] PRESSED_FIRST_STATE_SET = {R.attr.state_first, R.attr.state_pressed}; 1351 /** 1352 * Used by views that contain lists of items. This state indicates that 1353 * the view is pressed and showing the middle item. 1354 * @hide 1355 */ 1356 protected static final int[] PRESSED_MIDDLE_STATE_SET = {R.attr.state_middle, R.attr.state_pressed}; 1357 /** 1358 * Used by views that contain lists of items. This state indicates that 1359 * the view is pressed and showing only one item. 1360 * @hide 1361 */ 1362 protected static final int[] PRESSED_SINGLE_STATE_SET = {R.attr.state_single, R.attr.state_pressed}; 1363 1364 /** 1365 * Temporary Rect currently for use in setBackground(). This will probably 1366 * be extended in the future to hold our own class with more than just 1367 * a Rect. :) 1368 */ 1369 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 1370 1371 /** 1372 * Map used to store views' tags. 1373 */ 1374 private static WeakHashMap<View, SparseArray<Object>> sTags; 1375 1376 /** 1377 * Lock used to access sTags. 1378 */ 1379 private static final Object sTagsLock = new Object(); 1380 1381 /** 1382 * The animation currently associated with this view. 1383 * @hide 1384 */ 1385 protected Animation mCurrentAnimation = null; 1386 1387 /** 1388 * Width as measured during measure pass. 1389 * {@hide} 1390 */ 1391 @ViewDebug.ExportedProperty(category = "measurement") 1392 protected int mMeasuredWidth; 1393 1394 /** 1395 * Height as measured during measure pass. 1396 * {@hide} 1397 */ 1398 @ViewDebug.ExportedProperty(category = "measurement") 1399 protected int mMeasuredHeight; 1400 1401 /** 1402 * The view's identifier. 1403 * {@hide} 1404 * 1405 * @see #setId(int) 1406 * @see #getId() 1407 */ 1408 @ViewDebug.ExportedProperty(resolveId = true) 1409 int mID = NO_ID; 1410 1411 /** 1412 * The view's tag. 1413 * {@hide} 1414 * 1415 * @see #setTag(Object) 1416 * @see #getTag() 1417 */ 1418 protected Object mTag; 1419 1420 // for mPrivateFlags: 1421 /** {@hide} */ 1422 static final int WANTS_FOCUS = 0x00000001; 1423 /** {@hide} */ 1424 static final int FOCUSED = 0x00000002; 1425 /** {@hide} */ 1426 static final int SELECTED = 0x00000004; 1427 /** {@hide} */ 1428 static final int IS_ROOT_NAMESPACE = 0x00000008; 1429 /** {@hide} */ 1430 static final int HAS_BOUNDS = 0x00000010; 1431 /** {@hide} */ 1432 static final int DRAWN = 0x00000020; 1433 /** 1434 * When this flag is set, this view is running an animation on behalf of its 1435 * children and should therefore not cancel invalidate requests, even if they 1436 * lie outside of this view's bounds. 1437 * 1438 * {@hide} 1439 */ 1440 static final int DRAW_ANIMATION = 0x00000040; 1441 /** {@hide} */ 1442 static final int SKIP_DRAW = 0x00000080; 1443 /** {@hide} */ 1444 static final int ONLY_DRAWS_BACKGROUND = 0x00000100; 1445 /** {@hide} */ 1446 static final int REQUEST_TRANSPARENT_REGIONS = 0x00000200; 1447 /** {@hide} */ 1448 static final int DRAWABLE_STATE_DIRTY = 0x00000400; 1449 /** {@hide} */ 1450 static final int MEASURED_DIMENSION_SET = 0x00000800; 1451 /** {@hide} */ 1452 static final int FORCE_LAYOUT = 0x00001000; 1453 /** {@hide} */ 1454 static final int LAYOUT_REQUIRED = 0x00002000; 1455 1456 private static final int PRESSED = 0x00004000; 1457 1458 /** {@hide} */ 1459 static final int DRAWING_CACHE_VALID = 0x00008000; 1460 /** 1461 * Flag used to indicate that this view should be drawn once more (and only once 1462 * more) after its animation has completed. 1463 * {@hide} 1464 */ 1465 static final int ANIMATION_STARTED = 0x00010000; 1466 1467 private static final int SAVE_STATE_CALLED = 0x00020000; 1468 1469 /** 1470 * Indicates that the View returned true when onSetAlpha() was called and that 1471 * the alpha must be restored. 1472 * {@hide} 1473 */ 1474 static final int ALPHA_SET = 0x00040000; 1475 1476 /** 1477 * Set by {@link #setScrollContainer(boolean)}. 1478 */ 1479 static final int SCROLL_CONTAINER = 0x00080000; 1480 1481 /** 1482 * Set by {@link #setScrollContainer(boolean)}. 1483 */ 1484 static final int SCROLL_CONTAINER_ADDED = 0x00100000; 1485 1486 /** 1487 * View flag indicating whether this view was invalidated (fully or partially.) 1488 * 1489 * @hide 1490 */ 1491 static final int DIRTY = 0x00200000; 1492 1493 /** 1494 * View flag indicating whether this view was invalidated by an opaque 1495 * invalidate request. 1496 * 1497 * @hide 1498 */ 1499 static final int DIRTY_OPAQUE = 0x00400000; 1500 1501 /** 1502 * Mask for {@link #DIRTY} and {@link #DIRTY_OPAQUE}. 1503 * 1504 * @hide 1505 */ 1506 static final int DIRTY_MASK = 0x00600000; 1507 1508 /** 1509 * Indicates whether the background is opaque. 1510 * 1511 * @hide 1512 */ 1513 static final int OPAQUE_BACKGROUND = 0x00800000; 1514 1515 /** 1516 * Indicates whether the scrollbars are opaque. 1517 * 1518 * @hide 1519 */ 1520 static final int OPAQUE_SCROLLBARS = 0x01000000; 1521 1522 /** 1523 * Indicates whether the view is opaque. 1524 * 1525 * @hide 1526 */ 1527 static final int OPAQUE_MASK = 0x01800000; 1528 1529 /** 1530 * Indicates a prepressed state; 1531 * the short time between ACTION_DOWN and recognizing 1532 * a 'real' press. Prepressed is used to recognize quick taps 1533 * even when they are shorter than ViewConfiguration.getTapTimeout(). 1534 * 1535 * @hide 1536 */ 1537 private static final int PREPRESSED = 0x02000000; 1538 1539 /** 1540 * Indicates whether the view is temporarily detached. 1541 * 1542 * @hide 1543 */ 1544 static final int CANCEL_NEXT_UP_EVENT = 0x04000000; 1545 1546 /** 1547 * Indicates that we should awaken scroll bars once attached 1548 * 1549 * @hide 1550 */ 1551 private static final int AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 1552 1553 /** 1554 * Always allow a user to over-scroll this view, provided it is a 1555 * view that can scroll. 1556 * 1557 * @see #getOverScrollMode() 1558 * @see #setOverScrollMode(int) 1559 */ 1560 public static final int OVER_SCROLL_ALWAYS = 0; 1561 1562 /** 1563 * Allow a user to over-scroll this view only if the content is large 1564 * enough to meaningfully scroll, provided it is a view that can scroll. 1565 * 1566 * @see #getOverScrollMode() 1567 * @see #setOverScrollMode(int) 1568 */ 1569 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 1570 1571 /** 1572 * Never allow a user to over-scroll this view. 1573 * 1574 * @see #getOverScrollMode() 1575 * @see #setOverScrollMode(int) 1576 */ 1577 public static final int OVER_SCROLL_NEVER = 2; 1578 1579 /** 1580 * Controls the over-scroll mode for this view. 1581 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 1582 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 1583 * and {@link #OVER_SCROLL_NEVER}. 1584 */ 1585 private int mOverScrollMode; 1586 1587 /** 1588 * The parent this view is attached to. 1589 * {@hide} 1590 * 1591 * @see #getParent() 1592 */ 1593 protected ViewParent mParent; 1594 1595 /** 1596 * {@hide} 1597 */ 1598 AttachInfo mAttachInfo; 1599 1600 /** 1601 * {@hide} 1602 */ 1603 @ViewDebug.ExportedProperty(flagMapping = { 1604 @ViewDebug.FlagToString(mask = FORCE_LAYOUT, equals = FORCE_LAYOUT, 1605 name = "FORCE_LAYOUT"), 1606 @ViewDebug.FlagToString(mask = LAYOUT_REQUIRED, equals = LAYOUT_REQUIRED, 1607 name = "LAYOUT_REQUIRED"), 1608 @ViewDebug.FlagToString(mask = DRAWING_CACHE_VALID, equals = DRAWING_CACHE_VALID, 1609 name = "DRAWING_CACHE_INVALID", outputIf = false), 1610 @ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "DRAWN", outputIf = true), 1611 @ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "NOT_DRAWN", outputIf = false), 1612 @ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 1613 @ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY, name = "DIRTY") 1614 }) 1615 int mPrivateFlags; 1616 1617 /** 1618 * Count of how many windows this view has been attached to. 1619 */ 1620 int mWindowAttachCount; 1621 1622 /** 1623 * The layout parameters associated with this view and used by the parent 1624 * {@link android.view.ViewGroup} to determine how this view should be 1625 * laid out. 1626 * {@hide} 1627 */ 1628 protected ViewGroup.LayoutParams mLayoutParams; 1629 1630 /** 1631 * The view flags hold various views states. 1632 * {@hide} 1633 */ 1634 @ViewDebug.ExportedProperty 1635 int mViewFlags; 1636 1637 /** 1638 * The distance in pixels from the left edge of this view's parent 1639 * to the left edge of this view. 1640 * {@hide} 1641 */ 1642 @ViewDebug.ExportedProperty(category = "layout") 1643 protected int mLeft; 1644 /** 1645 * The distance in pixels from the left edge of this view's parent 1646 * to the right edge of this view. 1647 * {@hide} 1648 */ 1649 @ViewDebug.ExportedProperty(category = "layout") 1650 protected int mRight; 1651 /** 1652 * The distance in pixels from the top edge of this view's parent 1653 * to the top edge of this view. 1654 * {@hide} 1655 */ 1656 @ViewDebug.ExportedProperty(category = "layout") 1657 protected int mTop; 1658 /** 1659 * The distance in pixels from the top edge of this view's parent 1660 * to the bottom edge of this view. 1661 * {@hide} 1662 */ 1663 @ViewDebug.ExportedProperty(category = "layout") 1664 protected int mBottom; 1665 1666 /** 1667 * The offset, in pixels, by which the content of this view is scrolled 1668 * horizontally. 1669 * {@hide} 1670 */ 1671 @ViewDebug.ExportedProperty(category = "scrolling") 1672 protected int mScrollX; 1673 /** 1674 * The offset, in pixels, by which the content of this view is scrolled 1675 * vertically. 1676 * {@hide} 1677 */ 1678 @ViewDebug.ExportedProperty(category = "scrolling") 1679 protected int mScrollY; 1680 1681 /** 1682 * The left padding in pixels, that is the distance in pixels between the 1683 * left edge of this view and the left edge of its content. 1684 * {@hide} 1685 */ 1686 @ViewDebug.ExportedProperty(category = "padding") 1687 protected int mPaddingLeft; 1688 /** 1689 * The right padding in pixels, that is the distance in pixels between the 1690 * right edge of this view and the right edge of its content. 1691 * {@hide} 1692 */ 1693 @ViewDebug.ExportedProperty(category = "padding") 1694 protected int mPaddingRight; 1695 /** 1696 * The top padding in pixels, that is the distance in pixels between the 1697 * top edge of this view and the top edge of its content. 1698 * {@hide} 1699 */ 1700 @ViewDebug.ExportedProperty(category = "padding") 1701 protected int mPaddingTop; 1702 /** 1703 * The bottom padding in pixels, that is the distance in pixels between the 1704 * bottom edge of this view and the bottom edge of its content. 1705 * {@hide} 1706 */ 1707 @ViewDebug.ExportedProperty(category = "padding") 1708 protected int mPaddingBottom; 1709 1710 /** 1711 * Briefly describes the view and is primarily used for accessibility support. 1712 */ 1713 private CharSequence mContentDescription; 1714 1715 /** 1716 * Cache the paddingRight set by the user to append to the scrollbar's size. 1717 */ 1718 @ViewDebug.ExportedProperty(category = "padding") 1719 int mUserPaddingRight; 1720 1721 /** 1722 * Cache the paddingBottom set by the user to append to the scrollbar's size. 1723 */ 1724 @ViewDebug.ExportedProperty(category = "padding") 1725 int mUserPaddingBottom; 1726 1727 /** 1728 * @hide 1729 */ 1730 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 1731 /** 1732 * @hide 1733 */ 1734 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 1735 1736 private Resources mResources = null; 1737 1738 private Drawable mBGDrawable; 1739 1740 private int mBackgroundResource; 1741 private boolean mBackgroundSizeChanged; 1742 1743 /** 1744 * Listener used to dispatch focus change events. 1745 * This field should be made private, so it is hidden from the SDK. 1746 * {@hide} 1747 */ 1748 protected OnFocusChangeListener mOnFocusChangeListener; 1749 1750 /** 1751 * Listener used to dispatch click events. 1752 * This field should be made private, so it is hidden from the SDK. 1753 * {@hide} 1754 */ 1755 protected OnClickListener mOnClickListener; 1756 1757 /** 1758 * Listener used to dispatch long click events. 1759 * This field should be made private, so it is hidden from the SDK. 1760 * {@hide} 1761 */ 1762 protected OnLongClickListener mOnLongClickListener; 1763 1764 /** 1765 * Listener used to build the context menu. 1766 * This field should be made private, so it is hidden from the SDK. 1767 * {@hide} 1768 */ 1769 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 1770 1771 private OnKeyListener mOnKeyListener; 1772 1773 private OnTouchListener mOnTouchListener; 1774 1775 /** 1776 * The application environment this view lives in. 1777 * This field should be made private, so it is hidden from the SDK. 1778 * {@hide} 1779 */ 1780 protected Context mContext; 1781 1782 private ScrollabilityCache mScrollCache; 1783 1784 private int[] mDrawableState = null; 1785 1786 private SoftReference<Bitmap> mDrawingCache; 1787 private SoftReference<Bitmap> mUnscaledDrawingCache; 1788 1789 /** 1790 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 1791 * the user may specify which view to go to next. 1792 */ 1793 private int mNextFocusLeftId = View.NO_ID; 1794 1795 /** 1796 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 1797 * the user may specify which view to go to next. 1798 */ 1799 private int mNextFocusRightId = View.NO_ID; 1800 1801 /** 1802 * When this view has focus and the next focus is {@link #FOCUS_UP}, 1803 * the user may specify which view to go to next. 1804 */ 1805 private int mNextFocusUpId = View.NO_ID; 1806 1807 /** 1808 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 1809 * the user may specify which view to go to next. 1810 */ 1811 private int mNextFocusDownId = View.NO_ID; 1812 1813 private CheckForLongPress mPendingCheckForLongPress; 1814 private CheckForTap mPendingCheckForTap = null; 1815 private PerformClick mPerformClick; 1816 1817 private UnsetPressedState mUnsetPressedState; 1818 1819 /** 1820 * Whether the long press's action has been invoked. The tap's action is invoked on the 1821 * up event while a long press is invoked as soon as the long press duration is reached, so 1822 * a long press could be performed before the tap is checked, in which case the tap's action 1823 * should not be invoked. 1824 */ 1825 private boolean mHasPerformedLongPress; 1826 1827 /** 1828 * The minimum height of the view. We'll try our best to have the height 1829 * of this view to at least this amount. 1830 */ 1831 @ViewDebug.ExportedProperty(category = "measurement") 1832 private int mMinHeight; 1833 1834 /** 1835 * The minimum width of the view. We'll try our best to have the width 1836 * of this view to at least this amount. 1837 */ 1838 @ViewDebug.ExportedProperty(category = "measurement") 1839 private int mMinWidth; 1840 1841 /** 1842 * The delegate to handle touch events that are physically in this view 1843 * but should be handled by another view. 1844 */ 1845 private TouchDelegate mTouchDelegate = null; 1846 1847 /** 1848 * Solid color to use as a background when creating the drawing cache. Enables 1849 * the cache to use 16 bit bitmaps instead of 32 bit. 1850 */ 1851 private int mDrawingCacheBackgroundColor = 0; 1852 1853 /** 1854 * Special tree observer used when mAttachInfo is null. 1855 */ 1856 private ViewTreeObserver mFloatingTreeObserver; 1857 1858 /** 1859 * Cache the touch slop from the context that created the view. 1860 */ 1861 private int mTouchSlop; 1862 1863 // Used for debug only 1864 static long sInstanceCount = 0; 1865 1866 /** 1867 * Simple constructor to use when creating a view from code. 1868 * 1869 * @param context The Context the view is running in, through which it can 1870 * access the current theme, resources, etc. 1871 */ View(Context context)1872 public View(Context context) { 1873 mContext = context; 1874 mResources = context != null ? context.getResources() : null; 1875 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED; 1876 // Used for debug only 1877 //++sInstanceCount; 1878 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 1879 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 1880 } 1881 1882 /** 1883 * Constructor that is called when inflating a view from XML. This is called 1884 * when a view is being constructed from an XML file, supplying attributes 1885 * that were specified in the XML file. This version uses a default style of 1886 * 0, so the only attribute values applied are those in the Context's Theme 1887 * and the given AttributeSet. 1888 * 1889 * <p> 1890 * The method onFinishInflate() will be called after all children have been 1891 * added. 1892 * 1893 * @param context The Context the view is running in, through which it can 1894 * access the current theme, resources, etc. 1895 * @param attrs The attributes of the XML tag that is inflating the view. 1896 * @see #View(Context, AttributeSet, int) 1897 */ View(Context context, AttributeSet attrs)1898 public View(Context context, AttributeSet attrs) { 1899 this(context, attrs, 0); 1900 } 1901 1902 /** 1903 * Perform inflation from XML and apply a class-specific base style. This 1904 * constructor of View allows subclasses to use their own base style when 1905 * they are inflating. For example, a Button class's constructor would call 1906 * this version of the super class constructor and supply 1907 * <code>R.attr.buttonStyle</code> for <var>defStyle</var>; this allows 1908 * the theme's button style to modify all of the base view attributes (in 1909 * particular its background) as well as the Button class's attributes. 1910 * 1911 * @param context The Context the view is running in, through which it can 1912 * access the current theme, resources, etc. 1913 * @param attrs The attributes of the XML tag that is inflating the view. 1914 * @param defStyle The default style to apply to this view. If 0, no style 1915 * will be applied (beyond what is included in the theme). This may 1916 * either be an attribute resource, whose value will be retrieved 1917 * from the current theme, or an explicit style resource. 1918 * @see #View(Context, AttributeSet) 1919 */ View(Context context, AttributeSet attrs, int defStyle)1920 public View(Context context, AttributeSet attrs, int defStyle) { 1921 this(context); 1922 1923 TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View, 1924 defStyle, 0); 1925 1926 Drawable background = null; 1927 1928 int leftPadding = -1; 1929 int topPadding = -1; 1930 int rightPadding = -1; 1931 int bottomPadding = -1; 1932 1933 int padding = -1; 1934 1935 int viewFlagValues = 0; 1936 int viewFlagMasks = 0; 1937 1938 boolean setScrollContainer = false; 1939 1940 int x = 0; 1941 int y = 0; 1942 1943 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 1944 1945 int overScrollMode = mOverScrollMode; 1946 final int N = a.getIndexCount(); 1947 for (int i = 0; i < N; i++) { 1948 int attr = a.getIndex(i); 1949 switch (attr) { 1950 case com.android.internal.R.styleable.View_background: 1951 background = a.getDrawable(attr); 1952 break; 1953 case com.android.internal.R.styleable.View_padding: 1954 padding = a.getDimensionPixelSize(attr, -1); 1955 break; 1956 case com.android.internal.R.styleable.View_paddingLeft: 1957 leftPadding = a.getDimensionPixelSize(attr, -1); 1958 break; 1959 case com.android.internal.R.styleable.View_paddingTop: 1960 topPadding = a.getDimensionPixelSize(attr, -1); 1961 break; 1962 case com.android.internal.R.styleable.View_paddingRight: 1963 rightPadding = a.getDimensionPixelSize(attr, -1); 1964 break; 1965 case com.android.internal.R.styleable.View_paddingBottom: 1966 bottomPadding = a.getDimensionPixelSize(attr, -1); 1967 break; 1968 case com.android.internal.R.styleable.View_scrollX: 1969 x = a.getDimensionPixelOffset(attr, 0); 1970 break; 1971 case com.android.internal.R.styleable.View_scrollY: 1972 y = a.getDimensionPixelOffset(attr, 0); 1973 break; 1974 case com.android.internal.R.styleable.View_id: 1975 mID = a.getResourceId(attr, NO_ID); 1976 break; 1977 case com.android.internal.R.styleable.View_tag: 1978 mTag = a.getText(attr); 1979 break; 1980 case com.android.internal.R.styleable.View_fitsSystemWindows: 1981 if (a.getBoolean(attr, false)) { 1982 viewFlagValues |= FITS_SYSTEM_WINDOWS; 1983 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 1984 } 1985 break; 1986 case com.android.internal.R.styleable.View_focusable: 1987 if (a.getBoolean(attr, false)) { 1988 viewFlagValues |= FOCUSABLE; 1989 viewFlagMasks |= FOCUSABLE_MASK; 1990 } 1991 break; 1992 case com.android.internal.R.styleable.View_focusableInTouchMode: 1993 if (a.getBoolean(attr, false)) { 1994 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 1995 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 1996 } 1997 break; 1998 case com.android.internal.R.styleable.View_clickable: 1999 if (a.getBoolean(attr, false)) { 2000 viewFlagValues |= CLICKABLE; 2001 viewFlagMasks |= CLICKABLE; 2002 } 2003 break; 2004 case com.android.internal.R.styleable.View_longClickable: 2005 if (a.getBoolean(attr, false)) { 2006 viewFlagValues |= LONG_CLICKABLE; 2007 viewFlagMasks |= LONG_CLICKABLE; 2008 } 2009 break; 2010 case com.android.internal.R.styleable.View_saveEnabled: 2011 if (!a.getBoolean(attr, true)) { 2012 viewFlagValues |= SAVE_DISABLED; 2013 viewFlagMasks |= SAVE_DISABLED_MASK; 2014 } 2015 break; 2016 case com.android.internal.R.styleable.View_duplicateParentState: 2017 if (a.getBoolean(attr, false)) { 2018 viewFlagValues |= DUPLICATE_PARENT_STATE; 2019 viewFlagMasks |= DUPLICATE_PARENT_STATE; 2020 } 2021 break; 2022 case com.android.internal.R.styleable.View_visibility: 2023 final int visibility = a.getInt(attr, 0); 2024 if (visibility != 0) { 2025 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 2026 viewFlagMasks |= VISIBILITY_MASK; 2027 } 2028 break; 2029 case com.android.internal.R.styleable.View_drawingCacheQuality: 2030 final int cacheQuality = a.getInt(attr, 0); 2031 if (cacheQuality != 0) { 2032 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 2033 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 2034 } 2035 break; 2036 case com.android.internal.R.styleable.View_contentDescription: 2037 mContentDescription = a.getString(attr); 2038 break; 2039 case com.android.internal.R.styleable.View_soundEffectsEnabled: 2040 if (!a.getBoolean(attr, true)) { 2041 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 2042 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 2043 } 2044 break; 2045 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 2046 if (!a.getBoolean(attr, true)) { 2047 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 2048 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 2049 } 2050 break; 2051 case R.styleable.View_scrollbars: 2052 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 2053 if (scrollbars != SCROLLBARS_NONE) { 2054 viewFlagValues |= scrollbars; 2055 viewFlagMasks |= SCROLLBARS_MASK; 2056 initializeScrollbars(a); 2057 } 2058 break; 2059 case R.styleable.View_fadingEdge: 2060 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 2061 if (fadingEdge != FADING_EDGE_NONE) { 2062 viewFlagValues |= fadingEdge; 2063 viewFlagMasks |= FADING_EDGE_MASK; 2064 initializeFadingEdge(a); 2065 } 2066 break; 2067 case R.styleable.View_scrollbarStyle: 2068 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 2069 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 2070 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 2071 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 2072 } 2073 break; 2074 case R.styleable.View_isScrollContainer: 2075 setScrollContainer = true; 2076 if (a.getBoolean(attr, false)) { 2077 setScrollContainer(true); 2078 } 2079 break; 2080 case com.android.internal.R.styleable.View_keepScreenOn: 2081 if (a.getBoolean(attr, false)) { 2082 viewFlagValues |= KEEP_SCREEN_ON; 2083 viewFlagMasks |= KEEP_SCREEN_ON; 2084 } 2085 break; 2086 case R.styleable.View_filterTouchesWhenObscured: 2087 if (a.getBoolean(attr, false)) { 2088 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 2089 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 2090 } 2091 break; 2092 case R.styleable.View_nextFocusLeft: 2093 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 2094 break; 2095 case R.styleable.View_nextFocusRight: 2096 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 2097 break; 2098 case R.styleable.View_nextFocusUp: 2099 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 2100 break; 2101 case R.styleable.View_nextFocusDown: 2102 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 2103 break; 2104 case R.styleable.View_minWidth: 2105 mMinWidth = a.getDimensionPixelSize(attr, 0); 2106 break; 2107 case R.styleable.View_minHeight: 2108 mMinHeight = a.getDimensionPixelSize(attr, 0); 2109 break; 2110 case R.styleable.View_onClick: 2111 if (context.isRestricted()) { 2112 throw new IllegalStateException("The android:onClick attribute cannot " 2113 + "be used within a restricted context"); 2114 } 2115 2116 final String handlerName = a.getString(attr); 2117 if (handlerName != null) { 2118 setOnClickListener(new OnClickListener() { 2119 private Method mHandler; 2120 2121 public void onClick(View v) { 2122 if (mHandler == null) { 2123 try { 2124 mHandler = getContext().getClass().getMethod(handlerName, 2125 View.class); 2126 } catch (NoSuchMethodException e) { 2127 int id = getId(); 2128 String idText = id == NO_ID ? "" : " with id '" 2129 + getContext().getResources().getResourceEntryName( 2130 id) + "'"; 2131 throw new IllegalStateException("Could not find a method " + 2132 handlerName + "(View) in the activity " 2133 + getContext().getClass() + " for onClick handler" 2134 + " on view " + View.this.getClass() + idText, e); 2135 } 2136 } 2137 2138 try { 2139 mHandler.invoke(getContext(), View.this); 2140 } catch (IllegalAccessException e) { 2141 throw new IllegalStateException("Could not execute non " 2142 + "public method of the activity", e); 2143 } catch (InvocationTargetException e) { 2144 throw new IllegalStateException("Could not execute " 2145 + "method of the activity", e); 2146 } 2147 } 2148 }); 2149 } 2150 break; 2151 case R.styleable.View_overScrollMode: 2152 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 2153 break; 2154 } 2155 } 2156 2157 setOverScrollMode(overScrollMode); 2158 2159 if (background != null) { 2160 setBackgroundDrawable(background); 2161 } 2162 2163 if (padding >= 0) { 2164 leftPadding = padding; 2165 topPadding = padding; 2166 rightPadding = padding; 2167 bottomPadding = padding; 2168 } 2169 2170 // If the user specified the padding (either with android:padding or 2171 // android:paddingLeft/Top/Right/Bottom), use this padding, otherwise 2172 // use the default padding or the padding from the background drawable 2173 // (stored at this point in mPadding*) 2174 setPadding(leftPadding >= 0 ? leftPadding : mPaddingLeft, 2175 topPadding >= 0 ? topPadding : mPaddingTop, 2176 rightPadding >= 0 ? rightPadding : mPaddingRight, 2177 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 2178 2179 if (viewFlagMasks != 0) { 2180 setFlags(viewFlagValues, viewFlagMasks); 2181 } 2182 2183 // Needs to be called after mViewFlags is set 2184 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 2185 recomputePadding(); 2186 } 2187 2188 if (x != 0 || y != 0) { 2189 scrollTo(x, y); 2190 } 2191 2192 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 2193 setScrollContainer(true); 2194 } 2195 2196 computeOpaqueFlags(); 2197 2198 a.recycle(); 2199 } 2200 2201 /** 2202 * Non-public constructor for use in testing 2203 */ View()2204 View() { 2205 } 2206 2207 // Used for debug only 2208 /* 2209 @Override 2210 protected void finalize() throws Throwable { 2211 super.finalize(); 2212 --sInstanceCount; 2213 } 2214 */ 2215 2216 /** 2217 * <p> 2218 * Initializes the fading edges from a given set of styled attributes. This 2219 * method should be called by subclasses that need fading edges and when an 2220 * instance of these subclasses is created programmatically rather than 2221 * being inflated from XML. This method is automatically called when the XML 2222 * is inflated. 2223 * </p> 2224 * 2225 * @param a the styled attributes set to initialize the fading edges from 2226 */ initializeFadingEdge(TypedArray a)2227 protected void initializeFadingEdge(TypedArray a) { 2228 initScrollCache(); 2229 2230 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 2231 R.styleable.View_fadingEdgeLength, 2232 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 2233 } 2234 2235 /** 2236 * Returns the size of the vertical faded edges used to indicate that more 2237 * content in this view is visible. 2238 * 2239 * @return The size in pixels of the vertical faded edge or 0 if vertical 2240 * faded edges are not enabled for this view. 2241 * @attr ref android.R.styleable#View_fadingEdgeLength 2242 */ getVerticalFadingEdgeLength()2243 public int getVerticalFadingEdgeLength() { 2244 if (isVerticalFadingEdgeEnabled()) { 2245 ScrollabilityCache cache = mScrollCache; 2246 if (cache != null) { 2247 return cache.fadingEdgeLength; 2248 } 2249 } 2250 return 0; 2251 } 2252 2253 /** 2254 * Set the size of the faded edge used to indicate that more content in this 2255 * view is available. Will not change whether the fading edge is enabled; use 2256 * {@link #setVerticalFadingEdgeEnabled} or {@link #setHorizontalFadingEdgeEnabled} 2257 * to enable the fading edge for the vertical or horizontal fading edges. 2258 * 2259 * @param length The size in pixels of the faded edge used to indicate that more 2260 * content in this view is visible. 2261 */ setFadingEdgeLength(int length)2262 public void setFadingEdgeLength(int length) { 2263 initScrollCache(); 2264 mScrollCache.fadingEdgeLength = length; 2265 } 2266 2267 /** 2268 * Returns the size of the horizontal faded edges used to indicate that more 2269 * content in this view is visible. 2270 * 2271 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 2272 * faded edges are not enabled for this view. 2273 * @attr ref android.R.styleable#View_fadingEdgeLength 2274 */ getHorizontalFadingEdgeLength()2275 public int getHorizontalFadingEdgeLength() { 2276 if (isHorizontalFadingEdgeEnabled()) { 2277 ScrollabilityCache cache = mScrollCache; 2278 if (cache != null) { 2279 return cache.fadingEdgeLength; 2280 } 2281 } 2282 return 0; 2283 } 2284 2285 /** 2286 * Returns the width of the vertical scrollbar. 2287 * 2288 * @return The width in pixels of the vertical scrollbar or 0 if there 2289 * is no vertical scrollbar. 2290 */ getVerticalScrollbarWidth()2291 public int getVerticalScrollbarWidth() { 2292 ScrollabilityCache cache = mScrollCache; 2293 if (cache != null) { 2294 ScrollBarDrawable scrollBar = cache.scrollBar; 2295 if (scrollBar != null) { 2296 int size = scrollBar.getSize(true); 2297 if (size <= 0) { 2298 size = cache.scrollBarSize; 2299 } 2300 return size; 2301 } 2302 return 0; 2303 } 2304 return 0; 2305 } 2306 2307 /** 2308 * Returns the height of the horizontal scrollbar. 2309 * 2310 * @return The height in pixels of the horizontal scrollbar or 0 if 2311 * there is no horizontal scrollbar. 2312 */ getHorizontalScrollbarHeight()2313 protected int getHorizontalScrollbarHeight() { 2314 ScrollabilityCache cache = mScrollCache; 2315 if (cache != null) { 2316 ScrollBarDrawable scrollBar = cache.scrollBar; 2317 if (scrollBar != null) { 2318 int size = scrollBar.getSize(false); 2319 if (size <= 0) { 2320 size = cache.scrollBarSize; 2321 } 2322 return size; 2323 } 2324 return 0; 2325 } 2326 return 0; 2327 } 2328 2329 /** 2330 * <p> 2331 * Initializes the scrollbars from a given set of styled attributes. This 2332 * method should be called by subclasses that need scrollbars and when an 2333 * instance of these subclasses is created programmatically rather than 2334 * being inflated from XML. This method is automatically called when the XML 2335 * is inflated. 2336 * </p> 2337 * 2338 * @param a the styled attributes set to initialize the scrollbars from 2339 */ initializeScrollbars(TypedArray a)2340 protected void initializeScrollbars(TypedArray a) { 2341 initScrollCache(); 2342 2343 final ScrollabilityCache scrollabilityCache = mScrollCache; 2344 2345 if (scrollabilityCache.scrollBar == null) { 2346 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 2347 } 2348 2349 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 2350 2351 if (!fadeScrollbars) { 2352 scrollabilityCache.state = ScrollabilityCache.ON; 2353 } 2354 scrollabilityCache.fadeScrollBars = fadeScrollbars; 2355 2356 2357 scrollabilityCache.scrollBarFadeDuration = a.getInt( 2358 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 2359 .getScrollBarFadeDuration()); 2360 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 2361 R.styleable.View_scrollbarDefaultDelayBeforeFade, 2362 ViewConfiguration.getScrollDefaultDelay()); 2363 2364 2365 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 2366 com.android.internal.R.styleable.View_scrollbarSize, 2367 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 2368 2369 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 2370 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 2371 2372 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 2373 if (thumb != null) { 2374 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 2375 } 2376 2377 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 2378 false); 2379 if (alwaysDraw) { 2380 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 2381 } 2382 2383 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 2384 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 2385 2386 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 2387 if (thumb != null) { 2388 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 2389 } 2390 2391 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 2392 false); 2393 if (alwaysDraw) { 2394 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 2395 } 2396 2397 // Re-apply user/background padding so that scrollbar(s) get added 2398 recomputePadding(); 2399 } 2400 2401 /** 2402 * <p> 2403 * Initalizes the scrollability cache if necessary. 2404 * </p> 2405 */ initScrollCache()2406 private void initScrollCache() { 2407 if (mScrollCache == null) { 2408 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 2409 } 2410 } 2411 2412 /** 2413 * Register a callback to be invoked when focus of this view changed. 2414 * 2415 * @param l The callback that will run. 2416 */ setOnFocusChangeListener(OnFocusChangeListener l)2417 public void setOnFocusChangeListener(OnFocusChangeListener l) { 2418 mOnFocusChangeListener = l; 2419 } 2420 2421 /** 2422 * Returns the focus-change callback registered for this view. 2423 * 2424 * @return The callback, or null if one is not registered. 2425 */ getOnFocusChangeListener()2426 public OnFocusChangeListener getOnFocusChangeListener() { 2427 return mOnFocusChangeListener; 2428 } 2429 2430 /** 2431 * Register a callback to be invoked when this view is clicked. If this view is not 2432 * clickable, it becomes clickable. 2433 * 2434 * @param l The callback that will run 2435 * 2436 * @see #setClickable(boolean) 2437 */ setOnClickListener(OnClickListener l)2438 public void setOnClickListener(OnClickListener l) { 2439 if (!isClickable()) { 2440 setClickable(true); 2441 } 2442 mOnClickListener = l; 2443 } 2444 2445 /** 2446 * Register a callback to be invoked when this view is clicked and held. If this view is not 2447 * long clickable, it becomes long clickable. 2448 * 2449 * @param l The callback that will run 2450 * 2451 * @see #setLongClickable(boolean) 2452 */ setOnLongClickListener(OnLongClickListener l)2453 public void setOnLongClickListener(OnLongClickListener l) { 2454 if (!isLongClickable()) { 2455 setLongClickable(true); 2456 } 2457 mOnLongClickListener = l; 2458 } 2459 2460 /** 2461 * Register a callback to be invoked when the context menu for this view is 2462 * being built. If this view is not long clickable, it becomes long clickable. 2463 * 2464 * @param l The callback that will run 2465 * 2466 */ setOnCreateContextMenuListener(OnCreateContextMenuListener l)2467 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 2468 if (!isLongClickable()) { 2469 setLongClickable(true); 2470 } 2471 mOnCreateContextMenuListener = l; 2472 } 2473 2474 /** 2475 * Call this view's OnClickListener, if it is defined. 2476 * 2477 * @return True there was an assigned OnClickListener that was called, false 2478 * otherwise is returned. 2479 */ performClick()2480 public boolean performClick() { 2481 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 2482 2483 if (mOnClickListener != null) { 2484 playSoundEffect(SoundEffectConstants.CLICK); 2485 mOnClickListener.onClick(this); 2486 return true; 2487 } 2488 2489 return false; 2490 } 2491 2492 /** 2493 * Call this view's OnLongClickListener, if it is defined. Invokes the context menu if the 2494 * OnLongClickListener did not consume the event. 2495 * 2496 * @return True if one of the above receivers consumed the event, false otherwise. 2497 */ performLongClick()2498 public boolean performLongClick() { 2499 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 2500 2501 boolean handled = false; 2502 if (mOnLongClickListener != null) { 2503 handled = mOnLongClickListener.onLongClick(View.this); 2504 } 2505 if (!handled) { 2506 handled = showContextMenu(); 2507 } 2508 if (handled) { 2509 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 2510 } 2511 return handled; 2512 } 2513 2514 /** 2515 * Bring up the context menu for this view. 2516 * 2517 * @return Whether a context menu was displayed. 2518 */ showContextMenu()2519 public boolean showContextMenu() { 2520 return getParent().showContextMenuForChild(this); 2521 } 2522 2523 /** 2524 * Register a callback to be invoked when a key is pressed in this view. 2525 * @param l the key listener to attach to this view 2526 */ setOnKeyListener(OnKeyListener l)2527 public void setOnKeyListener(OnKeyListener l) { 2528 mOnKeyListener = l; 2529 } 2530 2531 /** 2532 * Register a callback to be invoked when a touch event is sent to this view. 2533 * @param l the touch listener to attach to this view 2534 */ setOnTouchListener(OnTouchListener l)2535 public void setOnTouchListener(OnTouchListener l) { 2536 mOnTouchListener = l; 2537 } 2538 2539 /** 2540 * Give this view focus. This will cause {@link #onFocusChanged} to be called. 2541 * 2542 * Note: this does not check whether this {@link View} should get focus, it just 2543 * gives it focus no matter what. It should only be called internally by framework 2544 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 2545 * 2546 * @param direction values are View.FOCUS_UP, View.FOCUS_DOWN, 2547 * View.FOCUS_LEFT or View.FOCUS_RIGHT. This is the direction which 2548 * focus moved when requestFocus() is called. It may not always 2549 * apply, in which case use the default View.FOCUS_DOWN. 2550 * @param previouslyFocusedRect The rectangle of the view that had focus 2551 * prior in this View's coordinate system. 2552 */ handleFocusGainInternal(int direction, Rect previouslyFocusedRect)2553 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) { 2554 if (DBG) { 2555 System.out.println(this + " requestFocus()"); 2556 } 2557 2558 if ((mPrivateFlags & FOCUSED) == 0) { 2559 mPrivateFlags |= FOCUSED; 2560 2561 if (mParent != null) { 2562 mParent.requestChildFocus(this, this); 2563 } 2564 2565 onFocusChanged(true, direction, previouslyFocusedRect); 2566 refreshDrawableState(); 2567 } 2568 } 2569 2570 /** 2571 * Request that a rectangle of this view be visible on the screen, 2572 * scrolling if necessary just enough. 2573 * 2574 * <p>A View should call this if it maintains some notion of which part 2575 * of its content is interesting. For example, a text editing view 2576 * should call this when its cursor moves. 2577 * 2578 * @param rectangle The rectangle. 2579 * @return Whether any parent scrolled. 2580 */ requestRectangleOnScreen(Rect rectangle)2581 public boolean requestRectangleOnScreen(Rect rectangle) { 2582 return requestRectangleOnScreen(rectangle, false); 2583 } 2584 2585 /** 2586 * Request that a rectangle of this view be visible on the screen, 2587 * scrolling if necessary just enough. 2588 * 2589 * <p>A View should call this if it maintains some notion of which part 2590 * of its content is interesting. For example, a text editing view 2591 * should call this when its cursor moves. 2592 * 2593 * <p>When <code>immediate</code> is set to true, scrolling will not be 2594 * animated. 2595 * 2596 * @param rectangle The rectangle. 2597 * @param immediate True to forbid animated scrolling, false otherwise 2598 * @return Whether any parent scrolled. 2599 */ requestRectangleOnScreen(Rect rectangle, boolean immediate)2600 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 2601 View child = this; 2602 ViewParent parent = mParent; 2603 boolean scrolled = false; 2604 while (parent != null) { 2605 scrolled |= parent.requestChildRectangleOnScreen(child, 2606 rectangle, immediate); 2607 2608 // offset rect so next call has the rectangle in the 2609 // coordinate system of its direct child. 2610 rectangle.offset(child.getLeft(), child.getTop()); 2611 rectangle.offset(-child.getScrollX(), -child.getScrollY()); 2612 2613 if (!(parent instanceof View)) { 2614 break; 2615 } 2616 2617 child = (View) parent; 2618 parent = child.getParent(); 2619 } 2620 return scrolled; 2621 } 2622 2623 /** 2624 * Called when this view wants to give up focus. This will cause 2625 * {@link #onFocusChanged} to be called. 2626 */ clearFocus()2627 public void clearFocus() { 2628 if (DBG) { 2629 System.out.println(this + " clearFocus()"); 2630 } 2631 2632 if ((mPrivateFlags & FOCUSED) != 0) { 2633 mPrivateFlags &= ~FOCUSED; 2634 2635 if (mParent != null) { 2636 mParent.clearChildFocus(this); 2637 } 2638 2639 onFocusChanged(false, 0, null); 2640 refreshDrawableState(); 2641 } 2642 } 2643 2644 /** 2645 * Called to clear the focus of a view that is about to be removed. 2646 * Doesn't call clearChildFocus, which prevents this view from taking 2647 * focus again before it has been removed from the parent 2648 */ clearFocusForRemoval()2649 void clearFocusForRemoval() { 2650 if ((mPrivateFlags & FOCUSED) != 0) { 2651 mPrivateFlags &= ~FOCUSED; 2652 2653 onFocusChanged(false, 0, null); 2654 refreshDrawableState(); 2655 } 2656 } 2657 2658 /** 2659 * Called internally by the view system when a new view is getting focus. 2660 * This is what clears the old focus. 2661 */ unFocus()2662 void unFocus() { 2663 if (DBG) { 2664 System.out.println(this + " unFocus()"); 2665 } 2666 2667 if ((mPrivateFlags & FOCUSED) != 0) { 2668 mPrivateFlags &= ~FOCUSED; 2669 2670 onFocusChanged(false, 0, null); 2671 refreshDrawableState(); 2672 } 2673 } 2674 2675 /** 2676 * Returns true if this view has focus iteself, or is the ancestor of the 2677 * view that has focus. 2678 * 2679 * @return True if this view has or contains focus, false otherwise. 2680 */ 2681 @ViewDebug.ExportedProperty(category = "focus") hasFocus()2682 public boolean hasFocus() { 2683 return (mPrivateFlags & FOCUSED) != 0; 2684 } 2685 2686 /** 2687 * Returns true if this view is focusable or if it contains a reachable View 2688 * for which {@link #hasFocusable()} returns true. A "reachable hasFocusable()" 2689 * is a View whose parents do not block descendants focus. 2690 * 2691 * Only {@link #VISIBLE} views are considered focusable. 2692 * 2693 * @return True if the view is focusable or if the view contains a focusable 2694 * View, false otherwise. 2695 * 2696 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 2697 */ hasFocusable()2698 public boolean hasFocusable() { 2699 return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable(); 2700 } 2701 2702 /** 2703 * Called by the view system when the focus state of this view changes. 2704 * When the focus change event is caused by directional navigation, direction 2705 * and previouslyFocusedRect provide insight into where the focus is coming from. 2706 * When overriding, be sure to call up through to the super class so that 2707 * the standard focus handling will occur. 2708 * 2709 * @param gainFocus True if the View has focus; false otherwise. 2710 * @param direction The direction focus has moved when requestFocus() 2711 * is called to give this view focus. Values are 2712 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT} or 2713 * {@link #FOCUS_RIGHT}. It may not always apply, in which 2714 * case use the default. 2715 * @param previouslyFocusedRect The rectangle, in this view's coordinate 2716 * system, of the previously focused view. If applicable, this will be 2717 * passed in as finer grained information about where the focus is coming 2718 * from (in addition to direction). Will be <code>null</code> otherwise. 2719 */ onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect)2720 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 2721 if (gainFocus) { 2722 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 2723 } 2724 2725 InputMethodManager imm = InputMethodManager.peekInstance(); 2726 if (!gainFocus) { 2727 if (isPressed()) { 2728 setPressed(false); 2729 } 2730 if (imm != null && mAttachInfo != null 2731 && mAttachInfo.mHasWindowFocus) { 2732 imm.focusOut(this); 2733 } 2734 onFocusLost(); 2735 } else if (imm != null && mAttachInfo != null 2736 && mAttachInfo.mHasWindowFocus) { 2737 imm.focusIn(this); 2738 } 2739 2740 invalidate(); 2741 if (mOnFocusChangeListener != null) { 2742 mOnFocusChangeListener.onFocusChange(this, gainFocus); 2743 } 2744 2745 if (mAttachInfo != null) { 2746 mAttachInfo.mKeyDispatchState.reset(this); 2747 } 2748 } 2749 2750 /** 2751 * {@inheritDoc} 2752 */ sendAccessibilityEvent(int eventType)2753 public void sendAccessibilityEvent(int eventType) { 2754 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 2755 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 2756 } 2757 } 2758 2759 /** 2760 * {@inheritDoc} 2761 */ sendAccessibilityEventUnchecked(AccessibilityEvent event)2762 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 2763 event.setClassName(getClass().getName()); 2764 event.setPackageName(getContext().getPackageName()); 2765 event.setEnabled(isEnabled()); 2766 event.setContentDescription(mContentDescription); 2767 2768 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && mAttachInfo != null) { 2769 ArrayList<View> focusablesTempList = mAttachInfo.mFocusablesTempList; 2770 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 2771 event.setItemCount(focusablesTempList.size()); 2772 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 2773 focusablesTempList.clear(); 2774 } 2775 2776 dispatchPopulateAccessibilityEvent(event); 2777 2778 AccessibilityManager.getInstance(mContext).sendAccessibilityEvent(event); 2779 } 2780 2781 /** 2782 * Dispatches an {@link AccessibilityEvent} to the {@link View} children 2783 * to be populated. 2784 * 2785 * @param event The event. 2786 * 2787 * @return True if the event population was completed. 2788 */ dispatchPopulateAccessibilityEvent(AccessibilityEvent event)2789 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 2790 return false; 2791 } 2792 2793 /** 2794 * Gets the {@link View} description. It briefly describes the view and is 2795 * primarily used for accessibility support. Set this property to enable 2796 * better accessibility support for your application. This is especially 2797 * true for views that do not have textual representation (For example, 2798 * ImageButton). 2799 * 2800 * @return The content descriptiopn. 2801 * 2802 * @attr ref android.R.styleable#View_contentDescription 2803 */ getContentDescription()2804 public CharSequence getContentDescription() { 2805 return mContentDescription; 2806 } 2807 2808 /** 2809 * Sets the {@link View} description. It briefly describes the view and is 2810 * primarily used for accessibility support. Set this property to enable 2811 * better accessibility support for your application. This is especially 2812 * true for views that do not have textual representation (For example, 2813 * ImageButton). 2814 * 2815 * @param contentDescription The content description. 2816 * 2817 * @attr ref android.R.styleable#View_contentDescription 2818 */ setContentDescription(CharSequence contentDescription)2819 public void setContentDescription(CharSequence contentDescription) { 2820 mContentDescription = contentDescription; 2821 } 2822 2823 /** 2824 * Invoked whenever this view loses focus, either by losing window focus or by losing 2825 * focus within its window. This method can be used to clear any state tied to the 2826 * focus. For instance, if a button is held pressed with the trackball and the window 2827 * loses focus, this method can be used to cancel the press. 2828 * 2829 * Subclasses of View overriding this method should always call super.onFocusLost(). 2830 * 2831 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 2832 * @see #onWindowFocusChanged(boolean) 2833 * 2834 * @hide pending API council approval 2835 */ onFocusLost()2836 protected void onFocusLost() { 2837 resetPressedState(); 2838 } 2839 resetPressedState()2840 private void resetPressedState() { 2841 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 2842 return; 2843 } 2844 2845 if (isPressed()) { 2846 setPressed(false); 2847 2848 if (!mHasPerformedLongPress) { 2849 removeLongPressCallback(); 2850 } 2851 } 2852 } 2853 2854 /** 2855 * Returns true if this view has focus 2856 * 2857 * @return True if this view has focus, false otherwise. 2858 */ 2859 @ViewDebug.ExportedProperty(category = "focus") isFocused()2860 public boolean isFocused() { 2861 return (mPrivateFlags & FOCUSED) != 0; 2862 } 2863 2864 /** 2865 * Find the view in the hierarchy rooted at this view that currently has 2866 * focus. 2867 * 2868 * @return The view that currently has focus, or null if no focused view can 2869 * be found. 2870 */ findFocus()2871 public View findFocus() { 2872 return (mPrivateFlags & FOCUSED) != 0 ? this : null; 2873 } 2874 2875 /** 2876 * Change whether this view is one of the set of scrollable containers in 2877 * its window. This will be used to determine whether the window can 2878 * resize or must pan when a soft input area is open -- scrollable 2879 * containers allow the window to use resize mode since the container 2880 * will appropriately shrink. 2881 */ setScrollContainer(boolean isScrollContainer)2882 public void setScrollContainer(boolean isScrollContainer) { 2883 if (isScrollContainer) { 2884 if (mAttachInfo != null && (mPrivateFlags&SCROLL_CONTAINER_ADDED) == 0) { 2885 mAttachInfo.mScrollContainers.add(this); 2886 mPrivateFlags |= SCROLL_CONTAINER_ADDED; 2887 } 2888 mPrivateFlags |= SCROLL_CONTAINER; 2889 } else { 2890 if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) { 2891 mAttachInfo.mScrollContainers.remove(this); 2892 } 2893 mPrivateFlags &= ~(SCROLL_CONTAINER|SCROLL_CONTAINER_ADDED); 2894 } 2895 } 2896 2897 /** 2898 * Returns the quality of the drawing cache. 2899 * 2900 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 2901 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 2902 * 2903 * @see #setDrawingCacheQuality(int) 2904 * @see #setDrawingCacheEnabled(boolean) 2905 * @see #isDrawingCacheEnabled() 2906 * 2907 * @attr ref android.R.styleable#View_drawingCacheQuality 2908 */ getDrawingCacheQuality()2909 public int getDrawingCacheQuality() { 2910 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 2911 } 2912 2913 /** 2914 * Set the drawing cache quality of this view. This value is used only when the 2915 * drawing cache is enabled 2916 * 2917 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 2918 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 2919 * 2920 * @see #getDrawingCacheQuality() 2921 * @see #setDrawingCacheEnabled(boolean) 2922 * @see #isDrawingCacheEnabled() 2923 * 2924 * @attr ref android.R.styleable#View_drawingCacheQuality 2925 */ setDrawingCacheQuality(int quality)2926 public void setDrawingCacheQuality(int quality) { 2927 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 2928 } 2929 2930 /** 2931 * Returns whether the screen should remain on, corresponding to the current 2932 * value of {@link #KEEP_SCREEN_ON}. 2933 * 2934 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 2935 * 2936 * @see #setKeepScreenOn(boolean) 2937 * 2938 * @attr ref android.R.styleable#View_keepScreenOn 2939 */ getKeepScreenOn()2940 public boolean getKeepScreenOn() { 2941 return (mViewFlags & KEEP_SCREEN_ON) != 0; 2942 } 2943 2944 /** 2945 * Controls whether the screen should remain on, modifying the 2946 * value of {@link #KEEP_SCREEN_ON}. 2947 * 2948 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 2949 * 2950 * @see #getKeepScreenOn() 2951 * 2952 * @attr ref android.R.styleable#View_keepScreenOn 2953 */ setKeepScreenOn(boolean keepScreenOn)2954 public void setKeepScreenOn(boolean keepScreenOn) { 2955 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 2956 } 2957 2958 /** 2959 * @return The user specified next focus ID. 2960 * 2961 * @attr ref android.R.styleable#View_nextFocusLeft 2962 */ getNextFocusLeftId()2963 public int getNextFocusLeftId() { 2964 return mNextFocusLeftId; 2965 } 2966 2967 /** 2968 * Set the id of the view to use for the next focus 2969 * 2970 * @param nextFocusLeftId 2971 * 2972 * @attr ref android.R.styleable#View_nextFocusLeft 2973 */ setNextFocusLeftId(int nextFocusLeftId)2974 public void setNextFocusLeftId(int nextFocusLeftId) { 2975 mNextFocusLeftId = nextFocusLeftId; 2976 } 2977 2978 /** 2979 * @return The user specified next focus ID. 2980 * 2981 * @attr ref android.R.styleable#View_nextFocusRight 2982 */ getNextFocusRightId()2983 public int getNextFocusRightId() { 2984 return mNextFocusRightId; 2985 } 2986 2987 /** 2988 * Set the id of the view to use for the next focus 2989 * 2990 * @param nextFocusRightId 2991 * 2992 * @attr ref android.R.styleable#View_nextFocusRight 2993 */ setNextFocusRightId(int nextFocusRightId)2994 public void setNextFocusRightId(int nextFocusRightId) { 2995 mNextFocusRightId = nextFocusRightId; 2996 } 2997 2998 /** 2999 * @return The user specified next focus ID. 3000 * 3001 * @attr ref android.R.styleable#View_nextFocusUp 3002 */ getNextFocusUpId()3003 public int getNextFocusUpId() { 3004 return mNextFocusUpId; 3005 } 3006 3007 /** 3008 * Set the id of the view to use for the next focus 3009 * 3010 * @param nextFocusUpId 3011 * 3012 * @attr ref android.R.styleable#View_nextFocusUp 3013 */ setNextFocusUpId(int nextFocusUpId)3014 public void setNextFocusUpId(int nextFocusUpId) { 3015 mNextFocusUpId = nextFocusUpId; 3016 } 3017 3018 /** 3019 * @return The user specified next focus ID. 3020 * 3021 * @attr ref android.R.styleable#View_nextFocusDown 3022 */ getNextFocusDownId()3023 public int getNextFocusDownId() { 3024 return mNextFocusDownId; 3025 } 3026 3027 /** 3028 * Set the id of the view to use for the next focus 3029 * 3030 * @param nextFocusDownId 3031 * 3032 * @attr ref android.R.styleable#View_nextFocusDown 3033 */ setNextFocusDownId(int nextFocusDownId)3034 public void setNextFocusDownId(int nextFocusDownId) { 3035 mNextFocusDownId = nextFocusDownId; 3036 } 3037 3038 /** 3039 * Returns the visibility of this view and all of its ancestors 3040 * 3041 * @return True if this view and all of its ancestors are {@link #VISIBLE} 3042 */ isShown()3043 public boolean isShown() { 3044 View current = this; 3045 //noinspection ConstantConditions 3046 do { 3047 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 3048 return false; 3049 } 3050 ViewParent parent = current.mParent; 3051 if (parent == null) { 3052 return false; // We are not attached to the view root 3053 } 3054 if (!(parent instanceof View)) { 3055 return true; 3056 } 3057 current = (View) parent; 3058 } while (current != null); 3059 3060 return false; 3061 } 3062 3063 /** 3064 * Apply the insets for system windows to this view, if the FITS_SYSTEM_WINDOWS flag 3065 * is set 3066 * 3067 * @param insets Insets for system windows 3068 * 3069 * @return True if this view applied the insets, false otherwise 3070 */ fitSystemWindows(Rect insets)3071 protected boolean fitSystemWindows(Rect insets) { 3072 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 3073 mPaddingLeft = insets.left; 3074 mPaddingTop = insets.top; 3075 mPaddingRight = insets.right; 3076 mPaddingBottom = insets.bottom; 3077 requestLayout(); 3078 return true; 3079 } 3080 return false; 3081 } 3082 3083 /** 3084 * Determine if this view has the FITS_SYSTEM_WINDOWS flag set. 3085 * @return True if window has FITS_SYSTEM_WINDOWS set 3086 * 3087 * @hide 3088 */ isFitsSystemWindowsFlagSet()3089 public boolean isFitsSystemWindowsFlagSet() { 3090 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 3091 } 3092 3093 /** 3094 * Returns the visibility status for this view. 3095 * 3096 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 3097 * @attr ref android.R.styleable#View_visibility 3098 */ 3099 @ViewDebug.ExportedProperty(mapping = { 3100 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 3101 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 3102 @ViewDebug.IntToString(from = GONE, to = "GONE") 3103 }) getVisibility()3104 public int getVisibility() { 3105 return mViewFlags & VISIBILITY_MASK; 3106 } 3107 3108 /** 3109 * Set the enabled state of this view. 3110 * 3111 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 3112 * @attr ref android.R.styleable#View_visibility 3113 */ 3114 @RemotableViewMethod setVisibility(int visibility)3115 public void setVisibility(int visibility) { 3116 setFlags(visibility, VISIBILITY_MASK); 3117 if (mBGDrawable != null) mBGDrawable.setVisible(visibility == VISIBLE, false); 3118 } 3119 3120 /** 3121 * Returns the enabled status for this view. The interpretation of the 3122 * enabled state varies by subclass. 3123 * 3124 * @return True if this view is enabled, false otherwise. 3125 */ 3126 @ViewDebug.ExportedProperty isEnabled()3127 public boolean isEnabled() { 3128 return (mViewFlags & ENABLED_MASK) == ENABLED; 3129 } 3130 3131 /** 3132 * Set the enabled state of this view. The interpretation of the enabled 3133 * state varies by subclass. 3134 * 3135 * @param enabled True if this view is enabled, false otherwise. 3136 */ 3137 @RemotableViewMethod setEnabled(boolean enabled)3138 public void setEnabled(boolean enabled) { 3139 if (enabled == isEnabled()) return; 3140 3141 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 3142 3143 /* 3144 * The View most likely has to change its appearance, so refresh 3145 * the drawable state. 3146 */ 3147 refreshDrawableState(); 3148 3149 // Invalidate too, since the default behavior for views is to be 3150 // be drawn at 50% alpha rather than to change the drawable. 3151 invalidate(); 3152 } 3153 3154 /** 3155 * Set whether this view can receive the focus. 3156 * 3157 * Setting this to false will also ensure that this view is not focusable 3158 * in touch mode. 3159 * 3160 * @param focusable If true, this view can receive the focus. 3161 * 3162 * @see #setFocusableInTouchMode(boolean) 3163 * @attr ref android.R.styleable#View_focusable 3164 */ setFocusable(boolean focusable)3165 public void setFocusable(boolean focusable) { 3166 if (!focusable) { 3167 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 3168 } 3169 setFlags(focusable ? FOCUSABLE : NOT_FOCUSABLE, FOCUSABLE_MASK); 3170 } 3171 3172 /** 3173 * Set whether this view can receive focus while in touch mode. 3174 * 3175 * Setting this to true will also ensure that this view is focusable. 3176 * 3177 * @param focusableInTouchMode If true, this view can receive the focus while 3178 * in touch mode. 3179 * 3180 * @see #setFocusable(boolean) 3181 * @attr ref android.R.styleable#View_focusableInTouchMode 3182 */ setFocusableInTouchMode(boolean focusableInTouchMode)3183 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 3184 // Focusable in touch mode should always be set before the focusable flag 3185 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 3186 // which, in touch mode, will not successfully request focus on this view 3187 // because the focusable in touch mode flag is not set 3188 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 3189 if (focusableInTouchMode) { 3190 setFlags(FOCUSABLE, FOCUSABLE_MASK); 3191 } 3192 } 3193 3194 /** 3195 * Set whether this view should have sound effects enabled for events such as 3196 * clicking and touching. 3197 * 3198 * <p>You may wish to disable sound effects for a view if you already play sounds, 3199 * for instance, a dial key that plays dtmf tones. 3200 * 3201 * @param soundEffectsEnabled whether sound effects are enabled for this view. 3202 * @see #isSoundEffectsEnabled() 3203 * @see #playSoundEffect(int) 3204 * @attr ref android.R.styleable#View_soundEffectsEnabled 3205 */ setSoundEffectsEnabled(boolean soundEffectsEnabled)3206 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 3207 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 3208 } 3209 3210 /** 3211 * @return whether this view should have sound effects enabled for events such as 3212 * clicking and touching. 3213 * 3214 * @see #setSoundEffectsEnabled(boolean) 3215 * @see #playSoundEffect(int) 3216 * @attr ref android.R.styleable#View_soundEffectsEnabled 3217 */ 3218 @ViewDebug.ExportedProperty isSoundEffectsEnabled()3219 public boolean isSoundEffectsEnabled() { 3220 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 3221 } 3222 3223 /** 3224 * Set whether this view should have haptic feedback for events such as 3225 * long presses. 3226 * 3227 * <p>You may wish to disable haptic feedback if your view already controls 3228 * its own haptic feedback. 3229 * 3230 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 3231 * @see #isHapticFeedbackEnabled() 3232 * @see #performHapticFeedback(int) 3233 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 3234 */ setHapticFeedbackEnabled(boolean hapticFeedbackEnabled)3235 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 3236 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 3237 } 3238 3239 /** 3240 * @return whether this view should have haptic feedback enabled for events 3241 * long presses. 3242 * 3243 * @see #setHapticFeedbackEnabled(boolean) 3244 * @see #performHapticFeedback(int) 3245 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 3246 */ 3247 @ViewDebug.ExportedProperty isHapticFeedbackEnabled()3248 public boolean isHapticFeedbackEnabled() { 3249 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 3250 } 3251 3252 /** 3253 * If this view doesn't do any drawing on its own, set this flag to 3254 * allow further optimizations. By default, this flag is not set on 3255 * View, but could be set on some View subclasses such as ViewGroup. 3256 * 3257 * Typically, if you override {@link #onDraw} you should clear this flag. 3258 * 3259 * @param willNotDraw whether or not this View draw on its own 3260 */ setWillNotDraw(boolean willNotDraw)3261 public void setWillNotDraw(boolean willNotDraw) { 3262 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 3263 } 3264 3265 /** 3266 * Returns whether or not this View draws on its own. 3267 * 3268 * @return true if this view has nothing to draw, false otherwise 3269 */ 3270 @ViewDebug.ExportedProperty(category = "drawing") willNotDraw()3271 public boolean willNotDraw() { 3272 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 3273 } 3274 3275 /** 3276 * When a View's drawing cache is enabled, drawing is redirected to an 3277 * offscreen bitmap. Some views, like an ImageView, must be able to 3278 * bypass this mechanism if they already draw a single bitmap, to avoid 3279 * unnecessary usage of the memory. 3280 * 3281 * @param willNotCacheDrawing true if this view does not cache its 3282 * drawing, false otherwise 3283 */ setWillNotCacheDrawing(boolean willNotCacheDrawing)3284 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 3285 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 3286 } 3287 3288 /** 3289 * Returns whether or not this View can cache its drawing or not. 3290 * 3291 * @return true if this view does not cache its drawing, false otherwise 3292 */ 3293 @ViewDebug.ExportedProperty(category = "drawing") willNotCacheDrawing()3294 public boolean willNotCacheDrawing() { 3295 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 3296 } 3297 3298 /** 3299 * Indicates whether this view reacts to click events or not. 3300 * 3301 * @return true if the view is clickable, false otherwise 3302 * 3303 * @see #setClickable(boolean) 3304 * @attr ref android.R.styleable#View_clickable 3305 */ 3306 @ViewDebug.ExportedProperty isClickable()3307 public boolean isClickable() { 3308 return (mViewFlags & CLICKABLE) == CLICKABLE; 3309 } 3310 3311 /** 3312 * Enables or disables click events for this view. When a view 3313 * is clickable it will change its state to "pressed" on every click. 3314 * Subclasses should set the view clickable to visually react to 3315 * user's clicks. 3316 * 3317 * @param clickable true to make the view clickable, false otherwise 3318 * 3319 * @see #isClickable() 3320 * @attr ref android.R.styleable#View_clickable 3321 */ setClickable(boolean clickable)3322 public void setClickable(boolean clickable) { 3323 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 3324 } 3325 3326 /** 3327 * Indicates whether this view reacts to long click events or not. 3328 * 3329 * @return true if the view is long clickable, false otherwise 3330 * 3331 * @see #setLongClickable(boolean) 3332 * @attr ref android.R.styleable#View_longClickable 3333 */ isLongClickable()3334 public boolean isLongClickable() { 3335 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 3336 } 3337 3338 /** 3339 * Enables or disables long click events for this view. When a view is long 3340 * clickable it reacts to the user holding down the button for a longer 3341 * duration than a tap. This event can either launch the listener or a 3342 * context menu. 3343 * 3344 * @param longClickable true to make the view long clickable, false otherwise 3345 * @see #isLongClickable() 3346 * @attr ref android.R.styleable#View_longClickable 3347 */ setLongClickable(boolean longClickable)3348 public void setLongClickable(boolean longClickable) { 3349 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 3350 } 3351 3352 /** 3353 * Sets the pressed that for this view. 3354 * 3355 * @see #isClickable() 3356 * @see #setClickable(boolean) 3357 * 3358 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 3359 * the View's internal state from a previously set "pressed" state. 3360 */ setPressed(boolean pressed)3361 public void setPressed(boolean pressed) { 3362 if (pressed) { 3363 mPrivateFlags |= PRESSED; 3364 } else { 3365 mPrivateFlags &= ~PRESSED; 3366 } 3367 refreshDrawableState(); 3368 dispatchSetPressed(pressed); 3369 } 3370 3371 /** 3372 * Dispatch setPressed to all of this View's children. 3373 * 3374 * @see #setPressed(boolean) 3375 * 3376 * @param pressed The new pressed state 3377 */ dispatchSetPressed(boolean pressed)3378 protected void dispatchSetPressed(boolean pressed) { 3379 } 3380 3381 /** 3382 * Indicates whether the view is currently in pressed state. Unless 3383 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 3384 * the pressed state. 3385 * 3386 * @see #setPressed 3387 * @see #isClickable() 3388 * @see #setClickable(boolean) 3389 * 3390 * @return true if the view is currently pressed, false otherwise 3391 */ isPressed()3392 public boolean isPressed() { 3393 return (mPrivateFlags & PRESSED) == PRESSED; 3394 } 3395 3396 /** 3397 * Indicates whether this view will save its state (that is, 3398 * whether its {@link #onSaveInstanceState} method will be called). 3399 * 3400 * @return Returns true if the view state saving is enabled, else false. 3401 * 3402 * @see #setSaveEnabled(boolean) 3403 * @attr ref android.R.styleable#View_saveEnabled 3404 */ isSaveEnabled()3405 public boolean isSaveEnabled() { 3406 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 3407 } 3408 3409 /** 3410 * Controls whether the saving of this view's state is 3411 * enabled (that is, whether its {@link #onSaveInstanceState} method 3412 * will be called). Note that even if freezing is enabled, the 3413 * view still must have an id assigned to it (via {@link #setId setId()}) 3414 * for its state to be saved. This flag can only disable the 3415 * saving of this view; any child views may still have their state saved. 3416 * 3417 * @param enabled Set to false to <em>disable</em> state saving, or true 3418 * (the default) to allow it. 3419 * 3420 * @see #isSaveEnabled() 3421 * @see #setId(int) 3422 * @see #onSaveInstanceState() 3423 * @attr ref android.R.styleable#View_saveEnabled 3424 */ setSaveEnabled(boolean enabled)3425 public void setSaveEnabled(boolean enabled) { 3426 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 3427 } 3428 3429 /** 3430 * Gets whether the framework should discard touches when the view's 3431 * window is obscured by another visible window. 3432 * Refer to the {@link View} security documentation for more details. 3433 * 3434 * @return True if touch filtering is enabled. 3435 * 3436 * @see #setFilterTouchesWhenObscured(boolean) 3437 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 3438 */ 3439 @ViewDebug.ExportedProperty getFilterTouchesWhenObscured()3440 public boolean getFilterTouchesWhenObscured() { 3441 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 3442 } 3443 3444 /** 3445 * Sets whether the framework should discard touches when the view's 3446 * window is obscured by another visible window. 3447 * Refer to the {@link View} security documentation for more details. 3448 * 3449 * @param enabled True if touch filtering should be enabled. 3450 * 3451 * @see #getFilterTouchesWhenObscured 3452 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 3453 */ setFilterTouchesWhenObscured(boolean enabled)3454 public void setFilterTouchesWhenObscured(boolean enabled) { 3455 setFlags(enabled ? 0 : FILTER_TOUCHES_WHEN_OBSCURED, 3456 FILTER_TOUCHES_WHEN_OBSCURED); 3457 } 3458 3459 /** 3460 * Returns whether this View is able to take focus. 3461 * 3462 * @return True if this view can take focus, or false otherwise. 3463 * @attr ref android.R.styleable#View_focusable 3464 */ 3465 @ViewDebug.ExportedProperty(category = "focus") isFocusable()3466 public final boolean isFocusable() { 3467 return FOCUSABLE == (mViewFlags & FOCUSABLE_MASK); 3468 } 3469 3470 /** 3471 * When a view is focusable, it may not want to take focus when in touch mode. 3472 * For example, a button would like focus when the user is navigating via a D-pad 3473 * so that the user can click on it, but once the user starts touching the screen, 3474 * the button shouldn't take focus 3475 * @return Whether the view is focusable in touch mode. 3476 * @attr ref android.R.styleable#View_focusableInTouchMode 3477 */ 3478 @ViewDebug.ExportedProperty isFocusableInTouchMode()3479 public final boolean isFocusableInTouchMode() { 3480 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 3481 } 3482 3483 /** 3484 * Find the nearest view in the specified direction that can take focus. 3485 * This does not actually give focus to that view. 3486 * 3487 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 3488 * 3489 * @return The nearest focusable in the specified direction, or null if none 3490 * can be found. 3491 */ focusSearch(int direction)3492 public View focusSearch(int direction) { 3493 if (mParent != null) { 3494 return mParent.focusSearch(this, direction); 3495 } else { 3496 return null; 3497 } 3498 } 3499 3500 /** 3501 * This method is the last chance for the focused view and its ancestors to 3502 * respond to an arrow key. This is called when the focused view did not 3503 * consume the key internally, nor could the view system find a new view in 3504 * the requested direction to give focus to. 3505 * 3506 * @param focused The currently focused view. 3507 * @param direction The direction focus wants to move. One of FOCUS_UP, 3508 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 3509 * @return True if the this view consumed this unhandled move. 3510 */ dispatchUnhandledMove(View focused, int direction)3511 public boolean dispatchUnhandledMove(View focused, int direction) { 3512 return false; 3513 } 3514 3515 /** 3516 * If a user manually specified the next view id for a particular direction, 3517 * use the root to look up the view. Once a view is found, it is cached 3518 * for future lookups. 3519 * @param root The root view of the hierarchy containing this view. 3520 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 3521 * @return The user specified next view, or null if there is none. 3522 */ findUserSetNextFocus(View root, int direction)3523 View findUserSetNextFocus(View root, int direction) { 3524 switch (direction) { 3525 case FOCUS_LEFT: 3526 if (mNextFocusLeftId == View.NO_ID) return null; 3527 return findViewShouldExist(root, mNextFocusLeftId); 3528 case FOCUS_RIGHT: 3529 if (mNextFocusRightId == View.NO_ID) return null; 3530 return findViewShouldExist(root, mNextFocusRightId); 3531 case FOCUS_UP: 3532 if (mNextFocusUpId == View.NO_ID) return null; 3533 return findViewShouldExist(root, mNextFocusUpId); 3534 case FOCUS_DOWN: 3535 if (mNextFocusDownId == View.NO_ID) return null; 3536 return findViewShouldExist(root, mNextFocusDownId); 3537 } 3538 return null; 3539 } 3540 findViewShouldExist(View root, int childViewId)3541 private static View findViewShouldExist(View root, int childViewId) { 3542 View result = root.findViewById(childViewId); 3543 if (result == null) { 3544 Log.w(VIEW_LOG_TAG, "couldn't find next focus view specified " 3545 + "by user for id " + childViewId); 3546 } 3547 return result; 3548 } 3549 3550 /** 3551 * Find and return all focusable views that are descendants of this view, 3552 * possibly including this view if it is focusable itself. 3553 * 3554 * @param direction The direction of the focus 3555 * @return A list of focusable views 3556 */ getFocusables(int direction)3557 public ArrayList<View> getFocusables(int direction) { 3558 ArrayList<View> result = new ArrayList<View>(24); 3559 addFocusables(result, direction); 3560 return result; 3561 } 3562 3563 /** 3564 * Add any focusable views that are descendants of this view (possibly 3565 * including this view if it is focusable itself) to views. If we are in touch mode, 3566 * only add views that are also focusable in touch mode. 3567 * 3568 * @param views Focusable views found so far 3569 * @param direction The direction of the focus 3570 */ addFocusables(ArrayList<View> views, int direction)3571 public void addFocusables(ArrayList<View> views, int direction) { 3572 addFocusables(views, direction, FOCUSABLES_TOUCH_MODE); 3573 } 3574 3575 /** 3576 * Adds any focusable views that are descendants of this view (possibly 3577 * including this view if it is focusable itself) to views. This method 3578 * adds all focusable views regardless if we are in touch mode or 3579 * only views focusable in touch mode if we are in touch mode depending on 3580 * the focusable mode paramater. 3581 * 3582 * @param views Focusable views found so far or null if all we are interested is 3583 * the number of focusables. 3584 * @param direction The direction of the focus. 3585 * @param focusableMode The type of focusables to be added. 3586 * 3587 * @see #FOCUSABLES_ALL 3588 * @see #FOCUSABLES_TOUCH_MODE 3589 */ addFocusables(ArrayList<View> views, int direction, int focusableMode)3590 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 3591 if (!isFocusable()) { 3592 return; 3593 } 3594 3595 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && 3596 isInTouchMode() && !isFocusableInTouchMode()) { 3597 return; 3598 } 3599 3600 if (views != null) { 3601 views.add(this); 3602 } 3603 } 3604 3605 /** 3606 * Find and return all touchable views that are descendants of this view, 3607 * possibly including this view if it is touchable itself. 3608 * 3609 * @return A list of touchable views 3610 */ getTouchables()3611 public ArrayList<View> getTouchables() { 3612 ArrayList<View> result = new ArrayList<View>(); 3613 addTouchables(result); 3614 return result; 3615 } 3616 3617 /** 3618 * Add any touchable views that are descendants of this view (possibly 3619 * including this view if it is touchable itself) to views. 3620 * 3621 * @param views Touchable views found so far 3622 */ addTouchables(ArrayList<View> views)3623 public void addTouchables(ArrayList<View> views) { 3624 final int viewFlags = mViewFlags; 3625 3626 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 3627 && (viewFlags & ENABLED_MASK) == ENABLED) { 3628 views.add(this); 3629 } 3630 } 3631 3632 /** 3633 * Call this to try to give focus to a specific view or to one of its 3634 * descendants. 3635 * 3636 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns false), 3637 * or if it is focusable and it is not focusable in touch mode ({@link #isFocusableInTouchMode}) 3638 * while the device is in touch mode. 3639 * 3640 * See also {@link #focusSearch}, which is what you call to say that you 3641 * have focus, and you want your parent to look for the next one. 3642 * 3643 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 3644 * {@link #FOCUS_DOWN} and <code>null</code>. 3645 * 3646 * @return Whether this view or one of its descendants actually took focus. 3647 */ requestFocus()3648 public final boolean requestFocus() { 3649 return requestFocus(View.FOCUS_DOWN); 3650 } 3651 3652 3653 /** 3654 * Call this to try to give focus to a specific view or to one of its 3655 * descendants and give it a hint about what direction focus is heading. 3656 * 3657 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns false), 3658 * or if it is focusable and it is not focusable in touch mode ({@link #isFocusableInTouchMode}) 3659 * while the device is in touch mode. 3660 * 3661 * See also {@link #focusSearch}, which is what you call to say that you 3662 * have focus, and you want your parent to look for the next one. 3663 * 3664 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 3665 * <code>null</code> set for the previously focused rectangle. 3666 * 3667 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 3668 * @return Whether this view or one of its descendants actually took focus. 3669 */ requestFocus(int direction)3670 public final boolean requestFocus(int direction) { 3671 return requestFocus(direction, null); 3672 } 3673 3674 /** 3675 * Call this to try to give focus to a specific view or to one of its descendants 3676 * and give it hints about the direction and a specific rectangle that the focus 3677 * is coming from. The rectangle can help give larger views a finer grained hint 3678 * about where focus is coming from, and therefore, where to show selection, or 3679 * forward focus change internally. 3680 * 3681 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns false), 3682 * or if it is focusable and it is not focusable in touch mode ({@link #isFocusableInTouchMode}) 3683 * while the device is in touch mode. 3684 * 3685 * A View will not take focus if it is not visible. 3686 * 3687 * A View will not take focus if one of its parents has {@link android.view.ViewGroup#getDescendantFocusability()} 3688 * equal to {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 3689 * 3690 * See also {@link #focusSearch}, which is what you call to say that you 3691 * have focus, and you want your parent to look for the next one. 3692 * 3693 * You may wish to override this method if your custom {@link View} has an internal 3694 * {@link View} that it wishes to forward the request to. 3695 * 3696 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 3697 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 3698 * to give a finer grained hint about where focus is coming from. May be null 3699 * if there is no hint. 3700 * @return Whether this view or one of its descendants actually took focus. 3701 */ requestFocus(int direction, Rect previouslyFocusedRect)3702 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 3703 // need to be focusable 3704 if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE || 3705 (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 3706 return false; 3707 } 3708 3709 // need to be focusable in touch mode if in touch mode 3710 if (isInTouchMode() && 3711 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 3712 return false; 3713 } 3714 3715 // need to not have any parents blocking us 3716 if (hasAncestorThatBlocksDescendantFocus()) { 3717 return false; 3718 } 3719 3720 handleFocusGainInternal(direction, previouslyFocusedRect); 3721 return true; 3722 } 3723 3724 /** 3725 * Call this to try to give focus to a specific view or to one of its descendants. This is a 3726 * special variant of {@link #requestFocus() } that will allow views that are not focuable in 3727 * touch mode to request focus when they are touched. 3728 * 3729 * @return Whether this view or one of its descendants actually took focus. 3730 * 3731 * @see #isInTouchMode() 3732 * 3733 */ requestFocusFromTouch()3734 public final boolean requestFocusFromTouch() { 3735 // Leave touch mode if we need to 3736 if (isInTouchMode()) { 3737 View root = getRootView(); 3738 if (root != null) { 3739 ViewRoot viewRoot = (ViewRoot)root.getParent(); 3740 if (viewRoot != null) { 3741 viewRoot.ensureTouchMode(false); 3742 } 3743 } 3744 } 3745 return requestFocus(View.FOCUS_DOWN); 3746 } 3747 3748 /** 3749 * @return Whether any ancestor of this view blocks descendant focus. 3750 */ hasAncestorThatBlocksDescendantFocus()3751 private boolean hasAncestorThatBlocksDescendantFocus() { 3752 ViewParent ancestor = mParent; 3753 while (ancestor instanceof ViewGroup) { 3754 final ViewGroup vgAncestor = (ViewGroup) ancestor; 3755 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS) { 3756 return true; 3757 } else { 3758 ancestor = vgAncestor.getParent(); 3759 } 3760 } 3761 return false; 3762 } 3763 3764 /** 3765 * @hide 3766 */ dispatchStartTemporaryDetach()3767 public void dispatchStartTemporaryDetach() { 3768 onStartTemporaryDetach(); 3769 } 3770 3771 /** 3772 * This is called when a container is going to temporarily detach a child, with 3773 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 3774 * It will either be followed by {@link #onFinishTemporaryDetach()} or 3775 * {@link #onDetachedFromWindow()} when the container is done. 3776 */ onStartTemporaryDetach()3777 public void onStartTemporaryDetach() { 3778 removeUnsetPressCallback(); 3779 mPrivateFlags |= CANCEL_NEXT_UP_EVENT; 3780 } 3781 3782 /** 3783 * @hide 3784 */ dispatchFinishTemporaryDetach()3785 public void dispatchFinishTemporaryDetach() { 3786 onFinishTemporaryDetach(); 3787 } 3788 3789 /** 3790 * Called after {@link #onStartTemporaryDetach} when the container is done 3791 * changing the view. 3792 */ onFinishTemporaryDetach()3793 public void onFinishTemporaryDetach() { 3794 } 3795 3796 /** 3797 * capture information of this view for later analysis: developement only 3798 * check dynamic switch to make sure we only dump view 3799 * when ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW) is set 3800 */ captureViewInfo(String subTag, View v)3801 private static void captureViewInfo(String subTag, View v) { 3802 if (v == null || SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW, 0) == 0) { 3803 return; 3804 } 3805 ViewDebug.dumpCapturedView(subTag, v); 3806 } 3807 3808 /** 3809 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 3810 * for this view's window. Returns null if the view is not currently attached 3811 * to the window. Normally you will not need to use this directly, but 3812 * just use the standard high-level event callbacks like {@link #onKeyDown}. 3813 */ getKeyDispatcherState()3814 public KeyEvent.DispatcherState getKeyDispatcherState() { 3815 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 3816 } 3817 3818 /** 3819 * Dispatch a key event before it is processed by any input method 3820 * associated with the view hierarchy. This can be used to intercept 3821 * key events in special situations before the IME consumes them; a 3822 * typical example would be handling the BACK key to update the application's 3823 * UI instead of allowing the IME to see it and close itself. 3824 * 3825 * @param event The key event to be dispatched. 3826 * @return True if the event was handled, false otherwise. 3827 */ dispatchKeyEventPreIme(KeyEvent event)3828 public boolean dispatchKeyEventPreIme(KeyEvent event) { 3829 return onKeyPreIme(event.getKeyCode(), event); 3830 } 3831 3832 /** 3833 * Dispatch a key event to the next view on the focus path. This path runs 3834 * from the top of the view tree down to the currently focused view. If this 3835 * view has focus, it will dispatch to itself. Otherwise it will dispatch 3836 * the next node down the focus path. This method also fires any key 3837 * listeners. 3838 * 3839 * @param event The key event to be dispatched. 3840 * @return True if the event was handled, false otherwise. 3841 */ dispatchKeyEvent(KeyEvent event)3842 public boolean dispatchKeyEvent(KeyEvent event) { 3843 // If any attached key listener a first crack at the event. 3844 //noinspection SimplifiableIfStatement 3845 3846 if (android.util.Config.LOGV) { 3847 captureViewInfo("captureViewKeyEvent", this); 3848 } 3849 3850 if (mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 3851 && mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 3852 return true; 3853 } 3854 3855 return event.dispatch(this, mAttachInfo != null 3856 ? mAttachInfo.mKeyDispatchState : null, this); 3857 } 3858 3859 /** 3860 * Dispatches a key shortcut event. 3861 * 3862 * @param event The key event to be dispatched. 3863 * @return True if the event was handled by the view, false otherwise. 3864 */ dispatchKeyShortcutEvent(KeyEvent event)3865 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 3866 return onKeyShortcut(event.getKeyCode(), event); 3867 } 3868 3869 /** 3870 * Pass the touch screen motion event down to the target view, or this 3871 * view if it is the target. 3872 * 3873 * @param event The motion event to be dispatched. 3874 * @return True if the event was handled by the view, false otherwise. 3875 */ dispatchTouchEvent(MotionEvent event)3876 public boolean dispatchTouchEvent(MotionEvent event) { 3877 if (!onFilterTouchEventForSecurity(event)) { 3878 return false; 3879 } 3880 3881 if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && 3882 mOnTouchListener.onTouch(this, event)) { 3883 return true; 3884 } 3885 return onTouchEvent(event); 3886 } 3887 3888 /** 3889 * Filter the touch event to apply security policies. 3890 * 3891 * @param event The motion event to be filtered. 3892 * @return True if the event should be dispatched, false if the event should be dropped. 3893 * 3894 * @see #getFilterTouchesWhenObscured 3895 */ onFilterTouchEventForSecurity(MotionEvent event)3896 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 3897 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 3898 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 3899 // Window is obscured, drop this touch. 3900 return false; 3901 } 3902 return true; 3903 } 3904 3905 /** 3906 * Pass a trackball motion event down to the focused view. 3907 * 3908 * @param event The motion event to be dispatched. 3909 * @return True if the event was handled by the view, false otherwise. 3910 */ dispatchTrackballEvent(MotionEvent event)3911 public boolean dispatchTrackballEvent(MotionEvent event) { 3912 //Log.i("view", "view=" + this + ", " + event.toString()); 3913 return onTrackballEvent(event); 3914 } 3915 3916 /** 3917 * Called when the window containing this view gains or loses window focus. 3918 * ViewGroups should override to route to their children. 3919 * 3920 * @param hasFocus True if the window containing this view now has focus, 3921 * false otherwise. 3922 */ dispatchWindowFocusChanged(boolean hasFocus)3923 public void dispatchWindowFocusChanged(boolean hasFocus) { 3924 onWindowFocusChanged(hasFocus); 3925 } 3926 3927 /** 3928 * Called when the window containing this view gains or loses focus. Note 3929 * that this is separate from view focus: to receive key events, both 3930 * your view and its window must have focus. If a window is displayed 3931 * on top of yours that takes input focus, then your own window will lose 3932 * focus but the view focus will remain unchanged. 3933 * 3934 * @param hasWindowFocus True if the window containing this view now has 3935 * focus, false otherwise. 3936 */ onWindowFocusChanged(boolean hasWindowFocus)3937 public void onWindowFocusChanged(boolean hasWindowFocus) { 3938 InputMethodManager imm = InputMethodManager.peekInstance(); 3939 if (!hasWindowFocus) { 3940 if (isPressed()) { 3941 setPressed(false); 3942 } 3943 if (imm != null && (mPrivateFlags & FOCUSED) != 0) { 3944 imm.focusOut(this); 3945 } 3946 removeLongPressCallback(); 3947 onFocusLost(); 3948 } else if (imm != null && (mPrivateFlags & FOCUSED) != 0) { 3949 imm.focusIn(this); 3950 } 3951 refreshDrawableState(); 3952 } 3953 3954 /** 3955 * Returns true if this view is in a window that currently has window focus. 3956 * Note that this is not the same as the view itself having focus. 3957 * 3958 * @return True if this view is in a window that currently has window focus. 3959 */ hasWindowFocus()3960 public boolean hasWindowFocus() { 3961 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 3962 } 3963 3964 /** 3965 * Dispatch a view visibility change down the view hierarchy. 3966 * ViewGroups should override to route to their children. 3967 * @param changedView The view whose visibility changed. Could be 'this' or 3968 * an ancestor view. 3969 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 3970 * {@link #INVISIBLE} or {@link #GONE}. 3971 */ dispatchVisibilityChanged(View changedView, int visibility)3972 protected void dispatchVisibilityChanged(View changedView, int visibility) { 3973 onVisibilityChanged(changedView, visibility); 3974 } 3975 3976 /** 3977 * Called when the visibility of the view or an ancestor of the view is changed. 3978 * @param changedView The view whose visibility changed. Could be 'this' or 3979 * an ancestor view. 3980 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 3981 * {@link #INVISIBLE} or {@link #GONE}. 3982 */ onVisibilityChanged(View changedView, int visibility)3983 protected void onVisibilityChanged(View changedView, int visibility) { 3984 if (visibility == VISIBLE) { 3985 if (mAttachInfo != null) { 3986 initialAwakenScrollBars(); 3987 } else { 3988 mPrivateFlags |= AWAKEN_SCROLL_BARS_ON_ATTACH; 3989 } 3990 } 3991 } 3992 3993 /** 3994 * Dispatch a hint about whether this view is displayed. For instance, when 3995 * a View moves out of the screen, it might receives a display hint indicating 3996 * the view is not displayed. Applications should not <em>rely</em> on this hint 3997 * as there is no guarantee that they will receive one. 3998 * 3999 * @param hint A hint about whether or not this view is displayed: 4000 * {@link #VISIBLE} or {@link #INVISIBLE}. 4001 */ dispatchDisplayHint(int hint)4002 public void dispatchDisplayHint(int hint) { 4003 onDisplayHint(hint); 4004 } 4005 4006 /** 4007 * Gives this view a hint about whether is displayed or not. For instance, when 4008 * a View moves out of the screen, it might receives a display hint indicating 4009 * the view is not displayed. Applications should not <em>rely</em> on this hint 4010 * as there is no guarantee that they will receive one. 4011 * 4012 * @param hint A hint about whether or not this view is displayed: 4013 * {@link #VISIBLE} or {@link #INVISIBLE}. 4014 */ onDisplayHint(int hint)4015 protected void onDisplayHint(int hint) { 4016 } 4017 4018 /** 4019 * Dispatch a window visibility change down the view hierarchy. 4020 * ViewGroups should override to route to their children. 4021 * 4022 * @param visibility The new visibility of the window. 4023 * 4024 * @see #onWindowVisibilityChanged 4025 */ dispatchWindowVisibilityChanged(int visibility)4026 public void dispatchWindowVisibilityChanged(int visibility) { 4027 onWindowVisibilityChanged(visibility); 4028 } 4029 4030 /** 4031 * Called when the window containing has change its visibility 4032 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 4033 * that this tells you whether or not your window is being made visible 4034 * to the window manager; this does <em>not</em> tell you whether or not 4035 * your window is obscured by other windows on the screen, even if it 4036 * is itself visible. 4037 * 4038 * @param visibility The new visibility of the window. 4039 */ onWindowVisibilityChanged(int visibility)4040 protected void onWindowVisibilityChanged(int visibility) { 4041 if (visibility == VISIBLE) { 4042 initialAwakenScrollBars(); 4043 } 4044 } 4045 4046 /** 4047 * Returns the current visibility of the window this view is attached to 4048 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 4049 * 4050 * @return Returns the current visibility of the view's window. 4051 */ getWindowVisibility()4052 public int getWindowVisibility() { 4053 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 4054 } 4055 4056 /** 4057 * Retrieve the overall visible display size in which the window this view is 4058 * attached to has been positioned in. This takes into account screen 4059 * decorations above the window, for both cases where the window itself 4060 * is being position inside of them or the window is being placed under 4061 * then and covered insets are used for the window to position its content 4062 * inside. In effect, this tells you the available area where content can 4063 * be placed and remain visible to users. 4064 * 4065 * <p>This function requires an IPC back to the window manager to retrieve 4066 * the requested information, so should not be used in performance critical 4067 * code like drawing. 4068 * 4069 * @param outRect Filled in with the visible display frame. If the view 4070 * is not attached to a window, this is simply the raw display size. 4071 */ getWindowVisibleDisplayFrame(Rect outRect)4072 public void getWindowVisibleDisplayFrame(Rect outRect) { 4073 if (mAttachInfo != null) { 4074 try { 4075 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 4076 } catch (RemoteException e) { 4077 return; 4078 } 4079 // XXX This is really broken, and probably all needs to be done 4080 // in the window manager, and we need to know more about whether 4081 // we want the area behind or in front of the IME. 4082 final Rect insets = mAttachInfo.mVisibleInsets; 4083 outRect.left += insets.left; 4084 outRect.top += insets.top; 4085 outRect.right -= insets.right; 4086 outRect.bottom -= insets.bottom; 4087 return; 4088 } 4089 Display d = WindowManagerImpl.getDefault().getDefaultDisplay(); 4090 outRect.set(0, 0, d.getWidth(), d.getHeight()); 4091 } 4092 4093 /** 4094 * Dispatch a notification about a resource configuration change down 4095 * the view hierarchy. 4096 * ViewGroups should override to route to their children. 4097 * 4098 * @param newConfig The new resource configuration. 4099 * 4100 * @see #onConfigurationChanged 4101 */ dispatchConfigurationChanged(Configuration newConfig)4102 public void dispatchConfigurationChanged(Configuration newConfig) { 4103 onConfigurationChanged(newConfig); 4104 } 4105 4106 /** 4107 * Called when the current configuration of the resources being used 4108 * by the application have changed. You can use this to decide when 4109 * to reload resources that can changed based on orientation and other 4110 * configuration characterstics. You only need to use this if you are 4111 * not relying on the normal {@link android.app.Activity} mechanism of 4112 * recreating the activity instance upon a configuration change. 4113 * 4114 * @param newConfig The new resource configuration. 4115 */ onConfigurationChanged(Configuration newConfig)4116 protected void onConfigurationChanged(Configuration newConfig) { 4117 } 4118 4119 /** 4120 * Private function to aggregate all per-view attributes in to the view 4121 * root. 4122 */ dispatchCollectViewAttributes(int visibility)4123 void dispatchCollectViewAttributes(int visibility) { 4124 performCollectViewAttributes(visibility); 4125 } 4126 performCollectViewAttributes(int visibility)4127 void performCollectViewAttributes(int visibility) { 4128 //noinspection PointlessBitwiseExpression 4129 if (((visibility | mViewFlags) & (VISIBILITY_MASK | KEEP_SCREEN_ON)) 4130 == (VISIBLE | KEEP_SCREEN_ON)) { 4131 mAttachInfo.mKeepScreenOn = true; 4132 } 4133 } 4134 needGlobalAttributesUpdate(boolean force)4135 void needGlobalAttributesUpdate(boolean force) { 4136 AttachInfo ai = mAttachInfo; 4137 if (ai != null) { 4138 if (ai.mKeepScreenOn || force) { 4139 ai.mRecomputeGlobalAttributes = true; 4140 } 4141 } 4142 } 4143 4144 /** 4145 * Returns whether the device is currently in touch mode. Touch mode is entered 4146 * once the user begins interacting with the device by touch, and affects various 4147 * things like whether focus is always visible to the user. 4148 * 4149 * @return Whether the device is in touch mode. 4150 */ 4151 @ViewDebug.ExportedProperty isInTouchMode()4152 public boolean isInTouchMode() { 4153 if (mAttachInfo != null) { 4154 return mAttachInfo.mInTouchMode; 4155 } else { 4156 return ViewRoot.isInTouchMode(); 4157 } 4158 } 4159 4160 /** 4161 * Returns the context the view is running in, through which it can 4162 * access the current theme, resources, etc. 4163 * 4164 * @return The view's Context. 4165 */ 4166 @ViewDebug.CapturedViewProperty getContext()4167 public final Context getContext() { 4168 return mContext; 4169 } 4170 4171 /** 4172 * Handle a key event before it is processed by any input method 4173 * associated with the view hierarchy. This can be used to intercept 4174 * key events in special situations before the IME consumes them; a 4175 * typical example would be handling the BACK key to update the application's 4176 * UI instead of allowing the IME to see it and close itself. 4177 * 4178 * @param keyCode The value in event.getKeyCode(). 4179 * @param event Description of the key event. 4180 * @return If you handled the event, return true. If you want to allow the 4181 * event to be handled by the next receiver, return false. 4182 */ onKeyPreIme(int keyCode, KeyEvent event)4183 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 4184 return false; 4185 } 4186 4187 /** 4188 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 4189 * KeyEvent.Callback.onKeyMultiple()}: perform press of the view 4190 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 4191 * is released, if the view is enabled and clickable. 4192 * 4193 * @param keyCode A key code that represents the button pressed, from 4194 * {@link android.view.KeyEvent}. 4195 * @param event The KeyEvent object that defines the button action. 4196 */ onKeyDown(int keyCode, KeyEvent event)4197 public boolean onKeyDown(int keyCode, KeyEvent event) { 4198 boolean result = false; 4199 4200 switch (keyCode) { 4201 case KeyEvent.KEYCODE_DPAD_CENTER: 4202 case KeyEvent.KEYCODE_ENTER: { 4203 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 4204 return true; 4205 } 4206 // Long clickable items don't necessarily have to be clickable 4207 if (((mViewFlags & CLICKABLE) == CLICKABLE || 4208 (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) && 4209 (event.getRepeatCount() == 0)) { 4210 setPressed(true); 4211 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) { 4212 postCheckForLongClick(0); 4213 } 4214 return true; 4215 } 4216 break; 4217 } 4218 } 4219 return result; 4220 } 4221 4222 /** 4223 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 4224 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 4225 * the event). 4226 */ onKeyLongPress(int keyCode, KeyEvent event)4227 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 4228 return false; 4229 } 4230 4231 /** 4232 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 4233 * KeyEvent.Callback.onKeyMultiple()}: perform clicking of the view 4234 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or 4235 * {@link KeyEvent#KEYCODE_ENTER} is released. 4236 * 4237 * @param keyCode A key code that represents the button pressed, from 4238 * {@link android.view.KeyEvent}. 4239 * @param event The KeyEvent object that defines the button action. 4240 */ onKeyUp(int keyCode, KeyEvent event)4241 public boolean onKeyUp(int keyCode, KeyEvent event) { 4242 boolean result = false; 4243 4244 switch (keyCode) { 4245 case KeyEvent.KEYCODE_DPAD_CENTER: 4246 case KeyEvent.KEYCODE_ENTER: { 4247 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 4248 return true; 4249 } 4250 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 4251 setPressed(false); 4252 4253 if (!mHasPerformedLongPress) { 4254 // This is a tap, so remove the longpress check 4255 removeLongPressCallback(); 4256 4257 result = performClick(); 4258 } 4259 } 4260 break; 4261 } 4262 } 4263 return result; 4264 } 4265 4266 /** 4267 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 4268 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 4269 * the event). 4270 * 4271 * @param keyCode A key code that represents the button pressed, from 4272 * {@link android.view.KeyEvent}. 4273 * @param repeatCount The number of times the action was made. 4274 * @param event The KeyEvent object that defines the button action. 4275 */ onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)4276 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 4277 return false; 4278 } 4279 4280 /** 4281 * Called when an unhandled key shortcut event occurs. 4282 * 4283 * @param keyCode The value in event.getKeyCode(). 4284 * @param event Description of the key event. 4285 * @return If you handled the event, return true. If you want to allow the 4286 * event to be handled by the next receiver, return false. 4287 */ onKeyShortcut(int keyCode, KeyEvent event)4288 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 4289 return false; 4290 } 4291 4292 /** 4293 * Check whether the called view is a text editor, in which case it 4294 * would make sense to automatically display a soft input window for 4295 * it. Subclasses should override this if they implement 4296 * {@link #onCreateInputConnection(EditorInfo)} to return true if 4297 * a call on that method would return a non-null InputConnection, and 4298 * they are really a first-class editor that the user would normally 4299 * start typing on when the go into a window containing your view. 4300 * 4301 * <p>The default implementation always returns false. This does 4302 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 4303 * will not be called or the user can not otherwise perform edits on your 4304 * view; it is just a hint to the system that this is not the primary 4305 * purpose of this view. 4306 * 4307 * @return Returns true if this view is a text editor, else false. 4308 */ onCheckIsTextEditor()4309 public boolean onCheckIsTextEditor() { 4310 return false; 4311 } 4312 4313 /** 4314 * Create a new InputConnection for an InputMethod to interact 4315 * with the view. The default implementation returns null, since it doesn't 4316 * support input methods. You can override this to implement such support. 4317 * This is only needed for views that take focus and text input. 4318 * 4319 * <p>When implementing this, you probably also want to implement 4320 * {@link #onCheckIsTextEditor()} to indicate you will return a 4321 * non-null InputConnection. 4322 * 4323 * @param outAttrs Fill in with attribute information about the connection. 4324 */ onCreateInputConnection(EditorInfo outAttrs)4325 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 4326 return null; 4327 } 4328 4329 /** 4330 * Called by the {@link android.view.inputmethod.InputMethodManager} 4331 * when a view who is not the current 4332 * input connection target is trying to make a call on the manager. The 4333 * default implementation returns false; you can override this to return 4334 * true for certain views if you are performing InputConnection proxying 4335 * to them. 4336 * @param view The View that is making the InputMethodManager call. 4337 * @return Return true to allow the call, false to reject. 4338 */ checkInputConnectionProxy(View view)4339 public boolean checkInputConnectionProxy(View view) { 4340 return false; 4341 } 4342 4343 /** 4344 * Show the context menu for this view. It is not safe to hold on to the 4345 * menu after returning from this method. 4346 * 4347 * You should normally not overload this method. Overload 4348 * {@link #onCreateContextMenu(ContextMenu)} or define an 4349 * {@link OnCreateContextMenuListener} to add items to the context menu. 4350 * 4351 * @param menu The context menu to populate 4352 */ createContextMenu(ContextMenu menu)4353 public void createContextMenu(ContextMenu menu) { 4354 ContextMenuInfo menuInfo = getContextMenuInfo(); 4355 4356 // Sets the current menu info so all items added to menu will have 4357 // my extra info set. 4358 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 4359 4360 onCreateContextMenu(menu); 4361 if (mOnCreateContextMenuListener != null) { 4362 mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 4363 } 4364 4365 // Clear the extra information so subsequent items that aren't mine don't 4366 // have my extra info. 4367 ((MenuBuilder)menu).setCurrentMenuInfo(null); 4368 4369 if (mParent != null) { 4370 mParent.createContextMenu(menu); 4371 } 4372 } 4373 4374 /** 4375 * Views should implement this if they have extra information to associate 4376 * with the context menu. The return result is supplied as a parameter to 4377 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 4378 * callback. 4379 * 4380 * @return Extra information about the item for which the context menu 4381 * should be shown. This information will vary across different 4382 * subclasses of View. 4383 */ getContextMenuInfo()4384 protected ContextMenuInfo getContextMenuInfo() { 4385 return null; 4386 } 4387 4388 /** 4389 * Views should implement this if the view itself is going to add items to 4390 * the context menu. 4391 * 4392 * @param menu the context menu to populate 4393 */ onCreateContextMenu(ContextMenu menu)4394 protected void onCreateContextMenu(ContextMenu menu) { 4395 } 4396 4397 /** 4398 * Implement this method to handle trackball motion events. The 4399 * <em>relative</em> movement of the trackball since the last event 4400 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 4401 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 4402 * that a movement of 1 corresponds to the user pressing one DPAD key (so 4403 * they will often be fractional values, representing the more fine-grained 4404 * movement information available from a trackball). 4405 * 4406 * @param event The motion event. 4407 * @return True if the event was handled, false otherwise. 4408 */ onTrackballEvent(MotionEvent event)4409 public boolean onTrackballEvent(MotionEvent event) { 4410 return false; 4411 } 4412 4413 /** 4414 * Implement this method to handle touch screen motion events. 4415 * 4416 * @param event The motion event. 4417 * @return True if the event was handled, false otherwise. 4418 */ onTouchEvent(MotionEvent event)4419 public boolean onTouchEvent(MotionEvent event) { 4420 final int viewFlags = mViewFlags; 4421 4422 if ((viewFlags & ENABLED_MASK) == DISABLED) { 4423 // A disabled view that is clickable still consumes the touch 4424 // events, it just doesn't respond to them. 4425 return (((viewFlags & CLICKABLE) == CLICKABLE || 4426 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); 4427 } 4428 4429 if (mTouchDelegate != null) { 4430 if (mTouchDelegate.onTouchEvent(event)) { 4431 return true; 4432 } 4433 } 4434 4435 if (((viewFlags & CLICKABLE) == CLICKABLE || 4436 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { 4437 switch (event.getAction()) { 4438 case MotionEvent.ACTION_UP: 4439 boolean prepressed = (mPrivateFlags & PREPRESSED) != 0; 4440 if ((mPrivateFlags & PRESSED) != 0 || prepressed) { 4441 // take focus if we don't have it already and we should in 4442 // touch mode. 4443 boolean focusTaken = false; 4444 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 4445 focusTaken = requestFocus(); 4446 } 4447 4448 if (!mHasPerformedLongPress) { 4449 // This is a tap, so remove the longpress check 4450 removeLongPressCallback(); 4451 4452 // Only perform take click actions if we were in the pressed state 4453 if (!focusTaken) { 4454 // Use a Runnable and post this rather than calling 4455 // performClick directly. This lets other visual state 4456 // of the view update before click actions start. 4457 if (mPerformClick == null) { 4458 mPerformClick = new PerformClick(); 4459 } 4460 if (!post(mPerformClick)) { 4461 performClick(); 4462 } 4463 } 4464 } 4465 4466 if (mUnsetPressedState == null) { 4467 mUnsetPressedState = new UnsetPressedState(); 4468 } 4469 4470 if (prepressed) { 4471 mPrivateFlags |= PRESSED; 4472 refreshDrawableState(); 4473 postDelayed(mUnsetPressedState, 4474 ViewConfiguration.getPressedStateDuration()); 4475 } else if (!post(mUnsetPressedState)) { 4476 // If the post failed, unpress right now 4477 mUnsetPressedState.run(); 4478 } 4479 removeTapCallback(); 4480 } 4481 break; 4482 4483 case MotionEvent.ACTION_DOWN: 4484 if (mPendingCheckForTap == null) { 4485 mPendingCheckForTap = new CheckForTap(); 4486 } 4487 mPrivateFlags |= PREPRESSED; 4488 mHasPerformedLongPress = false; 4489 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 4490 break; 4491 4492 case MotionEvent.ACTION_CANCEL: 4493 mPrivateFlags &= ~PRESSED; 4494 refreshDrawableState(); 4495 removeTapCallback(); 4496 break; 4497 4498 case MotionEvent.ACTION_MOVE: 4499 final int x = (int) event.getX(); 4500 final int y = (int) event.getY(); 4501 4502 // Be lenient about moving outside of buttons 4503 int slop = mTouchSlop; 4504 if ((x < 0 - slop) || (x >= getWidth() + slop) || 4505 (y < 0 - slop) || (y >= getHeight() + slop)) { 4506 // Outside button 4507 removeTapCallback(); 4508 if ((mPrivateFlags & PRESSED) != 0) { 4509 // Remove any future long press/tap checks 4510 removeLongPressCallback(); 4511 4512 // Need to switch from pressed to not pressed 4513 mPrivateFlags &= ~PRESSED; 4514 refreshDrawableState(); 4515 } 4516 } 4517 break; 4518 } 4519 return true; 4520 } 4521 4522 return false; 4523 } 4524 4525 /** 4526 * Remove the longpress detection timer. 4527 */ removeLongPressCallback()4528 private void removeLongPressCallback() { 4529 if (mPendingCheckForLongPress != null) { 4530 removeCallbacks(mPendingCheckForLongPress); 4531 } 4532 } 4533 4534 /** 4535 * Remove the prepress detection timer. 4536 */ removeUnsetPressCallback()4537 private void removeUnsetPressCallback() { 4538 if ((mPrivateFlags & PRESSED) != 0 && mUnsetPressedState != null) { 4539 setPressed(false); 4540 removeCallbacks(mUnsetPressedState); 4541 } 4542 } 4543 4544 /** 4545 * Remove the tap detection timer. 4546 */ removeTapCallback()4547 private void removeTapCallback() { 4548 if (mPendingCheckForTap != null) { 4549 mPrivateFlags &= ~PREPRESSED; 4550 removeCallbacks(mPendingCheckForTap); 4551 } 4552 } 4553 4554 /** 4555 * Cancels a pending long press. Your subclass can use this if you 4556 * want the context menu to come up if the user presses and holds 4557 * at the same place, but you don't want it to come up if they press 4558 * and then move around enough to cause scrolling. 4559 */ cancelLongPress()4560 public void cancelLongPress() { 4561 removeLongPressCallback(); 4562 4563 /* 4564 * The prepressed state handled by the tap callback is a display 4565 * construct, but the tap callback will post a long press callback 4566 * less its own timeout. Remove it here. 4567 */ 4568 removeTapCallback(); 4569 } 4570 4571 /** 4572 * Sets the TouchDelegate for this View. 4573 */ setTouchDelegate(TouchDelegate delegate)4574 public void setTouchDelegate(TouchDelegate delegate) { 4575 mTouchDelegate = delegate; 4576 } 4577 4578 /** 4579 * Gets the TouchDelegate for this View. 4580 */ getTouchDelegate()4581 public TouchDelegate getTouchDelegate() { 4582 return mTouchDelegate; 4583 } 4584 4585 /** 4586 * Set flags controlling behavior of this view. 4587 * 4588 * @param flags Constant indicating the value which should be set 4589 * @param mask Constant indicating the bit range that should be changed 4590 */ setFlags(int flags, int mask)4591 void setFlags(int flags, int mask) { 4592 int old = mViewFlags; 4593 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 4594 4595 int changed = mViewFlags ^ old; 4596 if (changed == 0) { 4597 return; 4598 } 4599 int privateFlags = mPrivateFlags; 4600 4601 /* Check if the FOCUSABLE bit has changed */ 4602 if (((changed & FOCUSABLE_MASK) != 0) && 4603 ((privateFlags & HAS_BOUNDS) !=0)) { 4604 if (((old & FOCUSABLE_MASK) == FOCUSABLE) 4605 && ((privateFlags & FOCUSED) != 0)) { 4606 /* Give up focus if we are no longer focusable */ 4607 clearFocus(); 4608 } else if (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE) 4609 && ((privateFlags & FOCUSED) == 0)) { 4610 /* 4611 * Tell the view system that we are now available to take focus 4612 * if no one else already has it. 4613 */ 4614 if (mParent != null) mParent.focusableViewAvailable(this); 4615 } 4616 } 4617 4618 if ((flags & VISIBILITY_MASK) == VISIBLE) { 4619 if ((changed & VISIBILITY_MASK) != 0) { 4620 /* 4621 * If this view is becoming visible, set the DRAWN flag so that 4622 * the next invalidate() will not be skipped. 4623 */ 4624 mPrivateFlags |= DRAWN; 4625 4626 needGlobalAttributesUpdate(true); 4627 4628 // a view becoming visible is worth notifying the parent 4629 // about in case nothing has focus. even if this specific view 4630 // isn't focusable, it may contain something that is, so let 4631 // the root view try to give this focus if nothing else does. 4632 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 4633 mParent.focusableViewAvailable(this); 4634 } 4635 } 4636 } 4637 4638 /* Check if the GONE bit has changed */ 4639 if ((changed & GONE) != 0) { 4640 needGlobalAttributesUpdate(false); 4641 requestLayout(); 4642 invalidate(); 4643 4644 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 4645 if (hasFocus()) clearFocus(); 4646 destroyDrawingCache(); 4647 } 4648 if (mAttachInfo != null) { 4649 mAttachInfo.mViewVisibilityChanged = true; 4650 } 4651 } 4652 4653 /* Check if the VISIBLE bit has changed */ 4654 if ((changed & INVISIBLE) != 0) { 4655 needGlobalAttributesUpdate(false); 4656 invalidate(); 4657 4658 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE) && hasFocus()) { 4659 // root view becoming invisible shouldn't clear focus 4660 if (getRootView() != this) { 4661 clearFocus(); 4662 } 4663 } 4664 if (mAttachInfo != null) { 4665 mAttachInfo.mViewVisibilityChanged = true; 4666 } 4667 } 4668 4669 if ((changed & VISIBILITY_MASK) != 0) { 4670 dispatchVisibilityChanged(this, (flags & VISIBILITY_MASK)); 4671 } 4672 4673 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 4674 destroyDrawingCache(); 4675 } 4676 4677 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 4678 destroyDrawingCache(); 4679 mPrivateFlags &= ~DRAWING_CACHE_VALID; 4680 } 4681 4682 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 4683 destroyDrawingCache(); 4684 mPrivateFlags &= ~DRAWING_CACHE_VALID; 4685 } 4686 4687 if ((changed & DRAW_MASK) != 0) { 4688 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 4689 if (mBGDrawable != null) { 4690 mPrivateFlags &= ~SKIP_DRAW; 4691 mPrivateFlags |= ONLY_DRAWS_BACKGROUND; 4692 } else { 4693 mPrivateFlags |= SKIP_DRAW; 4694 } 4695 } else { 4696 mPrivateFlags &= ~SKIP_DRAW; 4697 } 4698 requestLayout(); 4699 invalidate(); 4700 } 4701 4702 if ((changed & KEEP_SCREEN_ON) != 0) { 4703 if (mParent != null) { 4704 mParent.recomputeViewAttributes(this); 4705 } 4706 } 4707 } 4708 4709 /** 4710 * Change the view's z order in the tree, so it's on top of other sibling 4711 * views 4712 */ bringToFront()4713 public void bringToFront() { 4714 if (mParent != null) { 4715 mParent.bringChildToFront(this); 4716 } 4717 } 4718 4719 /** 4720 * This is called in response to an internal scroll in this view (i.e., the 4721 * view scrolled its own contents). This is typically as a result of 4722 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 4723 * called. 4724 * 4725 * @param l Current horizontal scroll origin. 4726 * @param t Current vertical scroll origin. 4727 * @param oldl Previous horizontal scroll origin. 4728 * @param oldt Previous vertical scroll origin. 4729 */ onScrollChanged(int l, int t, int oldl, int oldt)4730 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 4731 mBackgroundSizeChanged = true; 4732 4733 final AttachInfo ai = mAttachInfo; 4734 if (ai != null) { 4735 ai.mViewScrollChanged = true; 4736 } 4737 } 4738 4739 /** 4740 * This is called during layout when the size of this view has changed. If 4741 * you were just added to the view hierarchy, you're called with the old 4742 * values of 0. 4743 * 4744 * @param w Current width of this view. 4745 * @param h Current height of this view. 4746 * @param oldw Old width of this view. 4747 * @param oldh Old height of this view. 4748 */ onSizeChanged(int w, int h, int oldw, int oldh)4749 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 4750 } 4751 4752 /** 4753 * Called by draw to draw the child views. This may be overridden 4754 * by derived classes to gain control just before its children are drawn 4755 * (but after its own view has been drawn). 4756 * @param canvas the canvas on which to draw the view 4757 */ dispatchDraw(Canvas canvas)4758 protected void dispatchDraw(Canvas canvas) { 4759 } 4760 4761 /** 4762 * Gets the parent of this view. Note that the parent is a 4763 * ViewParent and not necessarily a View. 4764 * 4765 * @return Parent of this view. 4766 */ getParent()4767 public final ViewParent getParent() { 4768 return mParent; 4769 } 4770 4771 /** 4772 * Return the scrolled left position of this view. This is the left edge of 4773 * the displayed part of your view. You do not need to draw any pixels 4774 * farther left, since those are outside of the frame of your view on 4775 * screen. 4776 * 4777 * @return The left edge of the displayed part of your view, in pixels. 4778 */ getScrollX()4779 public final int getScrollX() { 4780 return mScrollX; 4781 } 4782 4783 /** 4784 * Return the scrolled top position of this view. This is the top edge of 4785 * the displayed part of your view. You do not need to draw any pixels above 4786 * it, since those are outside of the frame of your view on screen. 4787 * 4788 * @return The top edge of the displayed part of your view, in pixels. 4789 */ getScrollY()4790 public final int getScrollY() { 4791 return mScrollY; 4792 } 4793 4794 /** 4795 * Return the width of the your view. 4796 * 4797 * @return The width of your view, in pixels. 4798 */ 4799 @ViewDebug.ExportedProperty(category = "layout") getWidth()4800 public final int getWidth() { 4801 return mRight - mLeft; 4802 } 4803 4804 /** 4805 * Return the height of your view. 4806 * 4807 * @return The height of your view, in pixels. 4808 */ 4809 @ViewDebug.ExportedProperty(category = "layout") getHeight()4810 public final int getHeight() { 4811 return mBottom - mTop; 4812 } 4813 4814 /** 4815 * Return the visible drawing bounds of your view. Fills in the output 4816 * rectangle with the values from getScrollX(), getScrollY(), 4817 * getWidth(), and getHeight(). 4818 * 4819 * @param outRect The (scrolled) drawing bounds of the view. 4820 */ getDrawingRect(Rect outRect)4821 public void getDrawingRect(Rect outRect) { 4822 outRect.left = mScrollX; 4823 outRect.top = mScrollY; 4824 outRect.right = mScrollX + (mRight - mLeft); 4825 outRect.bottom = mScrollY + (mBottom - mTop); 4826 } 4827 4828 /** 4829 * The width of this view as measured in the most recent call to measure(). 4830 * This should be used during measurement and layout calculations only. Use 4831 * {@link #getWidth()} to see how wide a view is after layout. 4832 * 4833 * @return The measured width of this view. 4834 */ getMeasuredWidth()4835 public final int getMeasuredWidth() { 4836 return mMeasuredWidth; 4837 } 4838 4839 /** 4840 * The height of this view as measured in the most recent call to measure(). 4841 * This should be used during measurement and layout calculations only. Use 4842 * {@link #getHeight()} to see how tall a view is after layout. 4843 * 4844 * @return The measured height of this view. 4845 */ getMeasuredHeight()4846 public final int getMeasuredHeight() { 4847 return mMeasuredHeight; 4848 } 4849 4850 /** 4851 * Top position of this view relative to its parent. 4852 * 4853 * @return The top of this view, in pixels. 4854 */ 4855 @ViewDebug.CapturedViewProperty getTop()4856 public final int getTop() { 4857 return mTop; 4858 } 4859 4860 /** 4861 * Bottom position of this view relative to its parent. 4862 * 4863 * @return The bottom of this view, in pixels. 4864 */ 4865 @ViewDebug.CapturedViewProperty getBottom()4866 public final int getBottom() { 4867 return mBottom; 4868 } 4869 4870 /** 4871 * Left position of this view relative to its parent. 4872 * 4873 * @return The left edge of this view, in pixels. 4874 */ 4875 @ViewDebug.CapturedViewProperty getLeft()4876 public final int getLeft() { 4877 return mLeft; 4878 } 4879 4880 /** 4881 * Right position of this view relative to its parent. 4882 * 4883 * @return The right edge of this view, in pixels. 4884 */ 4885 @ViewDebug.CapturedViewProperty getRight()4886 public final int getRight() { 4887 return mRight; 4888 } 4889 4890 /** 4891 * Hit rectangle in parent's coordinates 4892 * 4893 * @param outRect The hit rectangle of the view. 4894 */ getHitRect(Rect outRect)4895 public void getHitRect(Rect outRect) { 4896 outRect.set(mLeft, mTop, mRight, mBottom); 4897 } 4898 4899 /** 4900 * When a view has focus and the user navigates away from it, the next view is searched for 4901 * starting from the rectangle filled in by this method. 4902 * 4903 * By default, the rectange is the {@link #getDrawingRect})of the view. However, if your 4904 * view maintains some idea of internal selection, such as a cursor, or a selected row 4905 * or column, you should override this method and fill in a more specific rectangle. 4906 * 4907 * @param r The rectangle to fill in, in this view's coordinates. 4908 */ getFocusedRect(Rect r)4909 public void getFocusedRect(Rect r) { 4910 getDrawingRect(r); 4911 } 4912 4913 /** 4914 * If some part of this view is not clipped by any of its parents, then 4915 * return that area in r in global (root) coordinates. To convert r to local 4916 * coordinates, offset it by -globalOffset (e.g. r.offset(-globalOffset.x, 4917 * -globalOffset.y)) If the view is completely clipped or translated out, 4918 * return false. 4919 * 4920 * @param r If true is returned, r holds the global coordinates of the 4921 * visible portion of this view. 4922 * @param globalOffset If true is returned, globalOffset holds the dx,dy 4923 * between this view and its root. globalOffet may be null. 4924 * @return true if r is non-empty (i.e. part of the view is visible at the 4925 * root level. 4926 */ getGlobalVisibleRect(Rect r, Point globalOffset)4927 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 4928 int width = mRight - mLeft; 4929 int height = mBottom - mTop; 4930 if (width > 0 && height > 0) { 4931 r.set(0, 0, width, height); 4932 if (globalOffset != null) { 4933 globalOffset.set(-mScrollX, -mScrollY); 4934 } 4935 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 4936 } 4937 return false; 4938 } 4939 getGlobalVisibleRect(Rect r)4940 public final boolean getGlobalVisibleRect(Rect r) { 4941 return getGlobalVisibleRect(r, null); 4942 } 4943 getLocalVisibleRect(Rect r)4944 public final boolean getLocalVisibleRect(Rect r) { 4945 Point offset = new Point(); 4946 if (getGlobalVisibleRect(r, offset)) { 4947 r.offset(-offset.x, -offset.y); // make r local 4948 return true; 4949 } 4950 return false; 4951 } 4952 4953 /** 4954 * Offset this view's vertical location by the specified number of pixels. 4955 * 4956 * @param offset the number of pixels to offset the view by 4957 */ offsetTopAndBottom(int offset)4958 public void offsetTopAndBottom(int offset) { 4959 mTop += offset; 4960 mBottom += offset; 4961 } 4962 4963 /** 4964 * Offset this view's horizontal location by the specified amount of pixels. 4965 * 4966 * @param offset the numer of pixels to offset the view by 4967 */ offsetLeftAndRight(int offset)4968 public void offsetLeftAndRight(int offset) { 4969 mLeft += offset; 4970 mRight += offset; 4971 } 4972 4973 /** 4974 * Get the LayoutParams associated with this view. All views should have 4975 * layout parameters. These supply parameters to the <i>parent</i> of this 4976 * view specifying how it should be arranged. There are many subclasses of 4977 * ViewGroup.LayoutParams, and these correspond to the different subclasses 4978 * of ViewGroup that are responsible for arranging their children. 4979 * @return The LayoutParams associated with this view 4980 */ 4981 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()4982 public ViewGroup.LayoutParams getLayoutParams() { 4983 return mLayoutParams; 4984 } 4985 4986 /** 4987 * Set the layout parameters associated with this view. These supply 4988 * parameters to the <i>parent</i> of this view specifying how it should be 4989 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 4990 * correspond to the different subclasses of ViewGroup that are responsible 4991 * for arranging their children. 4992 * 4993 * @param params the layout parameters for this view 4994 */ setLayoutParams(ViewGroup.LayoutParams params)4995 public void setLayoutParams(ViewGroup.LayoutParams params) { 4996 if (params == null) { 4997 throw new NullPointerException("params == null"); 4998 } 4999 mLayoutParams = params; 5000 requestLayout(); 5001 } 5002 5003 /** 5004 * Set the scrolled position of your view. This will cause a call to 5005 * {@link #onScrollChanged(int, int, int, int)} and the view will be 5006 * invalidated. 5007 * @param x the x position to scroll to 5008 * @param y the y position to scroll to 5009 */ scrollTo(int x, int y)5010 public void scrollTo(int x, int y) { 5011 if (mScrollX != x || mScrollY != y) { 5012 int oldX = mScrollX; 5013 int oldY = mScrollY; 5014 mScrollX = x; 5015 mScrollY = y; 5016 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 5017 if (!awakenScrollBars()) { 5018 invalidate(); 5019 } 5020 } 5021 } 5022 5023 /** 5024 * Move the scrolled position of your view. This will cause a call to 5025 * {@link #onScrollChanged(int, int, int, int)} and the view will be 5026 * invalidated. 5027 * @param x the amount of pixels to scroll by horizontally 5028 * @param y the amount of pixels to scroll by vertically 5029 */ scrollBy(int x, int y)5030 public void scrollBy(int x, int y) { 5031 scrollTo(mScrollX + x, mScrollY + y); 5032 } 5033 5034 /** 5035 * <p>Trigger the scrollbars to draw. When invoked this method starts an 5036 * animation to fade the scrollbars out after a default delay. If a subclass 5037 * provides animated scrolling, the start delay should equal the duration 5038 * of the scrolling animation.</p> 5039 * 5040 * <p>The animation starts only if at least one of the scrollbars is 5041 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 5042 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 5043 * this method returns true, and false otherwise. If the animation is 5044 * started, this method calls {@link #invalidate()}; in that case the 5045 * caller should not call {@link #invalidate()}.</p> 5046 * 5047 * <p>This method should be invoked every time a subclass directly updates 5048 * the scroll parameters.</p> 5049 * 5050 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 5051 * and {@link #scrollTo(int, int)}.</p> 5052 * 5053 * @return true if the animation is played, false otherwise 5054 * 5055 * @see #awakenScrollBars(int) 5056 * @see #scrollBy(int, int) 5057 * @see #scrollTo(int, int) 5058 * @see #isHorizontalScrollBarEnabled() 5059 * @see #isVerticalScrollBarEnabled() 5060 * @see #setHorizontalScrollBarEnabled(boolean) 5061 * @see #setVerticalScrollBarEnabled(boolean) 5062 */ awakenScrollBars()5063 protected boolean awakenScrollBars() { 5064 return mScrollCache != null && 5065 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 5066 } 5067 5068 /** 5069 * Trigger the scrollbars to draw. 5070 * This method differs from awakenScrollBars() only in its default duration. 5071 * initialAwakenScrollBars() will show the scroll bars for longer than 5072 * usual to give the user more of a chance to notice them. 5073 * 5074 * @return true if the animation is played, false otherwise. 5075 */ initialAwakenScrollBars()5076 private boolean initialAwakenScrollBars() { 5077 return mScrollCache != null && 5078 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 5079 } 5080 5081 /** 5082 * <p> 5083 * Trigger the scrollbars to draw. When invoked this method starts an 5084 * animation to fade the scrollbars out after a fixed delay. If a subclass 5085 * provides animated scrolling, the start delay should equal the duration of 5086 * the scrolling animation. 5087 * </p> 5088 * 5089 * <p> 5090 * The animation starts only if at least one of the scrollbars is enabled, 5091 * as specified by {@link #isHorizontalScrollBarEnabled()} and 5092 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 5093 * this method returns true, and false otherwise. If the animation is 5094 * started, this method calls {@link #invalidate()}; in that case the caller 5095 * should not call {@link #invalidate()}. 5096 * </p> 5097 * 5098 * <p> 5099 * This method should be invoked everytime a subclass directly updates the 5100 * scroll parameters. 5101 * </p> 5102 * 5103 * @param startDelay the delay, in milliseconds, after which the animation 5104 * should start; when the delay is 0, the animation starts 5105 * immediately 5106 * @return true if the animation is played, false otherwise 5107 * 5108 * @see #scrollBy(int, int) 5109 * @see #scrollTo(int, int) 5110 * @see #isHorizontalScrollBarEnabled() 5111 * @see #isVerticalScrollBarEnabled() 5112 * @see #setHorizontalScrollBarEnabled(boolean) 5113 * @see #setVerticalScrollBarEnabled(boolean) 5114 */ awakenScrollBars(int startDelay)5115 protected boolean awakenScrollBars(int startDelay) { 5116 return awakenScrollBars(startDelay, true); 5117 } 5118 5119 /** 5120 * <p> 5121 * Trigger the scrollbars to draw. When invoked this method starts an 5122 * animation to fade the scrollbars out after a fixed delay. If a subclass 5123 * provides animated scrolling, the start delay should equal the duration of 5124 * the scrolling animation. 5125 * </p> 5126 * 5127 * <p> 5128 * The animation starts only if at least one of the scrollbars is enabled, 5129 * as specified by {@link #isHorizontalScrollBarEnabled()} and 5130 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 5131 * this method returns true, and false otherwise. If the animation is 5132 * started, this method calls {@link #invalidate()} if the invalidate parameter 5133 * is set to true; in that case the caller 5134 * should not call {@link #invalidate()}. 5135 * </p> 5136 * 5137 * <p> 5138 * This method should be invoked everytime a subclass directly updates the 5139 * scroll parameters. 5140 * </p> 5141 * 5142 * @param startDelay the delay, in milliseconds, after which the animation 5143 * should start; when the delay is 0, the animation starts 5144 * immediately 5145 * 5146 * @param invalidate Wheter this method should call invalidate 5147 * 5148 * @return true if the animation is played, false otherwise 5149 * 5150 * @see #scrollBy(int, int) 5151 * @see #scrollTo(int, int) 5152 * @see #isHorizontalScrollBarEnabled() 5153 * @see #isVerticalScrollBarEnabled() 5154 * @see #setHorizontalScrollBarEnabled(boolean) 5155 * @see #setVerticalScrollBarEnabled(boolean) 5156 */ awakenScrollBars(int startDelay, boolean invalidate)5157 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 5158 final ScrollabilityCache scrollCache = mScrollCache; 5159 5160 if (scrollCache == null || !scrollCache.fadeScrollBars) { 5161 return false; 5162 } 5163 5164 if (scrollCache.scrollBar == null) { 5165 scrollCache.scrollBar = new ScrollBarDrawable(); 5166 } 5167 5168 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 5169 5170 if (invalidate) { 5171 // Invalidate to show the scrollbars 5172 invalidate(); 5173 } 5174 5175 if (scrollCache.state == ScrollabilityCache.OFF) { 5176 // FIXME: this is copied from WindowManagerService. 5177 // We should get this value from the system when it 5178 // is possible to do so. 5179 final int KEY_REPEAT_FIRST_DELAY = 750; 5180 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 5181 } 5182 5183 // Tell mScrollCache when we should start fading. This may 5184 // extend the fade start time if one was already scheduled 5185 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 5186 scrollCache.fadeStartTime = fadeStartTime; 5187 scrollCache.state = ScrollabilityCache.ON; 5188 5189 // Schedule our fader to run, unscheduling any old ones first 5190 if (mAttachInfo != null) { 5191 mAttachInfo.mHandler.removeCallbacks(scrollCache); 5192 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 5193 } 5194 5195 return true; 5196 } 5197 5198 return false; 5199 } 5200 5201 /** 5202 * Mark the the area defined by dirty as needing to be drawn. If the view is 5203 * visible, {@link #onDraw} will be called at some point in the future. 5204 * This must be called from a UI thread. To call from a non-UI thread, call 5205 * {@link #postInvalidate()}. 5206 * 5207 * WARNING: This method is destructive to dirty. 5208 * @param dirty the rectangle representing the bounds of the dirty region 5209 */ invalidate(Rect dirty)5210 public void invalidate(Rect dirty) { 5211 if (ViewDebug.TRACE_HIERARCHY) { 5212 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE); 5213 } 5214 5215 if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) { 5216 mPrivateFlags &= ~DRAWING_CACHE_VALID; 5217 final ViewParent p = mParent; 5218 final AttachInfo ai = mAttachInfo; 5219 if (p != null && ai != null) { 5220 final int scrollX = mScrollX; 5221 final int scrollY = mScrollY; 5222 final Rect r = ai.mTmpInvalRect; 5223 r.set(dirty.left - scrollX, dirty.top - scrollY, 5224 dirty.right - scrollX, dirty.bottom - scrollY); 5225 mParent.invalidateChild(this, r); 5226 } 5227 } 5228 } 5229 5230 /** 5231 * Mark the the area defined by the rect (l,t,r,b) as needing to be drawn. 5232 * The coordinates of the dirty rect are relative to the view. 5233 * If the view is visible, {@link #onDraw} will be called at some point 5234 * in the future. This must be called from a UI thread. To call 5235 * from a non-UI thread, call {@link #postInvalidate()}. 5236 * @param l the left position of the dirty region 5237 * @param t the top position of the dirty region 5238 * @param r the right position of the dirty region 5239 * @param b the bottom position of the dirty region 5240 */ invalidate(int l, int t, int r, int b)5241 public void invalidate(int l, int t, int r, int b) { 5242 if (ViewDebug.TRACE_HIERARCHY) { 5243 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE); 5244 } 5245 5246 if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) { 5247 mPrivateFlags &= ~DRAWING_CACHE_VALID; 5248 final ViewParent p = mParent; 5249 final AttachInfo ai = mAttachInfo; 5250 if (p != null && ai != null && l < r && t < b) { 5251 final int scrollX = mScrollX; 5252 final int scrollY = mScrollY; 5253 final Rect tmpr = ai.mTmpInvalRect; 5254 tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY); 5255 p.invalidateChild(this, tmpr); 5256 } 5257 } 5258 } 5259 5260 /** 5261 * Invalidate the whole view. If the view is visible, {@link #onDraw} will 5262 * be called at some point in the future. This must be called from a 5263 * UI thread. To call from a non-UI thread, call {@link #postInvalidate()}. 5264 */ invalidate()5265 public void invalidate() { 5266 if (ViewDebug.TRACE_HIERARCHY) { 5267 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE); 5268 } 5269 5270 if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) { 5271 mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID; 5272 final ViewParent p = mParent; 5273 final AttachInfo ai = mAttachInfo; 5274 if (p != null && ai != null) { 5275 final Rect r = ai.mTmpInvalRect; 5276 r.set(0, 0, mRight - mLeft, mBottom - mTop); 5277 // Don't call invalidate -- we don't want to internally scroll 5278 // our own bounds 5279 p.invalidateChild(this, r); 5280 } 5281 } 5282 } 5283 5284 /** 5285 * Indicates whether this View is opaque. An opaque View guarantees that it will 5286 * draw all the pixels overlapping its bounds using a fully opaque color. 5287 * 5288 * Subclasses of View should override this method whenever possible to indicate 5289 * whether an instance is opaque. Opaque Views are treated in a special way by 5290 * the View hierarchy, possibly allowing it to perform optimizations during 5291 * invalidate/draw passes. 5292 * 5293 * @return True if this View is guaranteed to be fully opaque, false otherwise. 5294 */ 5295 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()5296 public boolean isOpaque() { 5297 return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK; 5298 } 5299 computeOpaqueFlags()5300 private void computeOpaqueFlags() { 5301 // Opaque if: 5302 // - Has a background 5303 // - Background is opaque 5304 // - Doesn't have scrollbars or scrollbars are inside overlay 5305 5306 if (mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE) { 5307 mPrivateFlags |= OPAQUE_BACKGROUND; 5308 } else { 5309 mPrivateFlags &= ~OPAQUE_BACKGROUND; 5310 } 5311 5312 final int flags = mViewFlags; 5313 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 5314 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY) { 5315 mPrivateFlags |= OPAQUE_SCROLLBARS; 5316 } else { 5317 mPrivateFlags &= ~OPAQUE_SCROLLBARS; 5318 } 5319 } 5320 5321 /** 5322 * @hide 5323 */ hasOpaqueScrollbars()5324 protected boolean hasOpaqueScrollbars() { 5325 return (mPrivateFlags & OPAQUE_SCROLLBARS) == OPAQUE_SCROLLBARS; 5326 } 5327 5328 /** 5329 * @return A handler associated with the thread running the View. This 5330 * handler can be used to pump events in the UI events queue. 5331 */ getHandler()5332 public Handler getHandler() { 5333 if (mAttachInfo != null) { 5334 return mAttachInfo.mHandler; 5335 } 5336 return null; 5337 } 5338 5339 /** 5340 * Causes the Runnable to be added to the message queue. 5341 * The runnable will be run on the user interface thread. 5342 * 5343 * @param action The Runnable that will be executed. 5344 * 5345 * @return Returns true if the Runnable was successfully placed in to the 5346 * message queue. Returns false on failure, usually because the 5347 * looper processing the message queue is exiting. 5348 */ post(Runnable action)5349 public boolean post(Runnable action) { 5350 Handler handler; 5351 if (mAttachInfo != null) { 5352 handler = mAttachInfo.mHandler; 5353 } else { 5354 // Assume that post will succeed later 5355 ViewRoot.getRunQueue().post(action); 5356 return true; 5357 } 5358 5359 return handler.post(action); 5360 } 5361 5362 /** 5363 * Causes the Runnable to be added to the message queue, to be run 5364 * after the specified amount of time elapses. 5365 * The runnable will be run on the user interface thread. 5366 * 5367 * @param action The Runnable that will be executed. 5368 * @param delayMillis The delay (in milliseconds) until the Runnable 5369 * will be executed. 5370 * 5371 * @return true if the Runnable was successfully placed in to the 5372 * message queue. Returns false on failure, usually because the 5373 * looper processing the message queue is exiting. Note that a 5374 * result of true does not mean the Runnable will be processed -- 5375 * if the looper is quit before the delivery time of the message 5376 * occurs then the message will be dropped. 5377 */ postDelayed(Runnable action, long delayMillis)5378 public boolean postDelayed(Runnable action, long delayMillis) { 5379 Handler handler; 5380 if (mAttachInfo != null) { 5381 handler = mAttachInfo.mHandler; 5382 } else { 5383 // Assume that post will succeed later 5384 ViewRoot.getRunQueue().postDelayed(action, delayMillis); 5385 return true; 5386 } 5387 5388 return handler.postDelayed(action, delayMillis); 5389 } 5390 5391 /** 5392 * Removes the specified Runnable from the message queue. 5393 * 5394 * @param action The Runnable to remove from the message handling queue 5395 * 5396 * @return true if this view could ask the Handler to remove the Runnable, 5397 * false otherwise. When the returned value is true, the Runnable 5398 * may or may not have been actually removed from the message queue 5399 * (for instance, if the Runnable was not in the queue already.) 5400 */ removeCallbacks(Runnable action)5401 public boolean removeCallbacks(Runnable action) { 5402 Handler handler; 5403 if (mAttachInfo != null) { 5404 handler = mAttachInfo.mHandler; 5405 } else { 5406 // Assume that post will succeed later 5407 ViewRoot.getRunQueue().removeCallbacks(action); 5408 return true; 5409 } 5410 5411 handler.removeCallbacks(action); 5412 return true; 5413 } 5414 5415 /** 5416 * Cause an invalidate to happen on a subsequent cycle through the event loop. 5417 * Use this to invalidate the View from a non-UI thread. 5418 * 5419 * @see #invalidate() 5420 */ postInvalidate()5421 public void postInvalidate() { 5422 postInvalidateDelayed(0); 5423 } 5424 5425 /** 5426 * Cause an invalidate of the specified area to happen on a subsequent cycle 5427 * through the event loop. Use this to invalidate the View from a non-UI thread. 5428 * 5429 * @param left The left coordinate of the rectangle to invalidate. 5430 * @param top The top coordinate of the rectangle to invalidate. 5431 * @param right The right coordinate of the rectangle to invalidate. 5432 * @param bottom The bottom coordinate of the rectangle to invalidate. 5433 * 5434 * @see #invalidate(int, int, int, int) 5435 * @see #invalidate(Rect) 5436 */ postInvalidate(int left, int top, int right, int bottom)5437 public void postInvalidate(int left, int top, int right, int bottom) { 5438 postInvalidateDelayed(0, left, top, right, bottom); 5439 } 5440 5441 /** 5442 * Cause an invalidate to happen on a subsequent cycle through the event 5443 * loop. Waits for the specified amount of time. 5444 * 5445 * @param delayMilliseconds the duration in milliseconds to delay the 5446 * invalidation by 5447 */ postInvalidateDelayed(long delayMilliseconds)5448 public void postInvalidateDelayed(long delayMilliseconds) { 5449 // We try only with the AttachInfo because there's no point in invalidating 5450 // if we are not attached to our window 5451 if (mAttachInfo != null) { 5452 Message msg = Message.obtain(); 5453 msg.what = AttachInfo.INVALIDATE_MSG; 5454 msg.obj = this; 5455 mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds); 5456 } 5457 } 5458 5459 /** 5460 * Cause an invalidate of the specified area to happen on a subsequent cycle 5461 * through the event loop. Waits for the specified amount of time. 5462 * 5463 * @param delayMilliseconds the duration in milliseconds to delay the 5464 * invalidation by 5465 * @param left The left coordinate of the rectangle to invalidate. 5466 * @param top The top coordinate of the rectangle to invalidate. 5467 * @param right The right coordinate of the rectangle to invalidate. 5468 * @param bottom The bottom coordinate of the rectangle to invalidate. 5469 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)5470 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 5471 int right, int bottom) { 5472 5473 // We try only with the AttachInfo because there's no point in invalidating 5474 // if we are not attached to our window 5475 if (mAttachInfo != null) { 5476 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire(); 5477 info.target = this; 5478 info.left = left; 5479 info.top = top; 5480 info.right = right; 5481 info.bottom = bottom; 5482 5483 final Message msg = Message.obtain(); 5484 msg.what = AttachInfo.INVALIDATE_RECT_MSG; 5485 msg.obj = info; 5486 mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds); 5487 } 5488 } 5489 5490 /** 5491 * Called by a parent to request that a child update its values for mScrollX 5492 * and mScrollY if necessary. This will typically be done if the child is 5493 * animating a scroll using a {@link android.widget.Scroller Scroller} 5494 * object. 5495 */ computeScroll()5496 public void computeScroll() { 5497 } 5498 5499 /** 5500 * <p>Indicate whether the horizontal edges are faded when the view is 5501 * scrolled horizontally.</p> 5502 * 5503 * @return true if the horizontal edges should are faded on scroll, false 5504 * otherwise 5505 * 5506 * @see #setHorizontalFadingEdgeEnabled(boolean) 5507 * @attr ref android.R.styleable#View_fadingEdge 5508 */ isHorizontalFadingEdgeEnabled()5509 public boolean isHorizontalFadingEdgeEnabled() { 5510 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 5511 } 5512 5513 /** 5514 * <p>Define whether the horizontal edges should be faded when this view 5515 * is scrolled horizontally.</p> 5516 * 5517 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 5518 * be faded when the view is scrolled 5519 * horizontally 5520 * 5521 * @see #isHorizontalFadingEdgeEnabled() 5522 * @attr ref android.R.styleable#View_fadingEdge 5523 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)5524 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 5525 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 5526 if (horizontalFadingEdgeEnabled) { 5527 initScrollCache(); 5528 } 5529 5530 mViewFlags ^= FADING_EDGE_HORIZONTAL; 5531 } 5532 } 5533 5534 /** 5535 * <p>Indicate whether the vertical edges are faded when the view is 5536 * scrolled horizontally.</p> 5537 * 5538 * @return true if the vertical edges should are faded on scroll, false 5539 * otherwise 5540 * 5541 * @see #setVerticalFadingEdgeEnabled(boolean) 5542 * @attr ref android.R.styleable#View_fadingEdge 5543 */ isVerticalFadingEdgeEnabled()5544 public boolean isVerticalFadingEdgeEnabled() { 5545 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 5546 } 5547 5548 /** 5549 * <p>Define whether the vertical edges should be faded when this view 5550 * is scrolled vertically.</p> 5551 * 5552 * @param verticalFadingEdgeEnabled true if the vertical edges should 5553 * be faded when the view is scrolled 5554 * vertically 5555 * 5556 * @see #isVerticalFadingEdgeEnabled() 5557 * @attr ref android.R.styleable#View_fadingEdge 5558 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)5559 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 5560 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 5561 if (verticalFadingEdgeEnabled) { 5562 initScrollCache(); 5563 } 5564 5565 mViewFlags ^= FADING_EDGE_VERTICAL; 5566 } 5567 } 5568 5569 /** 5570 * Returns the strength, or intensity, of the top faded edge. The strength is 5571 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 5572 * returns 0.0 or 1.0 but no value in between. 5573 * 5574 * Subclasses should override this method to provide a smoother fade transition 5575 * when scrolling occurs. 5576 * 5577 * @return the intensity of the top fade as a float between 0.0f and 1.0f 5578 */ getTopFadingEdgeStrength()5579 protected float getTopFadingEdgeStrength() { 5580 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 5581 } 5582 5583 /** 5584 * Returns the strength, or intensity, of the bottom faded edge. The strength is 5585 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 5586 * returns 0.0 or 1.0 but no value in between. 5587 * 5588 * Subclasses should override this method to provide a smoother fade transition 5589 * when scrolling occurs. 5590 * 5591 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 5592 */ getBottomFadingEdgeStrength()5593 protected float getBottomFadingEdgeStrength() { 5594 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 5595 computeVerticalScrollRange() ? 1.0f : 0.0f; 5596 } 5597 5598 /** 5599 * Returns the strength, or intensity, of the left faded edge. The strength is 5600 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 5601 * returns 0.0 or 1.0 but no value in between. 5602 * 5603 * Subclasses should override this method to provide a smoother fade transition 5604 * when scrolling occurs. 5605 * 5606 * @return the intensity of the left fade as a float between 0.0f and 1.0f 5607 */ getLeftFadingEdgeStrength()5608 protected float getLeftFadingEdgeStrength() { 5609 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 5610 } 5611 5612 /** 5613 * Returns the strength, or intensity, of the right faded edge. The strength is 5614 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 5615 * returns 0.0 or 1.0 but no value in between. 5616 * 5617 * Subclasses should override this method to provide a smoother fade transition 5618 * when scrolling occurs. 5619 * 5620 * @return the intensity of the right fade as a float between 0.0f and 1.0f 5621 */ getRightFadingEdgeStrength()5622 protected float getRightFadingEdgeStrength() { 5623 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 5624 computeHorizontalScrollRange() ? 1.0f : 0.0f; 5625 } 5626 5627 /** 5628 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 5629 * scrollbar is not drawn by default.</p> 5630 * 5631 * @return true if the horizontal scrollbar should be painted, false 5632 * otherwise 5633 * 5634 * @see #setHorizontalScrollBarEnabled(boolean) 5635 */ isHorizontalScrollBarEnabled()5636 public boolean isHorizontalScrollBarEnabled() { 5637 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 5638 } 5639 5640 /** 5641 * <p>Define whether the horizontal scrollbar should be drawn or not. The 5642 * scrollbar is not drawn by default.</p> 5643 * 5644 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 5645 * be painted 5646 * 5647 * @see #isHorizontalScrollBarEnabled() 5648 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)5649 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 5650 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 5651 mViewFlags ^= SCROLLBARS_HORIZONTAL; 5652 computeOpaqueFlags(); 5653 recomputePadding(); 5654 } 5655 } 5656 5657 /** 5658 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 5659 * scrollbar is not drawn by default.</p> 5660 * 5661 * @return true if the vertical scrollbar should be painted, false 5662 * otherwise 5663 * 5664 * @see #setVerticalScrollBarEnabled(boolean) 5665 */ isVerticalScrollBarEnabled()5666 public boolean isVerticalScrollBarEnabled() { 5667 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 5668 } 5669 5670 /** 5671 * <p>Define whether the vertical scrollbar should be drawn or not. The 5672 * scrollbar is not drawn by default.</p> 5673 * 5674 * @param verticalScrollBarEnabled true if the vertical scrollbar should 5675 * be painted 5676 * 5677 * @see #isVerticalScrollBarEnabled() 5678 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)5679 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 5680 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 5681 mViewFlags ^= SCROLLBARS_VERTICAL; 5682 computeOpaqueFlags(); 5683 recomputePadding(); 5684 } 5685 } 5686 recomputePadding()5687 private void recomputePadding() { 5688 setPadding(mPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 5689 } 5690 5691 /** 5692 * Define whether scrollbars will fade when the view is not scrolling. 5693 * 5694 * @param fadeScrollbars wheter to enable fading 5695 * 5696 */ setScrollbarFadingEnabled(boolean fadeScrollbars)5697 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 5698 initScrollCache(); 5699 final ScrollabilityCache scrollabilityCache = mScrollCache; 5700 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5701 if (fadeScrollbars) { 5702 scrollabilityCache.state = ScrollabilityCache.OFF; 5703 } else { 5704 scrollabilityCache.state = ScrollabilityCache.ON; 5705 } 5706 } 5707 5708 /** 5709 * 5710 * Returns true if scrollbars will fade when this view is not scrolling 5711 * 5712 * @return true if scrollbar fading is enabled 5713 */ isScrollbarFadingEnabled()5714 public boolean isScrollbarFadingEnabled() { 5715 return mScrollCache != null && mScrollCache.fadeScrollBars; 5716 } 5717 5718 /** 5719 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 5720 * inset. When inset, they add to the padding of the view. And the scrollbars 5721 * can be drawn inside the padding area or on the edge of the view. For example, 5722 * if a view has a background drawable and you want to draw the scrollbars 5723 * inside the padding specified by the drawable, you can use 5724 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 5725 * appear at the edge of the view, ignoring the padding, then you can use 5726 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 5727 * @param style the style of the scrollbars. Should be one of 5728 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 5729 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 5730 * @see #SCROLLBARS_INSIDE_OVERLAY 5731 * @see #SCROLLBARS_INSIDE_INSET 5732 * @see #SCROLLBARS_OUTSIDE_OVERLAY 5733 * @see #SCROLLBARS_OUTSIDE_INSET 5734 */ setScrollBarStyle(int style)5735 public void setScrollBarStyle(int style) { 5736 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 5737 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 5738 computeOpaqueFlags(); 5739 recomputePadding(); 5740 } 5741 } 5742 5743 /** 5744 * <p>Returns the current scrollbar style.</p> 5745 * @return the current scrollbar style 5746 * @see #SCROLLBARS_INSIDE_OVERLAY 5747 * @see #SCROLLBARS_INSIDE_INSET 5748 * @see #SCROLLBARS_OUTSIDE_OVERLAY 5749 * @see #SCROLLBARS_OUTSIDE_INSET 5750 */ getScrollBarStyle()5751 public int getScrollBarStyle() { 5752 return mViewFlags & SCROLLBARS_STYLE_MASK; 5753 } 5754 5755 /** 5756 * <p>Compute the horizontal range that the horizontal scrollbar 5757 * represents.</p> 5758 * 5759 * <p>The range is expressed in arbitrary units that must be the same as the 5760 * units used by {@link #computeHorizontalScrollExtent()} and 5761 * {@link #computeHorizontalScrollOffset()}.</p> 5762 * 5763 * <p>The default range is the drawing width of this view.</p> 5764 * 5765 * @return the total horizontal range represented by the horizontal 5766 * scrollbar 5767 * 5768 * @see #computeHorizontalScrollExtent() 5769 * @see #computeHorizontalScrollOffset() 5770 * @see android.widget.ScrollBarDrawable 5771 */ computeHorizontalScrollRange()5772 protected int computeHorizontalScrollRange() { 5773 return getWidth(); 5774 } 5775 5776 /** 5777 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 5778 * within the horizontal range. This value is used to compute the position 5779 * of the thumb within the scrollbar's track.</p> 5780 * 5781 * <p>The range is expressed in arbitrary units that must be the same as the 5782 * units used by {@link #computeHorizontalScrollRange()} and 5783 * {@link #computeHorizontalScrollExtent()}.</p> 5784 * 5785 * <p>The default offset is the scroll offset of this view.</p> 5786 * 5787 * @return the horizontal offset of the scrollbar's thumb 5788 * 5789 * @see #computeHorizontalScrollRange() 5790 * @see #computeHorizontalScrollExtent() 5791 * @see android.widget.ScrollBarDrawable 5792 */ computeHorizontalScrollOffset()5793 protected int computeHorizontalScrollOffset() { 5794 return mScrollX; 5795 } 5796 5797 /** 5798 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 5799 * within the horizontal range. This value is used to compute the length 5800 * of the thumb within the scrollbar's track.</p> 5801 * 5802 * <p>The range is expressed in arbitrary units that must be the same as the 5803 * units used by {@link #computeHorizontalScrollRange()} and 5804 * {@link #computeHorizontalScrollOffset()}.</p> 5805 * 5806 * <p>The default extent is the drawing width of this view.</p> 5807 * 5808 * @return the horizontal extent of the scrollbar's thumb 5809 * 5810 * @see #computeHorizontalScrollRange() 5811 * @see #computeHorizontalScrollOffset() 5812 * @see android.widget.ScrollBarDrawable 5813 */ computeHorizontalScrollExtent()5814 protected int computeHorizontalScrollExtent() { 5815 return getWidth(); 5816 } 5817 5818 /** 5819 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 5820 * 5821 * <p>The range is expressed in arbitrary units that must be the same as the 5822 * units used by {@link #computeVerticalScrollExtent()} and 5823 * {@link #computeVerticalScrollOffset()}.</p> 5824 * 5825 * @return the total vertical range represented by the vertical scrollbar 5826 * 5827 * <p>The default range is the drawing height of this view.</p> 5828 * 5829 * @see #computeVerticalScrollExtent() 5830 * @see #computeVerticalScrollOffset() 5831 * @see android.widget.ScrollBarDrawable 5832 */ computeVerticalScrollRange()5833 protected int computeVerticalScrollRange() { 5834 return getHeight(); 5835 } 5836 5837 /** 5838 * <p>Compute the vertical offset of the vertical scrollbar's thumb 5839 * within the horizontal range. This value is used to compute the position 5840 * of the thumb within the scrollbar's track.</p> 5841 * 5842 * <p>The range is expressed in arbitrary units that must be the same as the 5843 * units used by {@link #computeVerticalScrollRange()} and 5844 * {@link #computeVerticalScrollExtent()}.</p> 5845 * 5846 * <p>The default offset is the scroll offset of this view.</p> 5847 * 5848 * @return the vertical offset of the scrollbar's thumb 5849 * 5850 * @see #computeVerticalScrollRange() 5851 * @see #computeVerticalScrollExtent() 5852 * @see android.widget.ScrollBarDrawable 5853 */ computeVerticalScrollOffset()5854 protected int computeVerticalScrollOffset() { 5855 return mScrollY; 5856 } 5857 5858 /** 5859 * <p>Compute the vertical extent of the horizontal scrollbar's thumb 5860 * within the vertical range. This value is used to compute the length 5861 * of the thumb within the scrollbar's track.</p> 5862 * 5863 * <p>The range is expressed in arbitrary units that must be the same as the 5864 * units used by {@link #computeVerticalScrollRange()} and 5865 * {@link #computeVerticalScrollOffset()}.</p> 5866 * 5867 * <p>The default extent is the drawing height of this view.</p> 5868 * 5869 * @return the vertical extent of the scrollbar's thumb 5870 * 5871 * @see #computeVerticalScrollRange() 5872 * @see #computeVerticalScrollOffset() 5873 * @see android.widget.ScrollBarDrawable 5874 */ computeVerticalScrollExtent()5875 protected int computeVerticalScrollExtent() { 5876 return getHeight(); 5877 } 5878 5879 /** 5880 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 5881 * scrollbars are painted only if they have been awakened first.</p> 5882 * 5883 * @param canvas the canvas on which to draw the scrollbars 5884 * 5885 * @see #awakenScrollBars(int) 5886 */ onDrawScrollBars(Canvas canvas)5887 protected final void onDrawScrollBars(Canvas canvas) { 5888 // scrollbars are drawn only when the animation is running 5889 final ScrollabilityCache cache = mScrollCache; 5890 if (cache != null) { 5891 5892 int state = cache.state; 5893 5894 if (state == ScrollabilityCache.OFF) { 5895 return; 5896 } 5897 5898 boolean invalidate = false; 5899 5900 if (state == ScrollabilityCache.FADING) { 5901 // We're fading -- get our fade interpolation 5902 if (cache.interpolatorValues == null) { 5903 cache.interpolatorValues = new float[1]; 5904 } 5905 5906 float[] values = cache.interpolatorValues; 5907 5908 // Stops the animation if we're done 5909 if (cache.scrollBarInterpolator.timeToValues(values) == 5910 Interpolator.Result.FREEZE_END) { 5911 cache.state = ScrollabilityCache.OFF; 5912 } else { 5913 cache.scrollBar.setAlpha(Math.round(values[0])); 5914 } 5915 5916 // This will make the scroll bars inval themselves after 5917 // drawing. We only want this when we're fading so that 5918 // we prevent excessive redraws 5919 invalidate = true; 5920 } else { 5921 // We're just on -- but we may have been fading before so 5922 // reset alpha 5923 cache.scrollBar.setAlpha(255); 5924 } 5925 5926 5927 final int viewFlags = mViewFlags; 5928 5929 final boolean drawHorizontalScrollBar = 5930 (viewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 5931 final boolean drawVerticalScrollBar = 5932 (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL 5933 && !isVerticalScrollBarHidden(); 5934 5935 if (drawVerticalScrollBar || drawHorizontalScrollBar) { 5936 final int width = mRight - mLeft; 5937 final int height = mBottom - mTop; 5938 5939 final ScrollBarDrawable scrollBar = cache.scrollBar; 5940 int size = scrollBar.getSize(false); 5941 if (size <= 0) { 5942 size = cache.scrollBarSize; 5943 } 5944 5945 final int scrollX = mScrollX; 5946 final int scrollY = mScrollY; 5947 final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 5948 5949 int left, top, right, bottom; 5950 5951 if (drawHorizontalScrollBar) { 5952 scrollBar.setParameters(computeHorizontalScrollRange(), 5953 computeHorizontalScrollOffset(), 5954 computeHorizontalScrollExtent(), false); 5955 final int verticalScrollBarGap = drawVerticalScrollBar ? 5956 getVerticalScrollbarWidth() : 0; 5957 top = scrollY + height - size - (mUserPaddingBottom & inside); 5958 left = scrollX + (mPaddingLeft & inside); 5959 right = scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 5960 bottom = top + size; 5961 onDrawHorizontalScrollBar(canvas, scrollBar, left, top, right, bottom); 5962 if (invalidate) { 5963 invalidate(left, top, right, bottom); 5964 } 5965 } 5966 5967 if (drawVerticalScrollBar) { 5968 scrollBar.setParameters(computeVerticalScrollRange(), 5969 computeVerticalScrollOffset(), 5970 computeVerticalScrollExtent(), true); 5971 // TODO: Deal with RTL languages to position scrollbar on left 5972 left = scrollX + width - size - (mUserPaddingRight & inside); 5973 top = scrollY + (mPaddingTop & inside); 5974 right = left + size; 5975 bottom = scrollY + height - (mUserPaddingBottom & inside); 5976 onDrawVerticalScrollBar(canvas, scrollBar, left, top, right, bottom); 5977 if (invalidate) { 5978 invalidate(left, top, right, bottom); 5979 } 5980 } 5981 } 5982 } 5983 } 5984 5985 /** 5986 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 5987 * FastScroller is visible. 5988 * @return whether to temporarily hide the vertical scrollbar 5989 * @hide 5990 */ isVerticalScrollBarHidden()5991 protected boolean isVerticalScrollBarHidden() { 5992 return false; 5993 } 5994 5995 /** 5996 * <p>Draw the horizontal scrollbar if 5997 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 5998 * 5999 * @param canvas the canvas on which to draw the scrollbar 6000 * @param scrollBar the scrollbar's drawable 6001 * 6002 * @see #isHorizontalScrollBarEnabled() 6003 * @see #computeHorizontalScrollRange() 6004 * @see #computeHorizontalScrollExtent() 6005 * @see #computeHorizontalScrollOffset() 6006 * @see android.widget.ScrollBarDrawable 6007 * @hide 6008 */ onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)6009 protected void onDrawHorizontalScrollBar(Canvas canvas, 6010 Drawable scrollBar, 6011 int l, int t, int r, int b) { 6012 scrollBar.setBounds(l, t, r, b); 6013 scrollBar.draw(canvas); 6014 } 6015 6016 /** 6017 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 6018 * returns true.</p> 6019 * 6020 * @param canvas the canvas on which to draw the scrollbar 6021 * @param scrollBar the scrollbar's drawable 6022 * 6023 * @see #isVerticalScrollBarEnabled() 6024 * @see #computeVerticalScrollRange() 6025 * @see #computeVerticalScrollExtent() 6026 * @see #computeVerticalScrollOffset() 6027 * @see android.widget.ScrollBarDrawable 6028 * @hide 6029 */ onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)6030 protected void onDrawVerticalScrollBar(Canvas canvas, 6031 Drawable scrollBar, 6032 int l, int t, int r, int b) { 6033 scrollBar.setBounds(l, t, r, b); 6034 scrollBar.draw(canvas); 6035 } 6036 6037 /** 6038 * Implement this to do your drawing. 6039 * 6040 * @param canvas the canvas on which the background will be drawn 6041 */ onDraw(Canvas canvas)6042 protected void onDraw(Canvas canvas) { 6043 } 6044 6045 /* 6046 * Caller is responsible for calling requestLayout if necessary. 6047 * (This allows addViewInLayout to not request a new layout.) 6048 */ assignParent(ViewParent parent)6049 void assignParent(ViewParent parent) { 6050 if (mParent == null) { 6051 mParent = parent; 6052 } else if (parent == null) { 6053 mParent = null; 6054 } else { 6055 throw new RuntimeException("view " + this + " being added, but" 6056 + " it already has a parent"); 6057 } 6058 } 6059 6060 /** 6061 * This is called when the view is attached to a window. At this point it 6062 * has a Surface and will start drawing. Note that this function is 6063 * guaranteed to be called before {@link #onDraw}, however it may be called 6064 * any time before the first onDraw -- including before or after 6065 * {@link #onMeasure}. 6066 * 6067 * @see #onDetachedFromWindow() 6068 */ onAttachedToWindow()6069 protected void onAttachedToWindow() { 6070 if ((mPrivateFlags & REQUEST_TRANSPARENT_REGIONS) != 0) { 6071 mParent.requestTransparentRegion(this); 6072 } 6073 if ((mPrivateFlags & AWAKEN_SCROLL_BARS_ON_ATTACH) != 0) { 6074 initialAwakenScrollBars(); 6075 mPrivateFlags &= ~AWAKEN_SCROLL_BARS_ON_ATTACH; 6076 } 6077 } 6078 6079 /** 6080 * This is called when the view is detached from a window. At this point it 6081 * no longer has a surface for drawing. 6082 * 6083 * @see #onAttachedToWindow() 6084 */ onDetachedFromWindow()6085 protected void onDetachedFromWindow() { 6086 mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; 6087 removeUnsetPressCallback(); 6088 removeLongPressCallback(); 6089 destroyDrawingCache(); 6090 } 6091 6092 /** 6093 * @return The number of times this view has been attached to a window 6094 */ getWindowAttachCount()6095 protected int getWindowAttachCount() { 6096 return mWindowAttachCount; 6097 } 6098 6099 /** 6100 * Retrieve a unique token identifying the window this view is attached to. 6101 * @return Return the window's token for use in 6102 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 6103 */ getWindowToken()6104 public IBinder getWindowToken() { 6105 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 6106 } 6107 6108 /** 6109 * Retrieve a unique token identifying the top-level "real" window of 6110 * the window that this view is attached to. That is, this is like 6111 * {@link #getWindowToken}, except if the window this view in is a panel 6112 * window (attached to another containing window), then the token of 6113 * the containing window is returned instead. 6114 * 6115 * @return Returns the associated window token, either 6116 * {@link #getWindowToken()} or the containing window's token. 6117 */ getApplicationWindowToken()6118 public IBinder getApplicationWindowToken() { 6119 AttachInfo ai = mAttachInfo; 6120 if (ai != null) { 6121 IBinder appWindowToken = ai.mPanelParentWindowToken; 6122 if (appWindowToken == null) { 6123 appWindowToken = ai.mWindowToken; 6124 } 6125 return appWindowToken; 6126 } 6127 return null; 6128 } 6129 6130 /** 6131 * Retrieve private session object this view hierarchy is using to 6132 * communicate with the window manager. 6133 * @return the session object to communicate with the window manager 6134 */ getWindowSession()6135 /*package*/ IWindowSession getWindowSession() { 6136 return mAttachInfo != null ? mAttachInfo.mSession : null; 6137 } 6138 6139 /** 6140 * @param info the {@link android.view.View.AttachInfo} to associated with 6141 * this view 6142 */ dispatchAttachedToWindow(AttachInfo info, int visibility)6143 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 6144 //System.out.println("Attached! " + this); 6145 mAttachInfo = info; 6146 mWindowAttachCount++; 6147 if (mFloatingTreeObserver != null) { 6148 info.mTreeObserver.merge(mFloatingTreeObserver); 6149 mFloatingTreeObserver = null; 6150 } 6151 if ((mPrivateFlags&SCROLL_CONTAINER) != 0) { 6152 mAttachInfo.mScrollContainers.add(this); 6153 mPrivateFlags |= SCROLL_CONTAINER_ADDED; 6154 } 6155 performCollectViewAttributes(visibility); 6156 onAttachedToWindow(); 6157 int vis = info.mWindowVisibility; 6158 if (vis != GONE) { 6159 onWindowVisibilityChanged(vis); 6160 } 6161 } 6162 dispatchDetachedFromWindow()6163 void dispatchDetachedFromWindow() { 6164 //System.out.println("Detached! " + this); 6165 AttachInfo info = mAttachInfo; 6166 if (info != null) { 6167 int vis = info.mWindowVisibility; 6168 if (vis != GONE) { 6169 onWindowVisibilityChanged(GONE); 6170 } 6171 } 6172 6173 onDetachedFromWindow(); 6174 if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) { 6175 mAttachInfo.mScrollContainers.remove(this); 6176 mPrivateFlags &= ~SCROLL_CONTAINER_ADDED; 6177 } 6178 mAttachInfo = null; 6179 } 6180 6181 /** 6182 * Store this view hierarchy's frozen state into the given container. 6183 * 6184 * @param container The SparseArray in which to save the view's state. 6185 * 6186 * @see #restoreHierarchyState 6187 * @see #dispatchSaveInstanceState 6188 * @see #onSaveInstanceState 6189 */ saveHierarchyState(SparseArray<Parcelable> container)6190 public void saveHierarchyState(SparseArray<Parcelable> container) { 6191 dispatchSaveInstanceState(container); 6192 } 6193 6194 /** 6195 * Called by {@link #saveHierarchyState} to store the state for this view and its children. 6196 * May be overridden to modify how freezing happens to a view's children; for example, some 6197 * views may want to not store state for their children. 6198 * 6199 * @param container The SparseArray in which to save the view's state. 6200 * 6201 * @see #dispatchRestoreInstanceState 6202 * @see #saveHierarchyState 6203 * @see #onSaveInstanceState 6204 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)6205 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 6206 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 6207 mPrivateFlags &= ~SAVE_STATE_CALLED; 6208 Parcelable state = onSaveInstanceState(); 6209 if ((mPrivateFlags & SAVE_STATE_CALLED) == 0) { 6210 throw new IllegalStateException( 6211 "Derived class did not call super.onSaveInstanceState()"); 6212 } 6213 if (state != null) { 6214 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 6215 // + ": " + state); 6216 container.put(mID, state); 6217 } 6218 } 6219 } 6220 6221 /** 6222 * Hook allowing a view to generate a representation of its internal state 6223 * that can later be used to create a new instance with that same state. 6224 * This state should only contain information that is not persistent or can 6225 * not be reconstructed later. For example, you will never store your 6226 * current position on screen because that will be computed again when a 6227 * new instance of the view is placed in its view hierarchy. 6228 * <p> 6229 * Some examples of things you may store here: the current cursor position 6230 * in a text view (but usually not the text itself since that is stored in a 6231 * content provider or other persistent storage), the currently selected 6232 * item in a list view. 6233 * 6234 * @return Returns a Parcelable object containing the view's current dynamic 6235 * state, or null if there is nothing interesting to save. The 6236 * default implementation returns null. 6237 * @see #onRestoreInstanceState 6238 * @see #saveHierarchyState 6239 * @see #dispatchSaveInstanceState 6240 * @see #setSaveEnabled(boolean) 6241 */ onSaveInstanceState()6242 protected Parcelable onSaveInstanceState() { 6243 mPrivateFlags |= SAVE_STATE_CALLED; 6244 return BaseSavedState.EMPTY_STATE; 6245 } 6246 6247 /** 6248 * Restore this view hierarchy's frozen state from the given container. 6249 * 6250 * @param container The SparseArray which holds previously frozen states. 6251 * 6252 * @see #saveHierarchyState 6253 * @see #dispatchRestoreInstanceState 6254 * @see #onRestoreInstanceState 6255 */ restoreHierarchyState(SparseArray<Parcelable> container)6256 public void restoreHierarchyState(SparseArray<Parcelable> container) { 6257 dispatchRestoreInstanceState(container); 6258 } 6259 6260 /** 6261 * Called by {@link #restoreHierarchyState} to retrieve the state for this view and its 6262 * children. May be overridden to modify how restoreing happens to a view's children; for 6263 * example, some views may want to not store state for their children. 6264 * 6265 * @param container The SparseArray which holds previously saved state. 6266 * 6267 * @see #dispatchSaveInstanceState 6268 * @see #restoreHierarchyState 6269 * @see #onRestoreInstanceState 6270 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)6271 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 6272 if (mID != NO_ID) { 6273 Parcelable state = container.get(mID); 6274 if (state != null) { 6275 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 6276 // + ": " + state); 6277 mPrivateFlags &= ~SAVE_STATE_CALLED; 6278 onRestoreInstanceState(state); 6279 if ((mPrivateFlags & SAVE_STATE_CALLED) == 0) { 6280 throw new IllegalStateException( 6281 "Derived class did not call super.onRestoreInstanceState()"); 6282 } 6283 } 6284 } 6285 } 6286 6287 /** 6288 * Hook allowing a view to re-apply a representation of its internal state that had previously 6289 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 6290 * null state. 6291 * 6292 * @param state The frozen state that had previously been returned by 6293 * {@link #onSaveInstanceState}. 6294 * 6295 * @see #onSaveInstanceState 6296 * @see #restoreHierarchyState 6297 * @see #dispatchRestoreInstanceState 6298 */ onRestoreInstanceState(Parcelable state)6299 protected void onRestoreInstanceState(Parcelable state) { 6300 mPrivateFlags |= SAVE_STATE_CALLED; 6301 if (state != BaseSavedState.EMPTY_STATE && state != null) { 6302 throw new IllegalArgumentException("Wrong state class, expecting View State but " 6303 + "received " + state.getClass().toString() + " instead. This usually happens " 6304 + "when two views of different type have the same id in the same hierarchy. " 6305 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 6306 + "other views do not use the same id."); 6307 } 6308 } 6309 6310 /** 6311 * <p>Return the time at which the drawing of the view hierarchy started.</p> 6312 * 6313 * @return the drawing start time in milliseconds 6314 */ getDrawingTime()6315 public long getDrawingTime() { 6316 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 6317 } 6318 6319 /** 6320 * <p>Enables or disables the duplication of the parent's state into this view. When 6321 * duplication is enabled, this view gets its drawable state from its parent rather 6322 * than from its own internal properties.</p> 6323 * 6324 * <p>Note: in the current implementation, setting this property to true after the 6325 * view was added to a ViewGroup might have no effect at all. This property should 6326 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 6327 * 6328 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 6329 * property is enabled, an exception will be thrown.</p> 6330 * 6331 * @param enabled True to enable duplication of the parent's drawable state, false 6332 * to disable it. 6333 * 6334 * @see #getDrawableState() 6335 * @see #isDuplicateParentStateEnabled() 6336 */ setDuplicateParentStateEnabled(boolean enabled)6337 public void setDuplicateParentStateEnabled(boolean enabled) { 6338 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 6339 } 6340 6341 /** 6342 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 6343 * 6344 * @return True if this view's drawable state is duplicated from the parent, 6345 * false otherwise 6346 * 6347 * @see #getDrawableState() 6348 * @see #setDuplicateParentStateEnabled(boolean) 6349 */ isDuplicateParentStateEnabled()6350 public boolean isDuplicateParentStateEnabled() { 6351 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 6352 } 6353 6354 /** 6355 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 6356 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 6357 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 6358 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 6359 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 6360 * null.</p> 6361 * 6362 * @param enabled true to enable the drawing cache, false otherwise 6363 * 6364 * @see #isDrawingCacheEnabled() 6365 * @see #getDrawingCache() 6366 * @see #buildDrawingCache() 6367 */ setDrawingCacheEnabled(boolean enabled)6368 public void setDrawingCacheEnabled(boolean enabled) { 6369 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 6370 } 6371 6372 /** 6373 * <p>Indicates whether the drawing cache is enabled for this view.</p> 6374 * 6375 * @return true if the drawing cache is enabled 6376 * 6377 * @see #setDrawingCacheEnabled(boolean) 6378 * @see #getDrawingCache() 6379 */ 6380 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()6381 public boolean isDrawingCacheEnabled() { 6382 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 6383 } 6384 6385 /** 6386 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 6387 * 6388 * @return A non-scaled bitmap representing this view or null if cache is disabled. 6389 * 6390 * @see #getDrawingCache(boolean) 6391 */ getDrawingCache()6392 public Bitmap getDrawingCache() { 6393 return getDrawingCache(false); 6394 } 6395 6396 /** 6397 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 6398 * is null when caching is disabled. If caching is enabled and the cache is not ready, 6399 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 6400 * draw from the cache when the cache is enabled. To benefit from the cache, you must 6401 * request the drawing cache by calling this method and draw it on screen if the 6402 * returned bitmap is not null.</p> 6403 * 6404 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 6405 * this method will create a bitmap of the same size as this view. Because this bitmap 6406 * will be drawn scaled by the parent ViewGroup, the result on screen might show 6407 * scaling artifacts. To avoid such artifacts, you should call this method by setting 6408 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 6409 * size than the view. This implies that your application must be able to handle this 6410 * size.</p> 6411 * 6412 * @param autoScale Indicates whether the generated bitmap should be scaled based on 6413 * the current density of the screen when the application is in compatibility 6414 * mode. 6415 * 6416 * @return A bitmap representing this view or null if cache is disabled. 6417 * 6418 * @see #setDrawingCacheEnabled(boolean) 6419 * @see #isDrawingCacheEnabled() 6420 * @see #buildDrawingCache(boolean) 6421 * @see #destroyDrawingCache() 6422 */ getDrawingCache(boolean autoScale)6423 public Bitmap getDrawingCache(boolean autoScale) { 6424 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 6425 return null; 6426 } 6427 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 6428 buildDrawingCache(autoScale); 6429 } 6430 return autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) : 6431 (mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get()); 6432 } 6433 6434 /** 6435 * <p>Frees the resources used by the drawing cache. If you call 6436 * {@link #buildDrawingCache()} manually without calling 6437 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 6438 * should cleanup the cache with this method afterwards.</p> 6439 * 6440 * @see #setDrawingCacheEnabled(boolean) 6441 * @see #buildDrawingCache() 6442 * @see #getDrawingCache() 6443 */ destroyDrawingCache()6444 public void destroyDrawingCache() { 6445 if (mDrawingCache != null) { 6446 final Bitmap bitmap = mDrawingCache.get(); 6447 if (bitmap != null) bitmap.recycle(); 6448 mDrawingCache = null; 6449 } 6450 if (mUnscaledDrawingCache != null) { 6451 final Bitmap bitmap = mUnscaledDrawingCache.get(); 6452 if (bitmap != null) bitmap.recycle(); 6453 mUnscaledDrawingCache = null; 6454 } 6455 } 6456 6457 /** 6458 * Setting a solid background color for the drawing cache's bitmaps will improve 6459 * perfromance and memory usage. Note, though that this should only be used if this 6460 * view will always be drawn on top of a solid color. 6461 * 6462 * @param color The background color to use for the drawing cache's bitmap 6463 * 6464 * @see #setDrawingCacheEnabled(boolean) 6465 * @see #buildDrawingCache() 6466 * @see #getDrawingCache() 6467 */ setDrawingCacheBackgroundColor(int color)6468 public void setDrawingCacheBackgroundColor(int color) { 6469 if (color != mDrawingCacheBackgroundColor) { 6470 mDrawingCacheBackgroundColor = color; 6471 mPrivateFlags &= ~DRAWING_CACHE_VALID; 6472 } 6473 } 6474 6475 /** 6476 * @see #setDrawingCacheBackgroundColor(int) 6477 * 6478 * @return The background color to used for the drawing cache's bitmap 6479 */ getDrawingCacheBackgroundColor()6480 public int getDrawingCacheBackgroundColor() { 6481 return mDrawingCacheBackgroundColor; 6482 } 6483 6484 /** 6485 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 6486 * 6487 * @see #buildDrawingCache(boolean) 6488 */ buildDrawingCache()6489 public void buildDrawingCache() { 6490 buildDrawingCache(false); 6491 } 6492 6493 /** 6494 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 6495 * 6496 * <p>If you call {@link #buildDrawingCache()} manually without calling 6497 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 6498 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 6499 * 6500 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 6501 * this method will create a bitmap of the same size as this view. Because this bitmap 6502 * will be drawn scaled by the parent ViewGroup, the result on screen might show 6503 * scaling artifacts. To avoid such artifacts, you should call this method by setting 6504 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 6505 * size than the view. This implies that your application must be able to handle this 6506 * size.</p> 6507 * 6508 * @see #getDrawingCache() 6509 * @see #destroyDrawingCache() 6510 */ buildDrawingCache(boolean autoScale)6511 public void buildDrawingCache(boolean autoScale) { 6512 if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ? 6513 (mDrawingCache == null || mDrawingCache.get() == null) : 6514 (mUnscaledDrawingCache == null || mUnscaledDrawingCache.get() == null))) { 6515 6516 if (ViewDebug.TRACE_HIERARCHY) { 6517 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE); 6518 } 6519 if (Config.DEBUG && ViewDebug.profileDrawing) { 6520 EventLog.writeEvent(60002, hashCode()); 6521 } 6522 6523 int width = mRight - mLeft; 6524 int height = mBottom - mTop; 6525 6526 final AttachInfo attachInfo = mAttachInfo; 6527 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 6528 6529 if (autoScale && scalingRequired) { 6530 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 6531 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 6532 } 6533 6534 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 6535 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 6536 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 6537 6538 if (width <= 0 || height <= 0 || 6539 // Projected bitmap size in bytes 6540 (width * height * (opaque && !use32BitCache ? 2 : 4) > 6541 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) { 6542 destroyDrawingCache(); 6543 return; 6544 } 6545 6546 boolean clear = true; 6547 Bitmap bitmap = autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) : 6548 (mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get()); 6549 6550 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 6551 Bitmap.Config quality; 6552 if (!opaque) { 6553 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 6554 case DRAWING_CACHE_QUALITY_AUTO: 6555 quality = Bitmap.Config.ARGB_8888; 6556 break; 6557 case DRAWING_CACHE_QUALITY_LOW: 6558 quality = Bitmap.Config.ARGB_4444; 6559 break; 6560 case DRAWING_CACHE_QUALITY_HIGH: 6561 quality = Bitmap.Config.ARGB_8888; 6562 break; 6563 default: 6564 quality = Bitmap.Config.ARGB_8888; 6565 break; 6566 } 6567 } else { 6568 // Optimization for translucent windows 6569 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 6570 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 6571 } 6572 6573 // Try to cleanup memory 6574 if (bitmap != null) bitmap.recycle(); 6575 6576 try { 6577 bitmap = Bitmap.createBitmap(width, height, quality); 6578 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 6579 if (autoScale) { 6580 mDrawingCache = new SoftReference<Bitmap>(bitmap); 6581 } else { 6582 mUnscaledDrawingCache = new SoftReference<Bitmap>(bitmap); 6583 } 6584 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 6585 } catch (OutOfMemoryError e) { 6586 // If there is not enough memory to create the bitmap cache, just 6587 // ignore the issue as bitmap caches are not required to draw the 6588 // view hierarchy 6589 if (autoScale) { 6590 mDrawingCache = null; 6591 } else { 6592 mUnscaledDrawingCache = null; 6593 } 6594 return; 6595 } 6596 6597 clear = drawingCacheBackgroundColor != 0; 6598 } 6599 6600 Canvas canvas; 6601 if (attachInfo != null) { 6602 canvas = attachInfo.mCanvas; 6603 if (canvas == null) { 6604 canvas = new Canvas(); 6605 } 6606 canvas.setBitmap(bitmap); 6607 // Temporarily clobber the cached Canvas in case one of our children 6608 // is also using a drawing cache. Without this, the children would 6609 // steal the canvas by attaching their own bitmap to it and bad, bad 6610 // thing would happen (invisible views, corrupted drawings, etc.) 6611 attachInfo.mCanvas = null; 6612 } else { 6613 // This case should hopefully never or seldom happen 6614 canvas = new Canvas(bitmap); 6615 } 6616 6617 if (clear) { 6618 bitmap.eraseColor(drawingCacheBackgroundColor); 6619 } 6620 6621 computeScroll(); 6622 final int restoreCount = canvas.save(); 6623 6624 if (autoScale && scalingRequired) { 6625 final float scale = attachInfo.mApplicationScale; 6626 canvas.scale(scale, scale); 6627 } 6628 6629 canvas.translate(-mScrollX, -mScrollY); 6630 6631 mPrivateFlags |= DRAWN; 6632 mPrivateFlags |= DRAWING_CACHE_VALID; 6633 6634 // Fast path for layouts with no backgrounds 6635 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { 6636 if (ViewDebug.TRACE_HIERARCHY) { 6637 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW); 6638 } 6639 mPrivateFlags &= ~DIRTY_MASK; 6640 dispatchDraw(canvas); 6641 } else { 6642 draw(canvas); 6643 } 6644 6645 canvas.restoreToCount(restoreCount); 6646 6647 if (attachInfo != null) { 6648 // Restore the cached Canvas for our siblings 6649 attachInfo.mCanvas = canvas; 6650 } 6651 } 6652 } 6653 6654 /** 6655 * Create a snapshot of the view into a bitmap. We should probably make 6656 * some form of this public, but should think about the API. 6657 */ createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren)6658 Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 6659 int width = mRight - mLeft; 6660 int height = mBottom - mTop; 6661 6662 final AttachInfo attachInfo = mAttachInfo; 6663 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 6664 width = (int) ((width * scale) + 0.5f); 6665 height = (int) ((height * scale) + 0.5f); 6666 6667 Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1, height > 0 ? height : 1, quality); 6668 if (bitmap == null) { 6669 throw new OutOfMemoryError(); 6670 } 6671 6672 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 6673 6674 Canvas canvas; 6675 if (attachInfo != null) { 6676 canvas = attachInfo.mCanvas; 6677 if (canvas == null) { 6678 canvas = new Canvas(); 6679 } 6680 canvas.setBitmap(bitmap); 6681 // Temporarily clobber the cached Canvas in case one of our children 6682 // is also using a drawing cache. Without this, the children would 6683 // steal the canvas by attaching their own bitmap to it and bad, bad 6684 // things would happen (invisible views, corrupted drawings, etc.) 6685 attachInfo.mCanvas = null; 6686 } else { 6687 // This case should hopefully never or seldom happen 6688 canvas = new Canvas(bitmap); 6689 } 6690 6691 if ((backgroundColor & 0xff000000) != 0) { 6692 bitmap.eraseColor(backgroundColor); 6693 } 6694 6695 computeScroll(); 6696 final int restoreCount = canvas.save(); 6697 canvas.scale(scale, scale); 6698 canvas.translate(-mScrollX, -mScrollY); 6699 6700 // Temporarily remove the dirty mask 6701 int flags = mPrivateFlags; 6702 mPrivateFlags &= ~DIRTY_MASK; 6703 6704 // Fast path for layouts with no backgrounds 6705 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { 6706 dispatchDraw(canvas); 6707 } else { 6708 draw(canvas); 6709 } 6710 6711 mPrivateFlags = flags; 6712 6713 canvas.restoreToCount(restoreCount); 6714 6715 if (attachInfo != null) { 6716 // Restore the cached Canvas for our siblings 6717 attachInfo.mCanvas = canvas; 6718 } 6719 6720 return bitmap; 6721 } 6722 6723 /** 6724 * Indicates whether this View is currently in edit mode. A View is usually 6725 * in edit mode when displayed within a developer tool. For instance, if 6726 * this View is being drawn by a visual user interface builder, this method 6727 * should return true. 6728 * 6729 * Subclasses should check the return value of this method to provide 6730 * different behaviors if their normal behavior might interfere with the 6731 * host environment. For instance: the class spawns a thread in its 6732 * constructor, the drawing code relies on device-specific features, etc. 6733 * 6734 * This method is usually checked in the drawing code of custom widgets. 6735 * 6736 * @return True if this View is in edit mode, false otherwise. 6737 */ isInEditMode()6738 public boolean isInEditMode() { 6739 return false; 6740 } 6741 6742 /** 6743 * If the View draws content inside its padding and enables fading edges, 6744 * it needs to support padding offsets. Padding offsets are added to the 6745 * fading edges to extend the length of the fade so that it covers pixels 6746 * drawn inside the padding. 6747 * 6748 * Subclasses of this class should override this method if they need 6749 * to draw content inside the padding. 6750 * 6751 * @return True if padding offset must be applied, false otherwise. 6752 * 6753 * @see #getLeftPaddingOffset() 6754 * @see #getRightPaddingOffset() 6755 * @see #getTopPaddingOffset() 6756 * @see #getBottomPaddingOffset() 6757 * 6758 * @since CURRENT 6759 */ isPaddingOffsetRequired()6760 protected boolean isPaddingOffsetRequired() { 6761 return false; 6762 } 6763 6764 /** 6765 * Amount by which to extend the left fading region. Called only when 6766 * {@link #isPaddingOffsetRequired()} returns true. 6767 * 6768 * @return The left padding offset in pixels. 6769 * 6770 * @see #isPaddingOffsetRequired() 6771 * 6772 * @since CURRENT 6773 */ getLeftPaddingOffset()6774 protected int getLeftPaddingOffset() { 6775 return 0; 6776 } 6777 6778 /** 6779 * Amount by which to extend the right fading region. Called only when 6780 * {@link #isPaddingOffsetRequired()} returns true. 6781 * 6782 * @return The right padding offset in pixels. 6783 * 6784 * @see #isPaddingOffsetRequired() 6785 * 6786 * @since CURRENT 6787 */ getRightPaddingOffset()6788 protected int getRightPaddingOffset() { 6789 return 0; 6790 } 6791 6792 /** 6793 * Amount by which to extend the top fading region. Called only when 6794 * {@link #isPaddingOffsetRequired()} returns true. 6795 * 6796 * @return The top padding offset in pixels. 6797 * 6798 * @see #isPaddingOffsetRequired() 6799 * 6800 * @since CURRENT 6801 */ getTopPaddingOffset()6802 protected int getTopPaddingOffset() { 6803 return 0; 6804 } 6805 6806 /** 6807 * Amount by which to extend the bottom fading region. Called only when 6808 * {@link #isPaddingOffsetRequired()} returns true. 6809 * 6810 * @return The bottom padding offset in pixels. 6811 * 6812 * @see #isPaddingOffsetRequired() 6813 * 6814 * @since CURRENT 6815 */ getBottomPaddingOffset()6816 protected int getBottomPaddingOffset() { 6817 return 0; 6818 } 6819 6820 /** 6821 * Manually render this view (and all of its children) to the given Canvas. 6822 * The view must have already done a full layout before this function is 6823 * called. When implementing a view, do not override this method; instead, 6824 * you should implement {@link #onDraw}. 6825 * 6826 * @param canvas The Canvas to which the View is rendered. 6827 */ draw(Canvas canvas)6828 public void draw(Canvas canvas) { 6829 if (ViewDebug.TRACE_HIERARCHY) { 6830 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW); 6831 } 6832 6833 final int privateFlags = mPrivateFlags; 6834 final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE && 6835 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 6836 mPrivateFlags = (privateFlags & ~DIRTY_MASK) | DRAWN; 6837 6838 /* 6839 * Draw traversal performs several drawing steps which must be executed 6840 * in the appropriate order: 6841 * 6842 * 1. Draw the background 6843 * 2. If necessary, save the canvas' layers to prepare for fading 6844 * 3. Draw view's content 6845 * 4. Draw children 6846 * 5. If necessary, draw the fading edges and restore layers 6847 * 6. Draw decorations (scrollbars for instance) 6848 */ 6849 6850 // Step 1, draw the background, if needed 6851 int saveCount; 6852 6853 if (!dirtyOpaque) { 6854 final Drawable background = mBGDrawable; 6855 if (background != null) { 6856 final int scrollX = mScrollX; 6857 final int scrollY = mScrollY; 6858 6859 if (mBackgroundSizeChanged) { 6860 background.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 6861 mBackgroundSizeChanged = false; 6862 } 6863 6864 if ((scrollX | scrollY) == 0) { 6865 background.draw(canvas); 6866 } else { 6867 canvas.translate(scrollX, scrollY); 6868 background.draw(canvas); 6869 canvas.translate(-scrollX, -scrollY); 6870 } 6871 } 6872 } 6873 6874 // skip step 2 & 5 if possible (common case) 6875 final int viewFlags = mViewFlags; 6876 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 6877 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 6878 if (!verticalEdges && !horizontalEdges) { 6879 // Step 3, draw the content 6880 if (!dirtyOpaque) onDraw(canvas); 6881 6882 // Step 4, draw the children 6883 dispatchDraw(canvas); 6884 6885 // Step 6, draw decorations (scrollbars) 6886 onDrawScrollBars(canvas); 6887 6888 // we're done... 6889 return; 6890 } 6891 6892 /* 6893 * Here we do the full fledged routine... 6894 * (this is an uncommon case where speed matters less, 6895 * this is why we repeat some of the tests that have been 6896 * done above) 6897 */ 6898 6899 boolean drawTop = false; 6900 boolean drawBottom = false; 6901 boolean drawLeft = false; 6902 boolean drawRight = false; 6903 6904 float topFadeStrength = 0.0f; 6905 float bottomFadeStrength = 0.0f; 6906 float leftFadeStrength = 0.0f; 6907 float rightFadeStrength = 0.0f; 6908 6909 // Step 2, save the canvas' layers 6910 int paddingLeft = mPaddingLeft; 6911 int paddingTop = mPaddingTop; 6912 6913 final boolean offsetRequired = isPaddingOffsetRequired(); 6914 if (offsetRequired) { 6915 paddingLeft += getLeftPaddingOffset(); 6916 paddingTop += getTopPaddingOffset(); 6917 } 6918 6919 int left = mScrollX + paddingLeft; 6920 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 6921 int top = mScrollY + paddingTop; 6922 int bottom = top + mBottom - mTop - mPaddingBottom - paddingTop; 6923 6924 if (offsetRequired) { 6925 right += getRightPaddingOffset(); 6926 bottom += getBottomPaddingOffset(); 6927 } 6928 6929 final ScrollabilityCache scrollabilityCache = mScrollCache; 6930 int length = scrollabilityCache.fadingEdgeLength; 6931 6932 // clip the fade length if top and bottom fades overlap 6933 // overlapping fades produce odd-looking artifacts 6934 if (verticalEdges && (top + length > bottom - length)) { 6935 length = (bottom - top) / 2; 6936 } 6937 6938 // also clip horizontal fades if necessary 6939 if (horizontalEdges && (left + length > right - length)) { 6940 length = (right - left) / 2; 6941 } 6942 6943 if (verticalEdges) { 6944 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 6945 drawTop = topFadeStrength >= 0.0f; 6946 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 6947 drawBottom = bottomFadeStrength >= 0.0f; 6948 } 6949 6950 if (horizontalEdges) { 6951 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 6952 drawLeft = leftFadeStrength >= 0.0f; 6953 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 6954 drawRight = rightFadeStrength >= 0.0f; 6955 } 6956 6957 saveCount = canvas.getSaveCount(); 6958 6959 int solidColor = getSolidColor(); 6960 if (solidColor == 0) { 6961 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 6962 6963 if (drawTop) { 6964 canvas.saveLayer(left, top, right, top + length, null, flags); 6965 } 6966 6967 if (drawBottom) { 6968 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 6969 } 6970 6971 if (drawLeft) { 6972 canvas.saveLayer(left, top, left + length, bottom, null, flags); 6973 } 6974 6975 if (drawRight) { 6976 canvas.saveLayer(right - length, top, right, bottom, null, flags); 6977 } 6978 } else { 6979 scrollabilityCache.setFadeColor(solidColor); 6980 } 6981 6982 // Step 3, draw the content 6983 if (!dirtyOpaque) onDraw(canvas); 6984 6985 // Step 4, draw the children 6986 dispatchDraw(canvas); 6987 6988 // Step 5, draw the fade effect and restore layers 6989 final Paint p = scrollabilityCache.paint; 6990 final Matrix matrix = scrollabilityCache.matrix; 6991 final Shader fade = scrollabilityCache.shader; 6992 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 6993 6994 if (drawTop) { 6995 matrix.setScale(1, fadeHeight * topFadeStrength); 6996 matrix.postTranslate(left, top); 6997 fade.setLocalMatrix(matrix); 6998 canvas.drawRect(left, top, right, top + length, p); 6999 } 7000 7001 if (drawBottom) { 7002 matrix.setScale(1, fadeHeight * bottomFadeStrength); 7003 matrix.postRotate(180); 7004 matrix.postTranslate(left, bottom); 7005 fade.setLocalMatrix(matrix); 7006 canvas.drawRect(left, bottom - length, right, bottom, p); 7007 } 7008 7009 if (drawLeft) { 7010 matrix.setScale(1, fadeHeight * leftFadeStrength); 7011 matrix.postRotate(-90); 7012 matrix.postTranslate(left, top); 7013 fade.setLocalMatrix(matrix); 7014 canvas.drawRect(left, top, left + length, bottom, p); 7015 } 7016 7017 if (drawRight) { 7018 matrix.setScale(1, fadeHeight * rightFadeStrength); 7019 matrix.postRotate(90); 7020 matrix.postTranslate(right, top); 7021 fade.setLocalMatrix(matrix); 7022 canvas.drawRect(right - length, top, right, bottom, p); 7023 } 7024 7025 canvas.restoreToCount(saveCount); 7026 7027 // Step 6, draw decorations (scrollbars) 7028 onDrawScrollBars(canvas); 7029 } 7030 7031 /** 7032 * Override this if your view is known to always be drawn on top of a solid color background, 7033 * and needs to draw fading edges. Returning a non-zero color enables the view system to 7034 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 7035 * should be set to 0xFF. 7036 * 7037 * @see #setVerticalFadingEdgeEnabled 7038 * @see #setHorizontalFadingEdgeEnabled 7039 * 7040 * @return The known solid color background for this view, or 0 if the color may vary 7041 */ getSolidColor()7042 public int getSolidColor() { 7043 return 0; 7044 } 7045 7046 /** 7047 * Build a human readable string representation of the specified view flags. 7048 * 7049 * @param flags the view flags to convert to a string 7050 * @return a String representing the supplied flags 7051 */ printFlags(int flags)7052 private static String printFlags(int flags) { 7053 String output = ""; 7054 int numFlags = 0; 7055 if ((flags & FOCUSABLE_MASK) == FOCUSABLE) { 7056 output += "TAKES_FOCUS"; 7057 numFlags++; 7058 } 7059 7060 switch (flags & VISIBILITY_MASK) { 7061 case INVISIBLE: 7062 if (numFlags > 0) { 7063 output += " "; 7064 } 7065 output += "INVISIBLE"; 7066 // USELESS HERE numFlags++; 7067 break; 7068 case GONE: 7069 if (numFlags > 0) { 7070 output += " "; 7071 } 7072 output += "GONE"; 7073 // USELESS HERE numFlags++; 7074 break; 7075 default: 7076 break; 7077 } 7078 return output; 7079 } 7080 7081 /** 7082 * Build a human readable string representation of the specified private 7083 * view flags. 7084 * 7085 * @param privateFlags the private view flags to convert to a string 7086 * @return a String representing the supplied flags 7087 */ printPrivateFlags(int privateFlags)7088 private static String printPrivateFlags(int privateFlags) { 7089 String output = ""; 7090 int numFlags = 0; 7091 7092 if ((privateFlags & WANTS_FOCUS) == WANTS_FOCUS) { 7093 output += "WANTS_FOCUS"; 7094 numFlags++; 7095 } 7096 7097 if ((privateFlags & FOCUSED) == FOCUSED) { 7098 if (numFlags > 0) { 7099 output += " "; 7100 } 7101 output += "FOCUSED"; 7102 numFlags++; 7103 } 7104 7105 if ((privateFlags & SELECTED) == SELECTED) { 7106 if (numFlags > 0) { 7107 output += " "; 7108 } 7109 output += "SELECTED"; 7110 numFlags++; 7111 } 7112 7113 if ((privateFlags & IS_ROOT_NAMESPACE) == IS_ROOT_NAMESPACE) { 7114 if (numFlags > 0) { 7115 output += " "; 7116 } 7117 output += "IS_ROOT_NAMESPACE"; 7118 numFlags++; 7119 } 7120 7121 if ((privateFlags & HAS_BOUNDS) == HAS_BOUNDS) { 7122 if (numFlags > 0) { 7123 output += " "; 7124 } 7125 output += "HAS_BOUNDS"; 7126 numFlags++; 7127 } 7128 7129 if ((privateFlags & DRAWN) == DRAWN) { 7130 if (numFlags > 0) { 7131 output += " "; 7132 } 7133 output += "DRAWN"; 7134 // USELESS HERE numFlags++; 7135 } 7136 return output; 7137 } 7138 7139 /** 7140 * <p>Indicates whether or not this view's layout will be requested during 7141 * the next hierarchy layout pass.</p> 7142 * 7143 * @return true if the layout will be forced during next layout pass 7144 */ isLayoutRequested()7145 public boolean isLayoutRequested() { 7146 return (mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT; 7147 } 7148 7149 /** 7150 * Assign a size and position to a view and all of its 7151 * descendants 7152 * 7153 * <p>This is the second phase of the layout mechanism. 7154 * (The first is measuring). In this phase, each parent calls 7155 * layout on all of its children to position them. 7156 * This is typically done using the child measurements 7157 * that were stored in the measure pass(). 7158 * 7159 * Derived classes with children should override 7160 * onLayout. In that method, they should 7161 * call layout on each of their their children. 7162 * 7163 * @param l Left position, relative to parent 7164 * @param t Top position, relative to parent 7165 * @param r Right position, relative to parent 7166 * @param b Bottom position, relative to parent 7167 */ layout(int l, int t, int r, int b)7168 public final void layout(int l, int t, int r, int b) { 7169 boolean changed = setFrame(l, t, r, b); 7170 if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) { 7171 if (ViewDebug.TRACE_HIERARCHY) { 7172 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT); 7173 } 7174 7175 onLayout(changed, l, t, r, b); 7176 mPrivateFlags &= ~LAYOUT_REQUIRED; 7177 } 7178 mPrivateFlags &= ~FORCE_LAYOUT; 7179 } 7180 7181 /** 7182 * Called from layout when this view should 7183 * assign a size and position to each of its children. 7184 * 7185 * Derived classes with children should override 7186 * this method and call layout on each of 7187 * their their children. 7188 * @param changed This is a new size or position for this view 7189 * @param left Left position, relative to parent 7190 * @param top Top position, relative to parent 7191 * @param right Right position, relative to parent 7192 * @param bottom Bottom position, relative to parent 7193 */ onLayout(boolean changed, int left, int top, int right, int bottom)7194 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 7195 } 7196 7197 /** 7198 * Assign a size and position to this view. 7199 * 7200 * This is called from layout. 7201 * 7202 * @param left Left position, relative to parent 7203 * @param top Top position, relative to parent 7204 * @param right Right position, relative to parent 7205 * @param bottom Bottom position, relative to parent 7206 * @return true if the new size and position are different than the 7207 * previous ones 7208 * {@hide} 7209 */ setFrame(int left, int top, int right, int bottom)7210 protected boolean setFrame(int left, int top, int right, int bottom) { 7211 boolean changed = false; 7212 7213 if (DBG) { 7214 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 7215 + right + "," + bottom + ")"); 7216 } 7217 7218 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 7219 changed = true; 7220 7221 // Remember our drawn bit 7222 int drawn = mPrivateFlags & DRAWN; 7223 7224 // Invalidate our old position 7225 invalidate(); 7226 7227 7228 int oldWidth = mRight - mLeft; 7229 int oldHeight = mBottom - mTop; 7230 7231 mLeft = left; 7232 mTop = top; 7233 mRight = right; 7234 mBottom = bottom; 7235 7236 mPrivateFlags |= HAS_BOUNDS; 7237 7238 int newWidth = right - left; 7239 int newHeight = bottom - top; 7240 7241 if (newWidth != oldWidth || newHeight != oldHeight) { 7242 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 7243 } 7244 7245 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE) { 7246 // If we are visible, force the DRAWN bit to on so that 7247 // this invalidate will go through (at least to our parent). 7248 // This is because someone may have invalidated this view 7249 // before this call to setFrame came in, therby clearing 7250 // the DRAWN bit. 7251 mPrivateFlags |= DRAWN; 7252 invalidate(); 7253 } 7254 7255 // Reset drawn bit to original value (invalidate turns it off) 7256 mPrivateFlags |= drawn; 7257 7258 mBackgroundSizeChanged = true; 7259 } 7260 return changed; 7261 } 7262 7263 /** 7264 * Finalize inflating a view from XML. This is called as the last phase 7265 * of inflation, after all child views have been added. 7266 * 7267 * <p>Even if the subclass overrides onFinishInflate, they should always be 7268 * sure to call the super method, so that we get called. 7269 */ onFinishInflate()7270 protected void onFinishInflate() { 7271 } 7272 7273 /** 7274 * Returns the resources associated with this view. 7275 * 7276 * @return Resources object. 7277 */ getResources()7278 public Resources getResources() { 7279 return mResources; 7280 } 7281 7282 /** 7283 * Invalidates the specified Drawable. 7284 * 7285 * @param drawable the drawable to invalidate 7286 */ invalidateDrawable(Drawable drawable)7287 public void invalidateDrawable(Drawable drawable) { 7288 if (verifyDrawable(drawable)) { 7289 final Rect dirty = drawable.getBounds(); 7290 final int scrollX = mScrollX; 7291 final int scrollY = mScrollY; 7292 7293 invalidate(dirty.left + scrollX, dirty.top + scrollY, 7294 dirty.right + scrollX, dirty.bottom + scrollY); 7295 } 7296 } 7297 7298 /** 7299 * Schedules an action on a drawable to occur at a specified time. 7300 * 7301 * @param who the recipient of the action 7302 * @param what the action to run on the drawable 7303 * @param when the time at which the action must occur. Uses the 7304 * {@link SystemClock#uptimeMillis} timebase. 7305 */ scheduleDrawable(Drawable who, Runnable what, long when)7306 public void scheduleDrawable(Drawable who, Runnable what, long when) { 7307 if (verifyDrawable(who) && what != null && mAttachInfo != null) { 7308 mAttachInfo.mHandler.postAtTime(what, who, when); 7309 } 7310 } 7311 7312 /** 7313 * Cancels a scheduled action on a drawable. 7314 * 7315 * @param who the recipient of the action 7316 * @param what the action to cancel 7317 */ unscheduleDrawable(Drawable who, Runnable what)7318 public void unscheduleDrawable(Drawable who, Runnable what) { 7319 if (verifyDrawable(who) && what != null && mAttachInfo != null) { 7320 mAttachInfo.mHandler.removeCallbacks(what, who); 7321 } 7322 } 7323 7324 /** 7325 * Unschedule any events associated with the given Drawable. This can be 7326 * used when selecting a new Drawable into a view, so that the previous 7327 * one is completely unscheduled. 7328 * 7329 * @param who The Drawable to unschedule. 7330 * 7331 * @see #drawableStateChanged 7332 */ unscheduleDrawable(Drawable who)7333 public void unscheduleDrawable(Drawable who) { 7334 if (mAttachInfo != null) { 7335 mAttachInfo.mHandler.removeCallbacksAndMessages(who); 7336 } 7337 } 7338 7339 /** 7340 * If your view subclass is displaying its own Drawable objects, it should 7341 * override this function and return true for any Drawable it is 7342 * displaying. This allows animations for those drawables to be 7343 * scheduled. 7344 * 7345 * <p>Be sure to call through to the super class when overriding this 7346 * function. 7347 * 7348 * @param who The Drawable to verify. Return true if it is one you are 7349 * displaying, else return the result of calling through to the 7350 * super class. 7351 * 7352 * @return boolean If true than the Drawable is being displayed in the 7353 * view; else false and it is not allowed to animate. 7354 * 7355 * @see #unscheduleDrawable 7356 * @see #drawableStateChanged 7357 */ verifyDrawable(Drawable who)7358 protected boolean verifyDrawable(Drawable who) { 7359 return who == mBGDrawable; 7360 } 7361 7362 /** 7363 * This function is called whenever the state of the view changes in such 7364 * a way that it impacts the state of drawables being shown. 7365 * 7366 * <p>Be sure to call through to the superclass when overriding this 7367 * function. 7368 * 7369 * @see Drawable#setState 7370 */ drawableStateChanged()7371 protected void drawableStateChanged() { 7372 Drawable d = mBGDrawable; 7373 if (d != null && d.isStateful()) { 7374 d.setState(getDrawableState()); 7375 } 7376 } 7377 7378 /** 7379 * Call this to force a view to update its drawable state. This will cause 7380 * drawableStateChanged to be called on this view. Views that are interested 7381 * in the new state should call getDrawableState. 7382 * 7383 * @see #drawableStateChanged 7384 * @see #getDrawableState 7385 */ refreshDrawableState()7386 public void refreshDrawableState() { 7387 mPrivateFlags |= DRAWABLE_STATE_DIRTY; 7388 drawableStateChanged(); 7389 7390 ViewParent parent = mParent; 7391 if (parent != null) { 7392 parent.childDrawableStateChanged(this); 7393 } 7394 } 7395 7396 /** 7397 * Return an array of resource IDs of the drawable states representing the 7398 * current state of the view. 7399 * 7400 * @return The current drawable state 7401 * 7402 * @see Drawable#setState 7403 * @see #drawableStateChanged 7404 * @see #onCreateDrawableState 7405 */ getDrawableState()7406 public final int[] getDrawableState() { 7407 if ((mDrawableState != null) && ((mPrivateFlags & DRAWABLE_STATE_DIRTY) == 0)) { 7408 return mDrawableState; 7409 } else { 7410 mDrawableState = onCreateDrawableState(0); 7411 mPrivateFlags &= ~DRAWABLE_STATE_DIRTY; 7412 return mDrawableState; 7413 } 7414 } 7415 7416 /** 7417 * Generate the new {@link android.graphics.drawable.Drawable} state for 7418 * this view. This is called by the view 7419 * system when the cached Drawable state is determined to be invalid. To 7420 * retrieve the current state, you should use {@link #getDrawableState}. 7421 * 7422 * @param extraSpace if non-zero, this is the number of extra entries you 7423 * would like in the returned array in which you can place your own 7424 * states. 7425 * 7426 * @return Returns an array holding the current {@link Drawable} state of 7427 * the view. 7428 * 7429 * @see #mergeDrawableStates 7430 */ onCreateDrawableState(int extraSpace)7431 protected int[] onCreateDrawableState(int extraSpace) { 7432 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 7433 mParent instanceof View) { 7434 return ((View) mParent).onCreateDrawableState(extraSpace); 7435 } 7436 7437 int[] drawableState; 7438 7439 int privateFlags = mPrivateFlags; 7440 7441 int viewStateIndex = (((privateFlags & PRESSED) != 0) ? 1 : 0); 7442 7443 viewStateIndex = (viewStateIndex << 1) 7444 + (((mViewFlags & ENABLED_MASK) == ENABLED) ? 1 : 0); 7445 7446 viewStateIndex = (viewStateIndex << 1) + (isFocused() ? 1 : 0); 7447 7448 viewStateIndex = (viewStateIndex << 1) 7449 + (((privateFlags & SELECTED) != 0) ? 1 : 0); 7450 7451 final boolean hasWindowFocus = hasWindowFocus(); 7452 viewStateIndex = (viewStateIndex << 1) + (hasWindowFocus ? 1 : 0); 7453 7454 drawableState = VIEW_STATE_SETS[viewStateIndex]; 7455 7456 //noinspection ConstantIfStatement 7457 if (false) { 7458 Log.i("View", "drawableStateIndex=" + viewStateIndex); 7459 Log.i("View", toString() 7460 + " pressed=" + ((privateFlags & PRESSED) != 0) 7461 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 7462 + " fo=" + hasFocus() 7463 + " sl=" + ((privateFlags & SELECTED) != 0) 7464 + " wf=" + hasWindowFocus 7465 + ": " + Arrays.toString(drawableState)); 7466 } 7467 7468 if (extraSpace == 0) { 7469 return drawableState; 7470 } 7471 7472 final int[] fullState; 7473 if (drawableState != null) { 7474 fullState = new int[drawableState.length + extraSpace]; 7475 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 7476 } else { 7477 fullState = new int[extraSpace]; 7478 } 7479 7480 return fullState; 7481 } 7482 7483 /** 7484 * Merge your own state values in <var>additionalState</var> into the base 7485 * state values <var>baseState</var> that were returned by 7486 * {@link #onCreateDrawableState}. 7487 * 7488 * @param baseState The base state values returned by 7489 * {@link #onCreateDrawableState}, which will be modified to also hold your 7490 * own additional state values. 7491 * 7492 * @param additionalState The additional state values you would like 7493 * added to <var>baseState</var>; this array is not modified. 7494 * 7495 * @return As a convenience, the <var>baseState</var> array you originally 7496 * passed into the function is returned. 7497 * 7498 * @see #onCreateDrawableState 7499 */ mergeDrawableStates(int[] baseState, int[] additionalState)7500 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 7501 final int N = baseState.length; 7502 int i = N - 1; 7503 while (i >= 0 && baseState[i] == 0) { 7504 i--; 7505 } 7506 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 7507 return baseState; 7508 } 7509 7510 /** 7511 * Sets the background color for this view. 7512 * @param color the color of the background 7513 */ 7514 @RemotableViewMethod setBackgroundColor(int color)7515 public void setBackgroundColor(int color) { 7516 setBackgroundDrawable(new ColorDrawable(color)); 7517 } 7518 7519 /** 7520 * Set the background to a given resource. The resource should refer to 7521 * a Drawable object or 0 to remove the background. 7522 * @param resid The identifier of the resource. 7523 * @attr ref android.R.styleable#View_background 7524 */ 7525 @RemotableViewMethod setBackgroundResource(int resid)7526 public void setBackgroundResource(int resid) { 7527 if (resid != 0 && resid == mBackgroundResource) { 7528 return; 7529 } 7530 7531 Drawable d= null; 7532 if (resid != 0) { 7533 d = mResources.getDrawable(resid); 7534 } 7535 setBackgroundDrawable(d); 7536 7537 mBackgroundResource = resid; 7538 } 7539 7540 /** 7541 * Set the background to a given Drawable, or remove the background. If the 7542 * background has padding, this View's padding is set to the background's 7543 * padding. However, when a background is removed, this View's padding isn't 7544 * touched. If setting the padding is desired, please use 7545 * {@link #setPadding(int, int, int, int)}. 7546 * 7547 * @param d The Drawable to use as the background, or null to remove the 7548 * background 7549 */ setBackgroundDrawable(Drawable d)7550 public void setBackgroundDrawable(Drawable d) { 7551 boolean requestLayout = false; 7552 7553 mBackgroundResource = 0; 7554 7555 /* 7556 * Regardless of whether we're setting a new background or not, we want 7557 * to clear the previous drawable. 7558 */ 7559 if (mBGDrawable != null) { 7560 mBGDrawable.setCallback(null); 7561 unscheduleDrawable(mBGDrawable); 7562 } 7563 7564 if (d != null) { 7565 Rect padding = sThreadLocal.get(); 7566 if (padding == null) { 7567 padding = new Rect(); 7568 sThreadLocal.set(padding); 7569 } 7570 if (d.getPadding(padding)) { 7571 setPadding(padding.left, padding.top, padding.right, padding.bottom); 7572 } 7573 7574 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 7575 // if it has a different minimum size, we should layout again 7576 if (mBGDrawable == null || mBGDrawable.getMinimumHeight() != d.getMinimumHeight() || 7577 mBGDrawable.getMinimumWidth() != d.getMinimumWidth()) { 7578 requestLayout = true; 7579 } 7580 7581 d.setCallback(this); 7582 if (d.isStateful()) { 7583 d.setState(getDrawableState()); 7584 } 7585 d.setVisible(getVisibility() == VISIBLE, false); 7586 mBGDrawable = d; 7587 7588 if ((mPrivateFlags & SKIP_DRAW) != 0) { 7589 mPrivateFlags &= ~SKIP_DRAW; 7590 mPrivateFlags |= ONLY_DRAWS_BACKGROUND; 7591 requestLayout = true; 7592 } 7593 } else { 7594 /* Remove the background */ 7595 mBGDrawable = null; 7596 7597 if ((mPrivateFlags & ONLY_DRAWS_BACKGROUND) != 0) { 7598 /* 7599 * This view ONLY drew the background before and we're removing 7600 * the background, so now it won't draw anything 7601 * (hence we SKIP_DRAW) 7602 */ 7603 mPrivateFlags &= ~ONLY_DRAWS_BACKGROUND; 7604 mPrivateFlags |= SKIP_DRAW; 7605 } 7606 7607 /* 7608 * When the background is set, we try to apply its padding to this 7609 * View. When the background is removed, we don't touch this View's 7610 * padding. This is noted in the Javadocs. Hence, we don't need to 7611 * requestLayout(), the invalidate() below is sufficient. 7612 */ 7613 7614 // The old background's minimum size could have affected this 7615 // View's layout, so let's requestLayout 7616 requestLayout = true; 7617 } 7618 7619 computeOpaqueFlags(); 7620 7621 if (requestLayout) { 7622 requestLayout(); 7623 } 7624 7625 mBackgroundSizeChanged = true; 7626 invalidate(); 7627 } 7628 7629 /** 7630 * Gets the background drawable 7631 * @return The drawable used as the background for this view, if any. 7632 */ getBackground()7633 public Drawable getBackground() { 7634 return mBGDrawable; 7635 } 7636 7637 /** 7638 * Sets the padding. The view may add on the space required to display 7639 * the scrollbars, depending on the style and visibility of the scrollbars. 7640 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 7641 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 7642 * from the values set in this call. 7643 * 7644 * @attr ref android.R.styleable#View_padding 7645 * @attr ref android.R.styleable#View_paddingBottom 7646 * @attr ref android.R.styleable#View_paddingLeft 7647 * @attr ref android.R.styleable#View_paddingRight 7648 * @attr ref android.R.styleable#View_paddingTop 7649 * @param left the left padding in pixels 7650 * @param top the top padding in pixels 7651 * @param right the right padding in pixels 7652 * @param bottom the bottom padding in pixels 7653 */ setPadding(int left, int top, int right, int bottom)7654 public void setPadding(int left, int top, int right, int bottom) { 7655 boolean changed = false; 7656 7657 mUserPaddingRight = right; 7658 mUserPaddingBottom = bottom; 7659 7660 final int viewFlags = mViewFlags; 7661 7662 // Common case is there are no scroll bars. 7663 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 7664 // TODO: Deal with RTL languages to adjust left padding instead of right. 7665 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 7666 right += (viewFlags & SCROLLBARS_INSET_MASK) == 0 7667 ? 0 : getVerticalScrollbarWidth(); 7668 } 7669 if ((viewFlags & SCROLLBARS_HORIZONTAL) == 0) { 7670 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 7671 ? 0 : getHorizontalScrollbarHeight(); 7672 } 7673 } 7674 7675 if (mPaddingLeft != left) { 7676 changed = true; 7677 mPaddingLeft = left; 7678 } 7679 if (mPaddingTop != top) { 7680 changed = true; 7681 mPaddingTop = top; 7682 } 7683 if (mPaddingRight != right) { 7684 changed = true; 7685 mPaddingRight = right; 7686 } 7687 if (mPaddingBottom != bottom) { 7688 changed = true; 7689 mPaddingBottom = bottom; 7690 } 7691 7692 if (changed) { 7693 requestLayout(); 7694 } 7695 } 7696 7697 /** 7698 * Returns the top padding of this view. 7699 * 7700 * @return the top padding in pixels 7701 */ getPaddingTop()7702 public int getPaddingTop() { 7703 return mPaddingTop; 7704 } 7705 7706 /** 7707 * Returns the bottom padding of this view. If there are inset and enabled 7708 * scrollbars, this value may include the space required to display the 7709 * scrollbars as well. 7710 * 7711 * @return the bottom padding in pixels 7712 */ getPaddingBottom()7713 public int getPaddingBottom() { 7714 return mPaddingBottom; 7715 } 7716 7717 /** 7718 * Returns the left padding of this view. If there are inset and enabled 7719 * scrollbars, this value may include the space required to display the 7720 * scrollbars as well. 7721 * 7722 * @return the left padding in pixels 7723 */ getPaddingLeft()7724 public int getPaddingLeft() { 7725 return mPaddingLeft; 7726 } 7727 7728 /** 7729 * Returns the right padding of this view. If there are inset and enabled 7730 * scrollbars, this value may include the space required to display the 7731 * scrollbars as well. 7732 * 7733 * @return the right padding in pixels 7734 */ getPaddingRight()7735 public int getPaddingRight() { 7736 return mPaddingRight; 7737 } 7738 7739 /** 7740 * Changes the selection state of this view. A view can be selected or not. 7741 * Note that selection is not the same as focus. Views are typically 7742 * selected in the context of an AdapterView like ListView or GridView; 7743 * the selected view is the view that is highlighted. 7744 * 7745 * @param selected true if the view must be selected, false otherwise 7746 */ setSelected(boolean selected)7747 public void setSelected(boolean selected) { 7748 if (((mPrivateFlags & SELECTED) != 0) != selected) { 7749 mPrivateFlags = (mPrivateFlags & ~SELECTED) | (selected ? SELECTED : 0); 7750 if (!selected) resetPressedState(); 7751 invalidate(); 7752 refreshDrawableState(); 7753 dispatchSetSelected(selected); 7754 } 7755 } 7756 7757 /** 7758 * Dispatch setSelected to all of this View's children. 7759 * 7760 * @see #setSelected(boolean) 7761 * 7762 * @param selected The new selected state 7763 */ dispatchSetSelected(boolean selected)7764 protected void dispatchSetSelected(boolean selected) { 7765 } 7766 7767 /** 7768 * Indicates the selection state of this view. 7769 * 7770 * @return true if the view is selected, false otherwise 7771 */ 7772 @ViewDebug.ExportedProperty isSelected()7773 public boolean isSelected() { 7774 return (mPrivateFlags & SELECTED) != 0; 7775 } 7776 7777 /** 7778 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 7779 * observer can be used to get notifications when global events, like 7780 * layout, happen. 7781 * 7782 * The returned ViewTreeObserver observer is not guaranteed to remain 7783 * valid for the lifetime of this View. If the caller of this method keeps 7784 * a long-lived reference to ViewTreeObserver, it should always check for 7785 * the return value of {@link ViewTreeObserver#isAlive()}. 7786 * 7787 * @return The ViewTreeObserver for this view's hierarchy. 7788 */ getViewTreeObserver()7789 public ViewTreeObserver getViewTreeObserver() { 7790 if (mAttachInfo != null) { 7791 return mAttachInfo.mTreeObserver; 7792 } 7793 if (mFloatingTreeObserver == null) { 7794 mFloatingTreeObserver = new ViewTreeObserver(); 7795 } 7796 return mFloatingTreeObserver; 7797 } 7798 7799 /** 7800 * <p>Finds the topmost view in the current view hierarchy.</p> 7801 * 7802 * @return the topmost view containing this view 7803 */ getRootView()7804 public View getRootView() { 7805 if (mAttachInfo != null) { 7806 final View v = mAttachInfo.mRootView; 7807 if (v != null) { 7808 return v; 7809 } 7810 } 7811 7812 View parent = this; 7813 7814 while (parent.mParent != null && parent.mParent instanceof View) { 7815 parent = (View) parent.mParent; 7816 } 7817 7818 return parent; 7819 } 7820 7821 /** 7822 * <p>Computes the coordinates of this view on the screen. The argument 7823 * must be an array of two integers. After the method returns, the array 7824 * contains the x and y location in that order.</p> 7825 * 7826 * @param location an array of two integers in which to hold the coordinates 7827 */ getLocationOnScreen(int[] location)7828 public void getLocationOnScreen(int[] location) { 7829 getLocationInWindow(location); 7830 7831 final AttachInfo info = mAttachInfo; 7832 if (info != null) { 7833 location[0] += info.mWindowLeft; 7834 location[1] += info.mWindowTop; 7835 } 7836 } 7837 7838 /** 7839 * <p>Computes the coordinates of this view in its window. The argument 7840 * must be an array of two integers. After the method returns, the array 7841 * contains the x and y location in that order.</p> 7842 * 7843 * @param location an array of two integers in which to hold the coordinates 7844 */ getLocationInWindow(int[] location)7845 public void getLocationInWindow(int[] location) { 7846 if (location == null || location.length < 2) { 7847 throw new IllegalArgumentException("location must be an array of " 7848 + "two integers"); 7849 } 7850 7851 location[0] = mLeft; 7852 location[1] = mTop; 7853 7854 ViewParent viewParent = mParent; 7855 while (viewParent instanceof View) { 7856 final View view = (View)viewParent; 7857 location[0] += view.mLeft - view.mScrollX; 7858 location[1] += view.mTop - view.mScrollY; 7859 viewParent = view.mParent; 7860 } 7861 7862 if (viewParent instanceof ViewRoot) { 7863 // *cough* 7864 final ViewRoot vr = (ViewRoot)viewParent; 7865 location[1] -= vr.mCurScrollY; 7866 } 7867 } 7868 7869 /** 7870 * {@hide} 7871 * @param id the id of the view to be found 7872 * @return the view of the specified id, null if cannot be found 7873 */ findViewTraversal(int id)7874 protected View findViewTraversal(int id) { 7875 if (id == mID) { 7876 return this; 7877 } 7878 return null; 7879 } 7880 7881 /** 7882 * {@hide} 7883 * @param tag the tag of the view to be found 7884 * @return the view of specified tag, null if cannot be found 7885 */ findViewWithTagTraversal(Object tag)7886 protected View findViewWithTagTraversal(Object tag) { 7887 if (tag != null && tag.equals(mTag)) { 7888 return this; 7889 } 7890 return null; 7891 } 7892 7893 /** 7894 * Look for a child view with the given id. If this view has the given 7895 * id, return this view. 7896 * 7897 * @param id The id to search for. 7898 * @return The view that has the given id in the hierarchy or null 7899 */ findViewById(int id)7900 public final View findViewById(int id) { 7901 if (id < 0) { 7902 return null; 7903 } 7904 return findViewTraversal(id); 7905 } 7906 7907 /** 7908 * Look for a child view with the given tag. If this view has the given 7909 * tag, return this view. 7910 * 7911 * @param tag The tag to search for, using "tag.equals(getTag())". 7912 * @return The View that has the given tag in the hierarchy or null 7913 */ findViewWithTag(Object tag)7914 public final View findViewWithTag(Object tag) { 7915 if (tag == null) { 7916 return null; 7917 } 7918 return findViewWithTagTraversal(tag); 7919 } 7920 7921 /** 7922 * Sets the identifier for this view. The identifier does not have to be 7923 * unique in this view's hierarchy. The identifier should be a positive 7924 * number. 7925 * 7926 * @see #NO_ID 7927 * @see #getId 7928 * @see #findViewById 7929 * 7930 * @param id a number used to identify the view 7931 * 7932 * @attr ref android.R.styleable#View_id 7933 */ setId(int id)7934 public void setId(int id) { 7935 mID = id; 7936 } 7937 7938 /** 7939 * {@hide} 7940 * 7941 * @param isRoot true if the view belongs to the root namespace, false 7942 * otherwise 7943 */ setIsRootNamespace(boolean isRoot)7944 public void setIsRootNamespace(boolean isRoot) { 7945 if (isRoot) { 7946 mPrivateFlags |= IS_ROOT_NAMESPACE; 7947 } else { 7948 mPrivateFlags &= ~IS_ROOT_NAMESPACE; 7949 } 7950 } 7951 7952 /** 7953 * {@hide} 7954 * 7955 * @return true if the view belongs to the root namespace, false otherwise 7956 */ isRootNamespace()7957 public boolean isRootNamespace() { 7958 return (mPrivateFlags&IS_ROOT_NAMESPACE) != 0; 7959 } 7960 7961 /** 7962 * Returns this view's identifier. 7963 * 7964 * @return a positive integer used to identify the view or {@link #NO_ID} 7965 * if the view has no ID 7966 * 7967 * @see #setId 7968 * @see #findViewById 7969 * @attr ref android.R.styleable#View_id 7970 */ 7971 @ViewDebug.CapturedViewProperty getId()7972 public int getId() { 7973 return mID; 7974 } 7975 7976 /** 7977 * Returns this view's tag. 7978 * 7979 * @return the Object stored in this view as a tag 7980 * 7981 * @see #setTag(Object) 7982 * @see #getTag(int) 7983 */ 7984 @ViewDebug.ExportedProperty getTag()7985 public Object getTag() { 7986 return mTag; 7987 } 7988 7989 /** 7990 * Sets the tag associated with this view. A tag can be used to mark 7991 * a view in its hierarchy and does not have to be unique within the 7992 * hierarchy. Tags can also be used to store data within a view without 7993 * resorting to another data structure. 7994 * 7995 * @param tag an Object to tag the view with 7996 * 7997 * @see #getTag() 7998 * @see #setTag(int, Object) 7999 */ setTag(final Object tag)8000 public void setTag(final Object tag) { 8001 mTag = tag; 8002 } 8003 8004 /** 8005 * Returns the tag associated with this view and the specified key. 8006 * 8007 * @param key The key identifying the tag 8008 * 8009 * @return the Object stored in this view as a tag 8010 * 8011 * @see #setTag(int, Object) 8012 * @see #getTag() 8013 */ getTag(int key)8014 public Object getTag(int key) { 8015 SparseArray<Object> tags = null; 8016 synchronized (sTagsLock) { 8017 if (sTags != null) { 8018 tags = sTags.get(this); 8019 } 8020 } 8021 8022 if (tags != null) return tags.get(key); 8023 return null; 8024 } 8025 8026 /** 8027 * Sets a tag associated with this view and a key. A tag can be used 8028 * to mark a view in its hierarchy and does not have to be unique within 8029 * the hierarchy. Tags can also be used to store data within a view 8030 * without resorting to another data structure. 8031 * 8032 * The specified key should be an id declared in the resources of the 8033 * application to ensure it is unique (see the <a 8034 * href={@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 8035 * Keys identified as belonging to 8036 * the Android framework or not associated with any package will cause 8037 * an {@link IllegalArgumentException} to be thrown. 8038 * 8039 * @param key The key identifying the tag 8040 * @param tag An Object to tag the view with 8041 * 8042 * @throws IllegalArgumentException If they specified key is not valid 8043 * 8044 * @see #setTag(Object) 8045 * @see #getTag(int) 8046 */ setTag(int key, final Object tag)8047 public void setTag(int key, final Object tag) { 8048 // If the package id is 0x00 or 0x01, it's either an undefined package 8049 // or a framework id 8050 if ((key >>> 24) < 2) { 8051 throw new IllegalArgumentException("The key must be an application-specific " 8052 + "resource id."); 8053 } 8054 8055 setTagInternal(this, key, tag); 8056 } 8057 8058 /** 8059 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 8060 * framework id. 8061 * 8062 * @hide 8063 */ setTagInternal(int key, Object tag)8064 public void setTagInternal(int key, Object tag) { 8065 if ((key >>> 24) != 0x1) { 8066 throw new IllegalArgumentException("The key must be a framework-specific " 8067 + "resource id."); 8068 } 8069 8070 setTagInternal(this, key, tag); 8071 } 8072 setTagInternal(View view, int key, Object tag)8073 private static void setTagInternal(View view, int key, Object tag) { 8074 SparseArray<Object> tags = null; 8075 synchronized (sTagsLock) { 8076 if (sTags == null) { 8077 sTags = new WeakHashMap<View, SparseArray<Object>>(); 8078 } else { 8079 tags = sTags.get(view); 8080 } 8081 } 8082 8083 if (tags == null) { 8084 tags = new SparseArray<Object>(2); 8085 synchronized (sTagsLock) { 8086 sTags.put(view, tags); 8087 } 8088 } 8089 8090 tags.put(key, tag); 8091 } 8092 8093 /** 8094 * @param consistency The type of consistency. See ViewDebug for more information. 8095 * 8096 * @hide 8097 */ dispatchConsistencyCheck(int consistency)8098 protected boolean dispatchConsistencyCheck(int consistency) { 8099 return onConsistencyCheck(consistency); 8100 } 8101 8102 /** 8103 * Method that subclasses should implement to check their consistency. The type of 8104 * consistency check is indicated by the bit field passed as a parameter. 8105 * 8106 * @param consistency The type of consistency. See ViewDebug for more information. 8107 * 8108 * @throws IllegalStateException if the view is in an inconsistent state. 8109 * 8110 * @hide 8111 */ onConsistencyCheck(int consistency)8112 protected boolean onConsistencyCheck(int consistency) { 8113 boolean result = true; 8114 8115 final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0; 8116 final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0; 8117 8118 if (checkLayout) { 8119 if (getParent() == null) { 8120 result = false; 8121 android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, 8122 "View " + this + " does not have a parent."); 8123 } 8124 8125 if (mAttachInfo == null) { 8126 result = false; 8127 android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, 8128 "View " + this + " is not attached to a window."); 8129 } 8130 } 8131 8132 if (checkDrawing) { 8133 // Do not check the DIRTY/DRAWN flags because views can call invalidate() 8134 // from their draw() method 8135 8136 if ((mPrivateFlags & DRAWN) != DRAWN && 8137 (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) { 8138 result = false; 8139 android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, 8140 "View " + this + " was invalidated but its drawing cache is valid."); 8141 } 8142 } 8143 8144 return result; 8145 } 8146 8147 /** 8148 * Prints information about this view in the log output, with the tag 8149 * {@link #VIEW_LOG_TAG}. 8150 * 8151 * @hide 8152 */ debug()8153 public void debug() { 8154 debug(0); 8155 } 8156 8157 /** 8158 * Prints information about this view in the log output, with the tag 8159 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 8160 * indentation defined by the <code>depth</code>. 8161 * 8162 * @param depth the indentation level 8163 * 8164 * @hide 8165 */ debug(int depth)8166 protected void debug(int depth) { 8167 String output = debugIndent(depth - 1); 8168 8169 output += "+ " + this; 8170 int id = getId(); 8171 if (id != -1) { 8172 output += " (id=" + id + ")"; 8173 } 8174 Object tag = getTag(); 8175 if (tag != null) { 8176 output += " (tag=" + tag + ")"; 8177 } 8178 Log.d(VIEW_LOG_TAG, output); 8179 8180 if ((mPrivateFlags & FOCUSED) != 0) { 8181 output = debugIndent(depth) + " FOCUSED"; 8182 Log.d(VIEW_LOG_TAG, output); 8183 } 8184 8185 output = debugIndent(depth); 8186 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 8187 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 8188 + "} "; 8189 Log.d(VIEW_LOG_TAG, output); 8190 8191 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 8192 || mPaddingBottom != 0) { 8193 output = debugIndent(depth); 8194 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 8195 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 8196 Log.d(VIEW_LOG_TAG, output); 8197 } 8198 8199 output = debugIndent(depth); 8200 output += "mMeasureWidth=" + mMeasuredWidth + 8201 " mMeasureHeight=" + mMeasuredHeight; 8202 Log.d(VIEW_LOG_TAG, output); 8203 8204 output = debugIndent(depth); 8205 if (mLayoutParams == null) { 8206 output += "BAD! no layout params"; 8207 } else { 8208 output = mLayoutParams.debug(output); 8209 } 8210 Log.d(VIEW_LOG_TAG, output); 8211 8212 output = debugIndent(depth); 8213 output += "flags={"; 8214 output += View.printFlags(mViewFlags); 8215 output += "}"; 8216 Log.d(VIEW_LOG_TAG, output); 8217 8218 output = debugIndent(depth); 8219 output += "privateFlags={"; 8220 output += View.printPrivateFlags(mPrivateFlags); 8221 output += "}"; 8222 Log.d(VIEW_LOG_TAG, output); 8223 } 8224 8225 /** 8226 * Creates an string of whitespaces used for indentation. 8227 * 8228 * @param depth the indentation level 8229 * @return a String containing (depth * 2 + 3) * 2 white spaces 8230 * 8231 * @hide 8232 */ debugIndent(int depth)8233 protected static String debugIndent(int depth) { 8234 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 8235 for (int i = 0; i < (depth * 2) + 3; i++) { 8236 spaces.append(' ').append(' '); 8237 } 8238 return spaces.toString(); 8239 } 8240 8241 /** 8242 * <p>Return the offset of the widget's text baseline from the widget's top 8243 * boundary. If this widget does not support baseline alignment, this 8244 * method returns -1. </p> 8245 * 8246 * @return the offset of the baseline within the widget's bounds or -1 8247 * if baseline alignment is not supported 8248 */ 8249 @ViewDebug.ExportedProperty(category = "layout") getBaseline()8250 public int getBaseline() { 8251 return -1; 8252 } 8253 8254 /** 8255 * Call this when something has changed which has invalidated the 8256 * layout of this view. This will schedule a layout pass of the view 8257 * tree. 8258 */ requestLayout()8259 public void requestLayout() { 8260 if (ViewDebug.TRACE_HIERARCHY) { 8261 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT); 8262 } 8263 8264 mPrivateFlags |= FORCE_LAYOUT; 8265 8266 if (mParent != null && !mParent.isLayoutRequested()) { 8267 mParent.requestLayout(); 8268 } 8269 } 8270 8271 /** 8272 * Forces this view to be laid out during the next layout pass. 8273 * This method does not call requestLayout() or forceLayout() 8274 * on the parent. 8275 */ forceLayout()8276 public void forceLayout() { 8277 mPrivateFlags |= FORCE_LAYOUT; 8278 } 8279 8280 /** 8281 * <p> 8282 * This is called to find out how big a view should be. The parent 8283 * supplies constraint information in the width and height parameters. 8284 * </p> 8285 * 8286 * <p> 8287 * The actual mesurement work of a view is performed in 8288 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 8289 * {@link #onMeasure(int, int)} can and must be overriden by subclasses. 8290 * </p> 8291 * 8292 * 8293 * @param widthMeasureSpec Horizontal space requirements as imposed by the 8294 * parent 8295 * @param heightMeasureSpec Vertical space requirements as imposed by the 8296 * parent 8297 * 8298 * @see #onMeasure(int, int) 8299 */ measure(int widthMeasureSpec, int heightMeasureSpec)8300 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 8301 if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT || 8302 widthMeasureSpec != mOldWidthMeasureSpec || 8303 heightMeasureSpec != mOldHeightMeasureSpec) { 8304 8305 // first clears the measured dimension flag 8306 mPrivateFlags &= ~MEASURED_DIMENSION_SET; 8307 8308 if (ViewDebug.TRACE_HIERARCHY) { 8309 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE); 8310 } 8311 8312 // measure ourselves, this should set the measured dimension flag back 8313 onMeasure(widthMeasureSpec, heightMeasureSpec); 8314 8315 // flag not set, setMeasuredDimension() was not invoked, we raise 8316 // an exception to warn the developer 8317 if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) { 8318 throw new IllegalStateException("onMeasure() did not set the" 8319 + " measured dimension by calling" 8320 + " setMeasuredDimension()"); 8321 } 8322 8323 mPrivateFlags |= LAYOUT_REQUIRED; 8324 } 8325 8326 mOldWidthMeasureSpec = widthMeasureSpec; 8327 mOldHeightMeasureSpec = heightMeasureSpec; 8328 } 8329 8330 /** 8331 * <p> 8332 * Measure the view and its content to determine the measured width and the 8333 * measured height. This method is invoked by {@link #measure(int, int)} and 8334 * should be overriden by subclasses to provide accurate and efficient 8335 * measurement of their contents. 8336 * </p> 8337 * 8338 * <p> 8339 * <strong>CONTRACT:</strong> When overriding this method, you 8340 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 8341 * measured width and height of this view. Failure to do so will trigger an 8342 * <code>IllegalStateException</code>, thrown by 8343 * {@link #measure(int, int)}. Calling the superclass' 8344 * {@link #onMeasure(int, int)} is a valid use. 8345 * </p> 8346 * 8347 * <p> 8348 * The base class implementation of measure defaults to the background size, 8349 * unless a larger size is allowed by the MeasureSpec. Subclasses should 8350 * override {@link #onMeasure(int, int)} to provide better measurements of 8351 * their content. 8352 * </p> 8353 * 8354 * <p> 8355 * If this method is overridden, it is the subclass's responsibility to make 8356 * sure the measured height and width are at least the view's minimum height 8357 * and width ({@link #getSuggestedMinimumHeight()} and 8358 * {@link #getSuggestedMinimumWidth()}). 8359 * </p> 8360 * 8361 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 8362 * The requirements are encoded with 8363 * {@link android.view.View.MeasureSpec}. 8364 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 8365 * The requirements are encoded with 8366 * {@link android.view.View.MeasureSpec}. 8367 * 8368 * @see #getMeasuredWidth() 8369 * @see #getMeasuredHeight() 8370 * @see #setMeasuredDimension(int, int) 8371 * @see #getSuggestedMinimumHeight() 8372 * @see #getSuggestedMinimumWidth() 8373 * @see android.view.View.MeasureSpec#getMode(int) 8374 * @see android.view.View.MeasureSpec#getSize(int) 8375 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)8376 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 8377 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 8378 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 8379 } 8380 8381 /** 8382 * <p>This mehod must be called by {@link #onMeasure(int, int)} to store the 8383 * measured width and measured height. Failing to do so will trigger an 8384 * exception at measurement time.</p> 8385 * 8386 * @param measuredWidth the measured width of this view 8387 * @param measuredHeight the measured height of this view 8388 */ setMeasuredDimension(int measuredWidth, int measuredHeight)8389 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 8390 mMeasuredWidth = measuredWidth; 8391 mMeasuredHeight = measuredHeight; 8392 8393 mPrivateFlags |= MEASURED_DIMENSION_SET; 8394 } 8395 8396 /** 8397 * Utility to reconcile a desired size with constraints imposed by a MeasureSpec. 8398 * Will take the desired size, unless a different size is imposed by the constraints. 8399 * 8400 * @param size How big the view wants to be 8401 * @param measureSpec Constraints imposed by the parent 8402 * @return The size this view should be. 8403 */ resolveSize(int size, int measureSpec)8404 public static int resolveSize(int size, int measureSpec) { 8405 int result = size; 8406 int specMode = MeasureSpec.getMode(measureSpec); 8407 int specSize = MeasureSpec.getSize(measureSpec); 8408 switch (specMode) { 8409 case MeasureSpec.UNSPECIFIED: 8410 result = size; 8411 break; 8412 case MeasureSpec.AT_MOST: 8413 result = Math.min(size, specSize); 8414 break; 8415 case MeasureSpec.EXACTLY: 8416 result = specSize; 8417 break; 8418 } 8419 return result; 8420 } 8421 8422 /** 8423 * Utility to return a default size. Uses the supplied size if the 8424 * MeasureSpec imposed no contraints. Will get larger if allowed 8425 * by the MeasureSpec. 8426 * 8427 * @param size Default size for this view 8428 * @param measureSpec Constraints imposed by the parent 8429 * @return The size this view should be. 8430 */ getDefaultSize(int size, int measureSpec)8431 public static int getDefaultSize(int size, int measureSpec) { 8432 int result = size; 8433 int specMode = MeasureSpec.getMode(measureSpec); 8434 int specSize = MeasureSpec.getSize(measureSpec); 8435 8436 switch (specMode) { 8437 case MeasureSpec.UNSPECIFIED: 8438 result = size; 8439 break; 8440 case MeasureSpec.AT_MOST: 8441 case MeasureSpec.EXACTLY: 8442 result = specSize; 8443 break; 8444 } 8445 return result; 8446 } 8447 8448 /** 8449 * Returns the suggested minimum height that the view should use. This 8450 * returns the maximum of the view's minimum height 8451 * and the background's minimum height 8452 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 8453 * <p> 8454 * When being used in {@link #onMeasure(int, int)}, the caller should still 8455 * ensure the returned height is within the requirements of the parent. 8456 * 8457 * @return The suggested minimum height of the view. 8458 */ getSuggestedMinimumHeight()8459 protected int getSuggestedMinimumHeight() { 8460 int suggestedMinHeight = mMinHeight; 8461 8462 if (mBGDrawable != null) { 8463 final int bgMinHeight = mBGDrawable.getMinimumHeight(); 8464 if (suggestedMinHeight < bgMinHeight) { 8465 suggestedMinHeight = bgMinHeight; 8466 } 8467 } 8468 8469 return suggestedMinHeight; 8470 } 8471 8472 /** 8473 * Returns the suggested minimum width that the view should use. This 8474 * returns the maximum of the view's minimum width) 8475 * and the background's minimum width 8476 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 8477 * <p> 8478 * When being used in {@link #onMeasure(int, int)}, the caller should still 8479 * ensure the returned width is within the requirements of the parent. 8480 * 8481 * @return The suggested minimum width of the view. 8482 */ getSuggestedMinimumWidth()8483 protected int getSuggestedMinimumWidth() { 8484 int suggestedMinWidth = mMinWidth; 8485 8486 if (mBGDrawable != null) { 8487 final int bgMinWidth = mBGDrawable.getMinimumWidth(); 8488 if (suggestedMinWidth < bgMinWidth) { 8489 suggestedMinWidth = bgMinWidth; 8490 } 8491 } 8492 8493 return suggestedMinWidth; 8494 } 8495 8496 /** 8497 * Sets the minimum height of the view. It is not guaranteed the view will 8498 * be able to achieve this minimum height (for example, if its parent layout 8499 * constrains it with less available height). 8500 * 8501 * @param minHeight The minimum height the view will try to be. 8502 */ setMinimumHeight(int minHeight)8503 public void setMinimumHeight(int minHeight) { 8504 mMinHeight = minHeight; 8505 } 8506 8507 /** 8508 * Sets the minimum width of the view. It is not guaranteed the view will 8509 * be able to achieve this minimum width (for example, if its parent layout 8510 * constrains it with less available width). 8511 * 8512 * @param minWidth The minimum width the view will try to be. 8513 */ setMinimumWidth(int minWidth)8514 public void setMinimumWidth(int minWidth) { 8515 mMinWidth = minWidth; 8516 } 8517 8518 /** 8519 * Get the animation currently associated with this view. 8520 * 8521 * @return The animation that is currently playing or 8522 * scheduled to play for this view. 8523 */ getAnimation()8524 public Animation getAnimation() { 8525 return mCurrentAnimation; 8526 } 8527 8528 /** 8529 * Start the specified animation now. 8530 * 8531 * @param animation the animation to start now 8532 */ startAnimation(Animation animation)8533 public void startAnimation(Animation animation) { 8534 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 8535 setAnimation(animation); 8536 invalidate(); 8537 } 8538 8539 /** 8540 * Cancels any animations for this view. 8541 */ clearAnimation()8542 public void clearAnimation() { 8543 if (mCurrentAnimation != null) { 8544 mCurrentAnimation.detach(); 8545 } 8546 mCurrentAnimation = null; 8547 } 8548 8549 /** 8550 * Sets the next animation to play for this view. 8551 * If you want the animation to play immediately, use 8552 * startAnimation. This method provides allows fine-grained 8553 * control over the start time and invalidation, but you 8554 * must make sure that 1) the animation has a start time set, and 8555 * 2) the view will be invalidated when the animation is supposed to 8556 * start. 8557 * 8558 * @param animation The next animation, or null. 8559 */ setAnimation(Animation animation)8560 public void setAnimation(Animation animation) { 8561 mCurrentAnimation = animation; 8562 if (animation != null) { 8563 animation.reset(); 8564 } 8565 } 8566 8567 /** 8568 * Invoked by a parent ViewGroup to notify the start of the animation 8569 * currently associated with this view. If you override this method, 8570 * always call super.onAnimationStart(); 8571 * 8572 * @see #setAnimation(android.view.animation.Animation) 8573 * @see #getAnimation() 8574 */ onAnimationStart()8575 protected void onAnimationStart() { 8576 mPrivateFlags |= ANIMATION_STARTED; 8577 } 8578 8579 /** 8580 * Invoked by a parent ViewGroup to notify the end of the animation 8581 * currently associated with this view. If you override this method, 8582 * always call super.onAnimationEnd(); 8583 * 8584 * @see #setAnimation(android.view.animation.Animation) 8585 * @see #getAnimation() 8586 */ onAnimationEnd()8587 protected void onAnimationEnd() { 8588 mPrivateFlags &= ~ANIMATION_STARTED; 8589 } 8590 8591 /** 8592 * Invoked if there is a Transform that involves alpha. Subclass that can 8593 * draw themselves with the specified alpha should return true, and then 8594 * respect that alpha when their onDraw() is called. If this returns false 8595 * then the view may be redirected to draw into an offscreen buffer to 8596 * fulfill the request, which will look fine, but may be slower than if the 8597 * subclass handles it internally. The default implementation returns false. 8598 * 8599 * @param alpha The alpha (0..255) to apply to the view's drawing 8600 * @return true if the view can draw with the specified alpha. 8601 */ onSetAlpha(int alpha)8602 protected boolean onSetAlpha(int alpha) { 8603 return false; 8604 } 8605 8606 /** 8607 * This is used by the RootView to perform an optimization when 8608 * the view hierarchy contains one or several SurfaceView. 8609 * SurfaceView is always considered transparent, but its children are not, 8610 * therefore all View objects remove themselves from the global transparent 8611 * region (passed as a parameter to this function). 8612 * 8613 * @param region The transparent region for this ViewRoot (window). 8614 * 8615 * @return Returns true if the effective visibility of the view at this 8616 * point is opaque, regardless of the transparent region; returns false 8617 * if it is possible for underlying windows to be seen behind the view. 8618 * 8619 * {@hide} 8620 */ gatherTransparentRegion(Region region)8621 public boolean gatherTransparentRegion(Region region) { 8622 final AttachInfo attachInfo = mAttachInfo; 8623 if (region != null && attachInfo != null) { 8624 final int pflags = mPrivateFlags; 8625 if ((pflags & SKIP_DRAW) == 0) { 8626 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 8627 // remove it from the transparent region. 8628 final int[] location = attachInfo.mTransparentLocation; 8629 getLocationInWindow(location); 8630 region.op(location[0], location[1], location[0] + mRight - mLeft, 8631 location[1] + mBottom - mTop, Region.Op.DIFFERENCE); 8632 } else if ((pflags & ONLY_DRAWS_BACKGROUND) != 0 && mBGDrawable != null) { 8633 // The ONLY_DRAWS_BACKGROUND flag IS set and the background drawable 8634 // exists, so we remove the background drawable's non-transparent 8635 // parts from this transparent region. 8636 applyDrawableToTransparentRegion(mBGDrawable, region); 8637 } 8638 } 8639 return true; 8640 } 8641 8642 /** 8643 * Play a sound effect for this view. 8644 * 8645 * <p>The framework will play sound effects for some built in actions, such as 8646 * clicking, but you may wish to play these effects in your widget, 8647 * for instance, for internal navigation. 8648 * 8649 * <p>The sound effect will only be played if sound effects are enabled by the user, and 8650 * {@link #isSoundEffectsEnabled()} is true. 8651 * 8652 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 8653 */ playSoundEffect(int soundConstant)8654 public void playSoundEffect(int soundConstant) { 8655 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 8656 return; 8657 } 8658 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 8659 } 8660 8661 /** 8662 * BZZZTT!!1! 8663 * 8664 * <p>Provide haptic feedback to the user for this view. 8665 * 8666 * <p>The framework will provide haptic feedback for some built in actions, 8667 * such as long presses, but you may wish to provide feedback for your 8668 * own widget. 8669 * 8670 * <p>The feedback will only be performed if 8671 * {@link #isHapticFeedbackEnabled()} is true. 8672 * 8673 * @param feedbackConstant One of the constants defined in 8674 * {@link HapticFeedbackConstants} 8675 */ performHapticFeedback(int feedbackConstant)8676 public boolean performHapticFeedback(int feedbackConstant) { 8677 return performHapticFeedback(feedbackConstant, 0); 8678 } 8679 8680 /** 8681 * BZZZTT!!1! 8682 * 8683 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 8684 * 8685 * @param feedbackConstant One of the constants defined in 8686 * {@link HapticFeedbackConstants} 8687 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 8688 */ performHapticFeedback(int feedbackConstant, int flags)8689 public boolean performHapticFeedback(int feedbackConstant, int flags) { 8690 if (mAttachInfo == null) { 8691 return false; 8692 } 8693 if ((flags&HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 8694 && !isHapticFeedbackEnabled()) { 8695 return false; 8696 } 8697 return mAttachInfo.mRootCallbacks.performHapticFeedback( 8698 feedbackConstant, 8699 (flags&HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 8700 } 8701 8702 /** 8703 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 8704 * it is ever exposed at all. 8705 * @hide 8706 */ onCloseSystemDialogs(String reason)8707 public void onCloseSystemDialogs(String reason) { 8708 } 8709 8710 /** 8711 * Given a Drawable whose bounds have been set to draw into this view, 8712 * update a Region being computed for {@link #gatherTransparentRegion} so 8713 * that any non-transparent parts of the Drawable are removed from the 8714 * given transparent region. 8715 * 8716 * @param dr The Drawable whose transparency is to be applied to the region. 8717 * @param region A Region holding the current transparency information, 8718 * where any parts of the region that are set are considered to be 8719 * transparent. On return, this region will be modified to have the 8720 * transparency information reduced by the corresponding parts of the 8721 * Drawable that are not transparent. 8722 * {@hide} 8723 */ applyDrawableToTransparentRegion(Drawable dr, Region region)8724 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 8725 if (DBG) { 8726 Log.i("View", "Getting transparent region for: " + this); 8727 } 8728 final Region r = dr.getTransparentRegion(); 8729 final Rect db = dr.getBounds(); 8730 final AttachInfo attachInfo = mAttachInfo; 8731 if (r != null && attachInfo != null) { 8732 final int w = getRight()-getLeft(); 8733 final int h = getBottom()-getTop(); 8734 if (db.left > 0) { 8735 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 8736 r.op(0, 0, db.left, h, Region.Op.UNION); 8737 } 8738 if (db.right < w) { 8739 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 8740 r.op(db.right, 0, w, h, Region.Op.UNION); 8741 } 8742 if (db.top > 0) { 8743 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 8744 r.op(0, 0, w, db.top, Region.Op.UNION); 8745 } 8746 if (db.bottom < h) { 8747 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 8748 r.op(0, db.bottom, w, h, Region.Op.UNION); 8749 } 8750 final int[] location = attachInfo.mTransparentLocation; 8751 getLocationInWindow(location); 8752 r.translate(location[0], location[1]); 8753 region.op(r, Region.Op.INTERSECT); 8754 } else { 8755 region.op(db, Region.Op.DIFFERENCE); 8756 } 8757 } 8758 postCheckForLongClick(int delayOffset)8759 private void postCheckForLongClick(int delayOffset) { 8760 mHasPerformedLongPress = false; 8761 8762 if (mPendingCheckForLongPress == null) { 8763 mPendingCheckForLongPress = new CheckForLongPress(); 8764 } 8765 mPendingCheckForLongPress.rememberWindowAttachCount(); 8766 postDelayed(mPendingCheckForLongPress, 8767 ViewConfiguration.getLongPressTimeout() - delayOffset); 8768 } 8769 stateSetUnion(final int[] stateSet1, final int[] stateSet2)8770 private static int[] stateSetUnion(final int[] stateSet1, 8771 final int[] stateSet2) { 8772 final int stateSet1Length = stateSet1.length; 8773 final int stateSet2Length = stateSet2.length; 8774 final int[] newSet = new int[stateSet1Length + stateSet2Length]; 8775 int k = 0; 8776 int i = 0; 8777 int j = 0; 8778 // This is a merge of the two input state sets and assumes that the 8779 // input sets are sorted by the order imposed by ViewDrawableStates. 8780 for (int viewState : R.styleable.ViewDrawableStates) { 8781 if (i < stateSet1Length && stateSet1[i] == viewState) { 8782 newSet[k++] = viewState; 8783 i++; 8784 } else if (j < stateSet2Length && stateSet2[j] == viewState) { 8785 newSet[k++] = viewState; 8786 j++; 8787 } 8788 if (k > 1) { 8789 assert(newSet[k - 1] > newSet[k - 2]); 8790 } 8791 } 8792 return newSet; 8793 } 8794 8795 /** 8796 * Inflate a view from an XML resource. This convenience method wraps the {@link 8797 * LayoutInflater} class, which provides a full range of options for view inflation. 8798 * 8799 * @param context The Context object for your activity or application. 8800 * @param resource The resource ID to inflate 8801 * @param root A view group that will be the parent. Used to properly inflate the 8802 * layout_* parameters. 8803 * @see LayoutInflater 8804 */ inflate(Context context, int resource, ViewGroup root)8805 public static View inflate(Context context, int resource, ViewGroup root) { 8806 LayoutInflater factory = LayoutInflater.from(context); 8807 return factory.inflate(resource, root); 8808 } 8809 8810 /** 8811 * Scroll the view with standard behavior for scrolling beyond the normal 8812 * content boundaries. Views that call this method should override 8813 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 8814 * results of an over-scroll operation. 8815 * 8816 * Views can use this method to handle any touch or fling-based scrolling. 8817 * 8818 * @param deltaX Change in X in pixels 8819 * @param deltaY Change in Y in pixels 8820 * @param scrollX Current X scroll value in pixels before applying deltaX 8821 * @param scrollY Current Y scroll value in pixels before applying deltaY 8822 * @param scrollRangeX Maximum content scroll range along the X axis 8823 * @param scrollRangeY Maximum content scroll range along the Y axis 8824 * @param maxOverScrollX Number of pixels to overscroll by in either direction 8825 * along the X axis. 8826 * @param maxOverScrollY Number of pixels to overscroll by in either direction 8827 * along the Y axis. 8828 * @param isTouchEvent true if this scroll operation is the result of a touch event. 8829 * @return true if scrolling was clamped to an over-scroll boundary along either 8830 * axis, false otherwise. 8831 */ overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)8832 protected boolean overScrollBy(int deltaX, int deltaY, 8833 int scrollX, int scrollY, 8834 int scrollRangeX, int scrollRangeY, 8835 int maxOverScrollX, int maxOverScrollY, 8836 boolean isTouchEvent) { 8837 final int overScrollMode = mOverScrollMode; 8838 final boolean canScrollHorizontal = 8839 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 8840 final boolean canScrollVertical = 8841 computeVerticalScrollRange() > computeVerticalScrollExtent(); 8842 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 8843 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 8844 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 8845 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 8846 8847 int newScrollX = scrollX + deltaX; 8848 if (!overScrollHorizontal) { 8849 maxOverScrollX = 0; 8850 } 8851 8852 int newScrollY = scrollY + deltaY; 8853 if (!overScrollVertical) { 8854 maxOverScrollY = 0; 8855 } 8856 8857 // Clamp values if at the limits and record 8858 final int left = -maxOverScrollX; 8859 final int right = maxOverScrollX + scrollRangeX; 8860 final int top = -maxOverScrollY; 8861 final int bottom = maxOverScrollY + scrollRangeY; 8862 8863 boolean clampedX = false; 8864 if (newScrollX > right) { 8865 newScrollX = right; 8866 clampedX = true; 8867 } else if (newScrollX < left) { 8868 newScrollX = left; 8869 clampedX = true; 8870 } 8871 8872 boolean clampedY = false; 8873 if (newScrollY > bottom) { 8874 newScrollY = bottom; 8875 clampedY = true; 8876 } else if (newScrollY < top) { 8877 newScrollY = top; 8878 clampedY = true; 8879 } 8880 8881 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 8882 8883 return clampedX || clampedY; 8884 } 8885 8886 /** 8887 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 8888 * respond to the results of an over-scroll operation. 8889 * 8890 * @param scrollX New X scroll value in pixels 8891 * @param scrollY New Y scroll value in pixels 8892 * @param clampedX True if scrollX was clamped to an over-scroll boundary 8893 * @param clampedY True if scrollY was clamped to an over-scroll boundary 8894 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)8895 protected void onOverScrolled(int scrollX, int scrollY, 8896 boolean clampedX, boolean clampedY) { 8897 // Intentionally empty. 8898 } 8899 8900 /** 8901 * Returns the over-scroll mode for this view. The result will be 8902 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 8903 * (allow over-scrolling only if the view content is larger than the container), 8904 * or {@link #OVER_SCROLL_NEVER}. 8905 * 8906 * @return This view's over-scroll mode. 8907 */ getOverScrollMode()8908 public int getOverScrollMode() { 8909 return mOverScrollMode; 8910 } 8911 8912 /** 8913 * Set the over-scroll mode for this view. Valid over-scroll modes are 8914 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 8915 * (allow over-scrolling only if the view content is larger than the container), 8916 * or {@link #OVER_SCROLL_NEVER}. 8917 * 8918 * Setting the over-scroll mode of a view will have an effect only if the 8919 * view is capable of scrolling. 8920 * 8921 * @param overScrollMode The new over-scroll mode for this view. 8922 */ setOverScrollMode(int overScrollMode)8923 public void setOverScrollMode(int overScrollMode) { 8924 if (overScrollMode != OVER_SCROLL_ALWAYS && 8925 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 8926 overScrollMode != OVER_SCROLL_NEVER) { 8927 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 8928 } 8929 mOverScrollMode = overScrollMode; 8930 } 8931 8932 /** 8933 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 8934 * Each MeasureSpec represents a requirement for either the width or the height. 8935 * A MeasureSpec is comprised of a size and a mode. There are three possible 8936 * modes: 8937 * <dl> 8938 * <dt>UNSPECIFIED</dt> 8939 * <dd> 8940 * The parent has not imposed any constraint on the child. It can be whatever size 8941 * it wants. 8942 * </dd> 8943 * 8944 * <dt>EXACTLY</dt> 8945 * <dd> 8946 * The parent has determined an exact size for the child. The child is going to be 8947 * given those bounds regardless of how big it wants to be. 8948 * </dd> 8949 * 8950 * <dt>AT_MOST</dt> 8951 * <dd> 8952 * The child can be as large as it wants up to the specified size. 8953 * </dd> 8954 * </dl> 8955 * 8956 * MeasureSpecs are implemented as ints to reduce object allocation. This class 8957 * is provided to pack and unpack the <size, mode> tuple into the int. 8958 */ 8959 public static class MeasureSpec { 8960 private static final int MODE_SHIFT = 30; 8961 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 8962 8963 /** 8964 * Measure specification mode: The parent has not imposed any constraint 8965 * on the child. It can be whatever size it wants. 8966 */ 8967 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 8968 8969 /** 8970 * Measure specification mode: The parent has determined an exact size 8971 * for the child. The child is going to be given those bounds regardless 8972 * of how big it wants to be. 8973 */ 8974 public static final int EXACTLY = 1 << MODE_SHIFT; 8975 8976 /** 8977 * Measure specification mode: The child can be as large as it wants up 8978 * to the specified size. 8979 */ 8980 public static final int AT_MOST = 2 << MODE_SHIFT; 8981 8982 /** 8983 * Creates a measure specification based on the supplied size and mode. 8984 * 8985 * The mode must always be one of the following: 8986 * <ul> 8987 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 8988 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 8989 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 8990 * </ul> 8991 * 8992 * @param size the size of the measure specification 8993 * @param mode the mode of the measure specification 8994 * @return the measure specification based on size and mode 8995 */ makeMeasureSpec(int size, int mode)8996 public static int makeMeasureSpec(int size, int mode) { 8997 return size + mode; 8998 } 8999 9000 /** 9001 * Extracts the mode from the supplied measure specification. 9002 * 9003 * @param measureSpec the measure specification to extract the mode from 9004 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 9005 * {@link android.view.View.MeasureSpec#AT_MOST} or 9006 * {@link android.view.View.MeasureSpec#EXACTLY} 9007 */ getMode(int measureSpec)9008 public static int getMode(int measureSpec) { 9009 return (measureSpec & MODE_MASK); 9010 } 9011 9012 /** 9013 * Extracts the size from the supplied measure specification. 9014 * 9015 * @param measureSpec the measure specification to extract the size from 9016 * @return the size in pixels defined in the supplied measure specification 9017 */ getSize(int measureSpec)9018 public static int getSize(int measureSpec) { 9019 return (measureSpec & ~MODE_MASK); 9020 } 9021 9022 /** 9023 * Returns a String representation of the specified measure 9024 * specification. 9025 * 9026 * @param measureSpec the measure specification to convert to a String 9027 * @return a String with the following format: "MeasureSpec: MODE SIZE" 9028 */ toString(int measureSpec)9029 public static String toString(int measureSpec) { 9030 int mode = getMode(measureSpec); 9031 int size = getSize(measureSpec); 9032 9033 StringBuilder sb = new StringBuilder("MeasureSpec: "); 9034 9035 if (mode == UNSPECIFIED) 9036 sb.append("UNSPECIFIED "); 9037 else if (mode == EXACTLY) 9038 sb.append("EXACTLY "); 9039 else if (mode == AT_MOST) 9040 sb.append("AT_MOST "); 9041 else 9042 sb.append(mode).append(" "); 9043 9044 sb.append(size); 9045 return sb.toString(); 9046 } 9047 } 9048 9049 class CheckForLongPress implements Runnable { 9050 9051 private int mOriginalWindowAttachCount; 9052 run()9053 public void run() { 9054 if (isPressed() && (mParent != null) 9055 && mOriginalWindowAttachCount == mWindowAttachCount) { 9056 if (performLongClick()) { 9057 mHasPerformedLongPress = true; 9058 } 9059 } 9060 } 9061 rememberWindowAttachCount()9062 public void rememberWindowAttachCount() { 9063 mOriginalWindowAttachCount = mWindowAttachCount; 9064 } 9065 } 9066 9067 private final class CheckForTap implements Runnable { run()9068 public void run() { 9069 mPrivateFlags &= ~PREPRESSED; 9070 mPrivateFlags |= PRESSED; 9071 refreshDrawableState(); 9072 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) { 9073 postCheckForLongClick(ViewConfiguration.getTapTimeout()); 9074 } 9075 } 9076 } 9077 9078 private final class PerformClick implements Runnable { run()9079 public void run() { 9080 performClick(); 9081 } 9082 } 9083 9084 /** 9085 * Interface definition for a callback to be invoked when a key event is 9086 * dispatched to this view. The callback will be invoked before the key 9087 * event is given to the view. 9088 */ 9089 public interface OnKeyListener { 9090 /** 9091 * Called when a key is dispatched to a view. This allows listeners to 9092 * get a chance to respond before the target view. 9093 * 9094 * @param v The view the key has been dispatched to. 9095 * @param keyCode The code for the physical key that was pressed 9096 * @param event The KeyEvent object containing full information about 9097 * the event. 9098 * @return True if the listener has consumed the event, false otherwise. 9099 */ onKey(View v, int keyCode, KeyEvent event)9100 boolean onKey(View v, int keyCode, KeyEvent event); 9101 } 9102 9103 /** 9104 * Interface definition for a callback to be invoked when a touch event is 9105 * dispatched to this view. The callback will be invoked before the touch 9106 * event is given to the view. 9107 */ 9108 public interface OnTouchListener { 9109 /** 9110 * Called when a touch event is dispatched to a view. This allows listeners to 9111 * get a chance to respond before the target view. 9112 * 9113 * @param v The view the touch event has been dispatched to. 9114 * @param event The MotionEvent object containing full information about 9115 * the event. 9116 * @return True if the listener has consumed the event, false otherwise. 9117 */ onTouch(View v, MotionEvent event)9118 boolean onTouch(View v, MotionEvent event); 9119 } 9120 9121 /** 9122 * Interface definition for a callback to be invoked when a view has been clicked and held. 9123 */ 9124 public interface OnLongClickListener { 9125 /** 9126 * Called when a view has been clicked and held. 9127 * 9128 * @param v The view that was clicked and held. 9129 * 9130 * @return true if the callback consumed the long click, false otherwise. 9131 */ onLongClick(View v)9132 boolean onLongClick(View v); 9133 } 9134 9135 /** 9136 * Interface definition for a callback to be invoked when the focus state of 9137 * a view changed. 9138 */ 9139 public interface OnFocusChangeListener { 9140 /** 9141 * Called when the focus state of a view has changed. 9142 * 9143 * @param v The view whose state has changed. 9144 * @param hasFocus The new focus state of v. 9145 */ onFocusChange(View v, boolean hasFocus)9146 void onFocusChange(View v, boolean hasFocus); 9147 } 9148 9149 /** 9150 * Interface definition for a callback to be invoked when a view is clicked. 9151 */ 9152 public interface OnClickListener { 9153 /** 9154 * Called when a view has been clicked. 9155 * 9156 * @param v The view that was clicked. 9157 */ onClick(View v)9158 void onClick(View v); 9159 } 9160 9161 /** 9162 * Interface definition for a callback to be invoked when the context menu 9163 * for this view is being built. 9164 */ 9165 public interface OnCreateContextMenuListener { 9166 /** 9167 * Called when the context menu for this view is being built. It is not 9168 * safe to hold onto the menu after this method returns. 9169 * 9170 * @param menu The context menu that is being built 9171 * @param v The view for which the context menu is being built 9172 * @param menuInfo Extra information about the item for which the 9173 * context menu should be shown. This information will vary 9174 * depending on the class of v. 9175 */ onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)9176 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 9177 } 9178 9179 private final class UnsetPressedState implements Runnable { run()9180 public void run() { 9181 setPressed(false); 9182 } 9183 } 9184 9185 /** 9186 * Base class for derived classes that want to save and restore their own 9187 * state in {@link android.view.View#onSaveInstanceState()}. 9188 */ 9189 public static class BaseSavedState extends AbsSavedState { 9190 /** 9191 * Constructor used when reading from a parcel. Reads the state of the superclass. 9192 * 9193 * @param source 9194 */ BaseSavedState(Parcel source)9195 public BaseSavedState(Parcel source) { 9196 super(source); 9197 } 9198 9199 /** 9200 * Constructor called by derived classes when creating their SavedState objects 9201 * 9202 * @param superState The state of the superclass of this view 9203 */ BaseSavedState(Parcelable superState)9204 public BaseSavedState(Parcelable superState) { 9205 super(superState); 9206 } 9207 9208 public static final Parcelable.Creator<BaseSavedState> CREATOR = 9209 new Parcelable.Creator<BaseSavedState>() { 9210 public BaseSavedState createFromParcel(Parcel in) { 9211 return new BaseSavedState(in); 9212 } 9213 9214 public BaseSavedState[] newArray(int size) { 9215 return new BaseSavedState[size]; 9216 } 9217 }; 9218 } 9219 9220 /** 9221 * A set of information given to a view when it is attached to its parent 9222 * window. 9223 */ 9224 static class AttachInfo { 9225 interface Callbacks { playSoundEffect(int effectId)9226 void playSoundEffect(int effectId); performHapticFeedback(int effectId, boolean always)9227 boolean performHapticFeedback(int effectId, boolean always); 9228 } 9229 9230 /** 9231 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 9232 * to a Handler. This class contains the target (View) to invalidate and 9233 * the coordinates of the dirty rectangle. 9234 * 9235 * For performance purposes, this class also implements a pool of up to 9236 * POOL_LIMIT objects that get reused. This reduces memory allocations 9237 * whenever possible. 9238 */ 9239 static class InvalidateInfo implements Poolable<InvalidateInfo> { 9240 private static final int POOL_LIMIT = 10; 9241 private static final Pool<InvalidateInfo> sPool = Pools.synchronizedPool( 9242 Pools.finitePool(new PoolableManager<InvalidateInfo>() { 9243 public InvalidateInfo newInstance() { 9244 return new InvalidateInfo(); 9245 } 9246 9247 public void onAcquired(InvalidateInfo element) { 9248 } 9249 9250 public void onReleased(InvalidateInfo element) { 9251 } 9252 }, POOL_LIMIT) 9253 ); 9254 9255 private InvalidateInfo mNext; 9256 9257 View target; 9258 9259 int left; 9260 int top; 9261 int right; 9262 int bottom; 9263 setNextPoolable(InvalidateInfo element)9264 public void setNextPoolable(InvalidateInfo element) { 9265 mNext = element; 9266 } 9267 getNextPoolable()9268 public InvalidateInfo getNextPoolable() { 9269 return mNext; 9270 } 9271 acquire()9272 static InvalidateInfo acquire() { 9273 return sPool.acquire(); 9274 } 9275 release()9276 void release() { 9277 sPool.release(this); 9278 } 9279 } 9280 9281 final IWindowSession mSession; 9282 9283 final IWindow mWindow; 9284 9285 final IBinder mWindowToken; 9286 9287 final Callbacks mRootCallbacks; 9288 9289 /** 9290 * The top view of the hierarchy. 9291 */ 9292 View mRootView; 9293 9294 IBinder mPanelParentWindowToken; 9295 Surface mSurface; 9296 9297 /** 9298 * Scale factor used by the compatibility mode 9299 */ 9300 float mApplicationScale; 9301 9302 /** 9303 * Indicates whether the application is in compatibility mode 9304 */ 9305 boolean mScalingRequired; 9306 9307 /** 9308 * Left position of this view's window 9309 */ 9310 int mWindowLeft; 9311 9312 /** 9313 * Top position of this view's window 9314 */ 9315 int mWindowTop; 9316 9317 /** 9318 * Indicates whether views need to use 32-bit drawing caches 9319 */ 9320 boolean mUse32BitDrawingCache; 9321 9322 /** 9323 * For windows that are full-screen but using insets to layout inside 9324 * of the screen decorations, these are the current insets for the 9325 * content of the window. 9326 */ 9327 final Rect mContentInsets = new Rect(); 9328 9329 /** 9330 * For windows that are full-screen but using insets to layout inside 9331 * of the screen decorations, these are the current insets for the 9332 * actual visible parts of the window. 9333 */ 9334 final Rect mVisibleInsets = new Rect(); 9335 9336 /** 9337 * The internal insets given by this window. This value is 9338 * supplied by the client (through 9339 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 9340 * be given to the window manager when changed to be used in laying 9341 * out windows behind it. 9342 */ 9343 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 9344 = new ViewTreeObserver.InternalInsetsInfo(); 9345 9346 /** 9347 * All views in the window's hierarchy that serve as scroll containers, 9348 * used to determine if the window can be resized or must be panned 9349 * to adjust for a soft input area. 9350 */ 9351 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 9352 9353 final KeyEvent.DispatcherState mKeyDispatchState 9354 = new KeyEvent.DispatcherState(); 9355 9356 /** 9357 * Indicates whether the view's window currently has the focus. 9358 */ 9359 boolean mHasWindowFocus; 9360 9361 /** 9362 * The current visibility of the window. 9363 */ 9364 int mWindowVisibility; 9365 9366 /** 9367 * Indicates the time at which drawing started to occur. 9368 */ 9369 long mDrawingTime; 9370 9371 /** 9372 * Indicates whether or not ignoring the DIRTY_MASK flags. 9373 */ 9374 boolean mIgnoreDirtyState; 9375 9376 /** 9377 * Indicates whether the view's window is currently in touch mode. 9378 */ 9379 boolean mInTouchMode; 9380 9381 /** 9382 * Indicates that ViewRoot should trigger a global layout change 9383 * the next time it performs a traversal 9384 */ 9385 boolean mRecomputeGlobalAttributes; 9386 9387 /** 9388 * Set during a traveral if any views want to keep the screen on. 9389 */ 9390 boolean mKeepScreenOn; 9391 9392 /** 9393 * Set if the visibility of any views has changed. 9394 */ 9395 boolean mViewVisibilityChanged; 9396 9397 /** 9398 * Set to true if a view has been scrolled. 9399 */ 9400 boolean mViewScrollChanged; 9401 9402 /** 9403 * Global to the view hierarchy used as a temporary for dealing with 9404 * x/y points in the transparent region computations. 9405 */ 9406 final int[] mTransparentLocation = new int[2]; 9407 9408 /** 9409 * Global to the view hierarchy used as a temporary for dealing with 9410 * x/y points in the ViewGroup.invalidateChild implementation. 9411 */ 9412 final int[] mInvalidateChildLocation = new int[2]; 9413 9414 /** 9415 * The view tree observer used to dispatch global events like 9416 * layout, pre-draw, touch mode change, etc. 9417 */ 9418 final ViewTreeObserver mTreeObserver = new ViewTreeObserver(); 9419 9420 /** 9421 * A Canvas used by the view hierarchy to perform bitmap caching. 9422 */ 9423 Canvas mCanvas; 9424 9425 /** 9426 * A Handler supplied by a view's {@link android.view.ViewRoot}. This 9427 * handler can be used to pump events in the UI events queue. 9428 */ 9429 final Handler mHandler; 9430 9431 /** 9432 * Identifier for messages requesting the view to be invalidated. 9433 * Such messages should be sent to {@link #mHandler}. 9434 */ 9435 static final int INVALIDATE_MSG = 0x1; 9436 9437 /** 9438 * Identifier for messages requesting the view to invalidate a region. 9439 * Such messages should be sent to {@link #mHandler}. 9440 */ 9441 static final int INVALIDATE_RECT_MSG = 0x2; 9442 9443 /** 9444 * Temporary for use in computing invalidate rectangles while 9445 * calling up the hierarchy. 9446 */ 9447 final Rect mTmpInvalRect = new Rect(); 9448 9449 /** 9450 * Temporary list for use in collecting focusable descendents of a view. 9451 */ 9452 final ArrayList<View> mFocusablesTempList = new ArrayList<View>(24); 9453 9454 /** 9455 * Creates a new set of attachment information with the specified 9456 * events handler and thread. 9457 * 9458 * @param handler the events handler the view must use 9459 */ AttachInfo(IWindowSession session, IWindow window, Handler handler, Callbacks effectPlayer)9460 AttachInfo(IWindowSession session, IWindow window, 9461 Handler handler, Callbacks effectPlayer) { 9462 mSession = session; 9463 mWindow = window; 9464 mWindowToken = window.asBinder(); 9465 mHandler = handler; 9466 mRootCallbacks = effectPlayer; 9467 } 9468 } 9469 9470 /** 9471 * <p>ScrollabilityCache holds various fields used by a View when scrolling 9472 * is supported. This avoids keeping too many unused fields in most 9473 * instances of View.</p> 9474 */ 9475 private static class ScrollabilityCache implements Runnable { 9476 9477 /** 9478 * Scrollbars are not visible 9479 */ 9480 public static final int OFF = 0; 9481 9482 /** 9483 * Scrollbars are visible 9484 */ 9485 public static final int ON = 1; 9486 9487 /** 9488 * Scrollbars are fading away 9489 */ 9490 public static final int FADING = 2; 9491 9492 public boolean fadeScrollBars; 9493 9494 public int fadingEdgeLength; 9495 public int scrollBarDefaultDelayBeforeFade; 9496 public int scrollBarFadeDuration; 9497 9498 public int scrollBarSize; 9499 public ScrollBarDrawable scrollBar; 9500 public float[] interpolatorValues; 9501 public View host; 9502 9503 public final Paint paint; 9504 public final Matrix matrix; 9505 public Shader shader; 9506 9507 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 9508 9509 private final float[] mOpaque = {255.0f}; 9510 private final float[] mTransparent = {0.0f}; 9511 9512 /** 9513 * When fading should start. This time moves into the future every time 9514 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 9515 */ 9516 public long fadeStartTime; 9517 9518 9519 /** 9520 * The current state of the scrollbars: ON, OFF, or FADING 9521 */ 9522 public int state = OFF; 9523 9524 private int mLastColor; 9525 ScrollabilityCache(ViewConfiguration configuration, View host)9526 public ScrollabilityCache(ViewConfiguration configuration, View host) { 9527 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 9528 scrollBarSize = configuration.getScaledScrollBarSize(); 9529 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 9530 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 9531 9532 paint = new Paint(); 9533 matrix = new Matrix(); 9534 // use use a height of 1, and then wack the matrix each time we 9535 // actually use it. 9536 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 9537 9538 paint.setShader(shader); 9539 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 9540 this.host = host; 9541 } 9542 setFadeColor(int color)9543 public void setFadeColor(int color) { 9544 if (color != 0 && color != mLastColor) { 9545 mLastColor = color; 9546 color |= 0xFF000000; 9547 9548 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 9549 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 9550 9551 paint.setShader(shader); 9552 // Restore the default transfer mode (src_over) 9553 paint.setXfermode(null); 9554 } 9555 } 9556 run()9557 public void run() { 9558 long now = AnimationUtils.currentAnimationTimeMillis(); 9559 if (now >= fadeStartTime) { 9560 9561 // the animation fades the scrollbars out by changing 9562 // the opacity (alpha) from fully opaque to fully 9563 // transparent 9564 int nextFrame = (int) now; 9565 int framesCount = 0; 9566 9567 Interpolator interpolator = scrollBarInterpolator; 9568 9569 // Start opaque 9570 interpolator.setKeyFrame(framesCount++, nextFrame, mOpaque); 9571 9572 // End transparent 9573 nextFrame += scrollBarFadeDuration; 9574 interpolator.setKeyFrame(framesCount, nextFrame, mTransparent); 9575 9576 state = FADING; 9577 9578 // Kick off the fade animation 9579 host.invalidate(); 9580 } 9581 } 9582 9583 } 9584 } 9585