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