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