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