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